1. K10 BSP包的创建
在基于MQX4.0对Kinetis系列MCU进行开发时,通常需要相应MCU的BSP的支持。但是在MQX4.0中,并没有针对K10的现成的BSP包,所以需要由用户进行创建。比较简便的创建方法是从现有的Kinetis BSP包中选择一个型号最接近的MCU的BSP作为模板,然后在其基础上进行修改和移植。本文介绍了对BSP进行修改和移植的具体步骤和方法。
目前已有的典型的BSP包包括:
• 支持Kinetis 50MHz 的器件的BSP包为twrk20d50m
• 支持Kinetis 72MHz 的器件的BSP包为twrk20d72m
• 支持Kinetis 100MHz的器件,针对版本1.x的BSP有3个,分别是twrk40x256,twrk53n512和twrk60n512
• 支持Kinetis 100MHz的器件,针对版本2.x可选择的BSP有2个,分别是twrk40d100m和twrk60d100m
• 支持Kinetis 120MHz的器件的BSP包有2个,分别是twrk60f120m和twrk70f120m
例如对于K10DN512ZVLQ10,其掩膜号为 4N30D,对应版本是1.x,而且其主频是100MHz,所以可使用twrk60n512的BSP为模板,在此基础上进行修改和移植。
2. BSP包代码的生成
首先从Freescale官网 https://www.freescale.com/mqx下载并安装MQX4.0。在这里也可以找到其他的早期版本,如MQX3.8、 MQX3.7等,其中都带有MQX BSP Cloning Wizard工具。可以使用此工具,参照如下步骤进行BSP的创建和移植。
2.1新建BSP
在File菜单中选择NEW MQX BSP Clone后,出现如下图1所示的界面,在Name中输入取名为K10DN512,然后选择twrk60n512作为其Board Base,最后点击Finish完成。
图1. 新建一个BSP
紧接着会出现如图2所示的窗口,可以在该界面下选择CW10.x或者IAR或者KEIL作为开发平台,以及是否需要生成BSP,PSP,MFS,RTCS,USB等库和例程的选择项。需要注意的是,由于K10本身不包括USB和以太网模块,所以不要选择相应的选项。
图2. 选择开发平台和相关的软件库
2.2 生成BSP包
为了简化操作,这里只选择IAR的开发环境,而且只选择生成BSP,PSP以及MQX例程,然后点击Generate MQX Projects,开始创建新的BSP代码,如图 3所示。
图3 点击生成BSP包的工程
接着在C:FreescaleFreescale_MQX_4_0configK10DN512目录中,找到刚才生成的针对IAR的BSP代码,使用IAR开发环境选择File-》Open-》Workspace,打开build_libs.eww工程。如图4所示。
图4 打开IAR BSP工程
注意: 在 打开此工程时会提示RTCS、 MFS、 USB等库是否要加载。由于本文档只针对基本的BSP、PSP包进行移植,而且在图2中只勾选了这两项,所以这里可以忽略除BSP、 PSP以外的 MFS、 RTCS、USB等包的加载,直接点击确认完成就可以了。如果在实际应用中需要使用其他的包,需要将图2中相应的Libraries库和参考代码的选项勾选上,然后再进行代码生成即可。
3. BSP包代码的修改
在C:FreescaleFreescale_MQX_4_0mqxsourcepspcortex_m文件夹里的psp_cpudef.h文件中可以找到支持Kinetis K10/K20/K30/K40/K50/K60/K70等相关芯片的PSP宏定义,例如支持K10DN512的宏定义为:
#define PSP_CPU_MK10DN512Z (PSP_CPU_NUM(PSP_CPU_ARCH_ARM_CORTEX_M4, PSP_CPU_GROUP_KINETIS_K1X, 2))
同时在该文件中还可以找到所有Freescale指定PSP处理器支持包所支持内核的宏定义,如ColdFire,PPC,Cortex-A5,Cortex-A8等。
在本文中,我们创建的是针对K10DN512的BSP开发包,所以需要用上述的宏定义,将user_config.h文件中的MQX_CPU定义
#define MQX_CPU PSP_CPU_MK60DN512Z
修改为:
#define MQX_CPU PSP_CPU_MK10DN512Z
此时点击编译按钮会出现错误提示,如下图5所示。
图5. 头文件错误
出现这个错误是由于在C:FreescaleFreescale_MQX_4_0mqxsourcepspcortex_mkinetis.h中找不到头文件MK10DZ10.h,需要从以下的IAR安装目录中寻找:
C:Program FilesIAR SystemsEmbedded Workbench 6.5armincFreescale
然后将该文件拷贝到C:FreescaleFreescale_MQX_4_0mqxsourcepspcortex_mcpu中进行编译。
编译仍有错误出现,如下图6所示。
这个错误主要是由于移植使用的是K60的BSP包,因此里面含有以太网ENET部分和USB部分的代码,而在K10芯片中是没有这些功能模块的,在IAR IDE Workspace工作台环境下,需要将外围I/O驱动(Peripheral IO Drivers)中的ENET和USB等文件夹删除,同时将K10DN512 BSP Files文件夹中的 init_usb.c和init_enet.c文件删除。另外在K10DN512 BSP Files中,由于在MQX安装目录C:FreescaleFreescale_MQX_4_0mqxsourcespK10DN512 文件下的init_gpio.c和bsp.h中初始化了ent和usb部分的,需要打开这两个文件,找到_bsp_ent_io_init和bsp_usb_io_init的代码部分,然后直接进行删除。此时再进行编译,则应该没有错误出现了。
图6以太网及USB相关的文件编译错误
下一步需要修改的,是系统的时钟设置。针对K60DN512, MQX默认的外部时钟是50MHz。 对于K20系列MQX默认的外部时钟是8MHz,如果目标板的时钟和默认的外部时钟不一样,则需要重新配置。例如,如果这里选择25MHz的无源晶体作为外接时钟,那么就需要修改bsp_cm.h中的时钟设置,将CPU_XTAL_CLK_HZ的时钟修改为25MHz。当然根据实际项目设计有时也需要配置不同的总线时钟频率,内核时钟频率等,可以参照如下的代码对bsp_cm.h中的宏定义进行相应的修改:
#define CPU_BUS_CLK_HZ 48000000U /*初始化总线时钟频率为48MHz*/
修改为
#define CPU_BUS_CLK_HZ 50000000U /*初始化总线时钟频率为50MHz*/
#define CPU_CORE_CLK_HZ 96000000U /* 初始化内核、系统时钟频率为96MHz */
修改为
#define CPU_CORE_CLK_HZ 100000000U /* 初始化内核、系统时钟频率为100MHz */
#define CPU_CLOCK_CONFIG_NUMBER 0x03U /* 定义时钟配置的个数,时钟配置有0,1和2,共3种可以选择*/
#define CPU_BUS_CLK_HZ_CLOCK_CONFIG0 48000000U /*在时钟配置0中的总线时钟频率为48MHz */
修改为
#define CPU_BUS_CLK_HZ_CLOCK_CONFIG0 50000000U /*在时钟配置0中的总线时钟频率为50MHz */
#define CPU_CORE_CLK_HZ_CLOCK_CONFIG0 96000000U /* 在时钟配置0中的内核、系统时钟频率为96MHz*/
修改为
#define CPU_CORE_CLK_HZ_CLOCK_CONFIG0 100000000U /* 在时钟配置0中的内核、系统时钟频率为100MHz*/
#define CPU_XTAL_CLK_HZ 50000000U /* 外部晶体或者振荡器的时钟频率为50MHz*/
修改为
#define CPU_XTAL_CLK_HZ 25000000U /* 外部晶体或者振荡器的时钟频率为25MHz*/
相应的,对于使用的时钟配置0或者1或者2也需要修改,如果目标配置使用的是时钟配置0,可以参照如下代码修改。如果不使用时钟配置1或者2,则不需要做修改。
/* 在时钟配置0中的CPU时钟频率 */
#define CPU_CLOCK_CONFIG_0 0x00U /* 时钟配置0的定义 */
修改内核时钟频率,默认的是96MHz,改为100MHz。
#define CPU_CORE_CLK_HZ_CONFIG_0 100000000UL /* 内核时钟频率为100MHz*/
修改总线时钟频率,默认是48MHz,修改为50MHz。
#define CPU_BUS_CLK_HZ_CONFIG_0 50000000UL /* 总线时钟频率为50MHz*/
修改Flash时钟频率,默认是24MHz,修改为25MHz。
#define CPU_FLASH_CLK_HZ_CONFIG_0 25000000UL /* FLASH时钟频率为25MHz*/
#define CPU_PLL_FLL_CLK_HZ_CONFIG_0 100000000UL /* PLL/FLL时钟频率为100MHz*/
#define CPU_OSCER_CLK_HZ_CONFIG_0 50000000UL
/*在时钟配置0中的系统OSC 外部参考时钟 */
手工书写代码相对繁琐,更方便的方法是使用Freescale的Processor Expert 工具,根据硬件的需要来设置时钟,生成的如下的代码。通过PE工具来对CPU和各种外设进行设置,只需了解它的原理和用法,而不用把精力花在了解寄存器的具体细节上。打开PE后,参照图7的配置进行设置,点击Project-》Generator Processor Expert Code即可生成代码。记住重新修改配置后需要点击Project-》Clean,清掉上次生成的代码,然后再执行生成代码的操作。
void __pe_initialize_hardware(void)
{
_bsp_watchdog_disable();
/* 关闭 WDOG 模块 */
WDOG_UNLOCK = WDOG_UNLOCK_WDOGUNLOCK(0xC520);
WDOG_UNLOCK = WDOG_UNLOCK_WDOGUNLOCK(0xD928);
WDOG_STCTRLH = WDOG_STCTRLH_STNDBYEN_MASK | WDOG_STCTRLH_WAITEN_MASK | WDOG_STCTRLH_STOPEN_MASK | WDOG_STCTRLH_ALLOWUPDATE_MASK | WDOG_STCTRLH_CLKSRC_MASK;
/* 系统时钟初始化 */
/* SIM_SCGC5: PORTA=1 */
SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV2(0x01) | SIM_CLKDIV1_OUTDIV3(0x03) |
SIM_CLKDIV1_OUTDIV4(0x03); /* 更新系统预分频器 */
SIM_SOPT1 &= (uint32_t)~(uint32_t)(SIM_SOPT1_OSC32KSEL_MASK);
PORTA_PCR18 &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
PORTA_PCR19 &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
/*切换到FBE 模式*/
OSC_CR = OSC_CR_ERCLKEN_MASK;
SIM_SOPT2 &= (uint32_t)~(uint32_t)(SIM_SOPT2_MCGCLKSEL_MASK);
MCG_C2 = (MCG_C2_RANGE(0x02) | MCG_C2_EREFS_MASK);
MCG_C1 = (MCG_C1_CLKS(0x02) | MCG_C1_FRDIV(0x05) | MCG_C1_IRCLKEN_MASK);
MCG_C4 &= (uint8_t)~(uint8_t)((MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0x03)));
MCG_C5 = MCG_C5_PRDIV(0x07);
MCG_C6 = MCG_C6_VDIV(0x08);
while((MCG_S & MCG_S_OSCINIT_MASK) == 0x00U) { /*判断晶振是否运行?*/
}
while((MCG_S & MCG_S_IREFST_MASK) != 0x00U) {
/* 判断FLL参考源是否为外部参考时钟 */
}
while((MCG_S & 0x0CU) != 0x08U) { //等待,直到外部参考时钟作为MCG的输出
}
/* 切换到 PBE 模式*/
OSC_CR = OSC_CR_ERCLKEN_MASK;
SIM_SOPT2 &= (uint32_t)~(uint32_t)(SIM_SOPT2_MCGCLKSEL_MASK);
MCG_C1 = (MCG_C1_CLKS(0x02) | MCG_C1_FRDIV(0x05) | MCG_C1_IRCLKEN_MASK);
MCG_C2 = (MCG_C2_RANGE(0x02) | MCG_C2_EREFS_MASK);
MCG_C5 = MCG_C5_PRDIV(0x07);
MCG_C6 = (MCG_C6_PLLS_MASK | MCG_C6_VDIV(0x08));
while((MCG_S & 0x0CU) != 0x08U) { /*等待,直到外部参考时钟作为MCG输出*/
}
while((MCG_S & MCG_S_LOCK_MASK) == 0x00U) { /* 等待直到锁住*/
}
/* 切换到 PEE模式 */
OSC_CR = OSC_CR_ERCLKEN_MASK;
SIM_SOPT2 &= (uint32_t)~(uint32_t)(SIM_SOPT2_MCGCLKSEL_MASK);
MCG_C1 = (MCG_C1_FRDIV(0x05) | MCG_C1_IRCLKEN_MASK);
MCG_C2 = (MCG_C2_RANGE(0x02) | MCG_C2_EREFS_MASK);
MCG_C5 = MCG_C5_PRDIV(0x07);
MCG_C6 = (MCG_C6_PLLS_MASK | MCG_C6_VDIV(0x08));
while((MCG_S & 0x0CU) != 0x0CU) { /* 等待,直到PLL输出*/
}
}
图7. PE设置
MQX4.0中PE的时钟初始化代码在bsp_cm.c文件的void __pe_initialize_hardware(void)函数中。可以将上述PE生成的代码直接粘贴在该文件中。调试可能会出现系统时钟配置错误。当出现此类错误时,程序可能会停在图8所示的dispatch.s文件中的等待中断的语句cpsid.n i处。这种错误往往是由于只修改了部分的时钟寄存器设置或者是直接使用其他系列的Kinetis的BSP包中的时钟配置,而没有做相应的修改所造成的。例如,直接使用K60 BSP包的默认时钟部分代码,在K10的25Mhz外部时钟环境中进行调试就会出现上述错误。这里不建议手工书写代码或者直接拷贝其他Kinetis系列的不同时钟配置的代码,建议使用PE来配置生成时钟代码,对于有错误的部分PE中会有相关的红色提示符标示出来,因此不用担心那些时钟寄存器配置错误或被遗漏了。
图8. dispatch.s代码
一般地,在user_config.h配置中,RTC是默认使能的,也就是外部的32.768Khz晶振是需要外接的,如果不外接,可以将配置文件user_config.h中的宏定义语句:
#define BSPCFG_ENABLE_RTCDEV 1 修改为
#define BSPCFG_ENABLE_RTCDEV 0
另外由于K10中不包含USB和以太网的代码,所以需要将相关的USB,Ethernet的文件删除,并将user_config.h头文件中的宏定义修改为:
#define RTCSCFG_ENABLE_ICMP 0
#define RTCSCFG_ENABLE_UDP 0
#define RTCSCFG_ENABLE_TCP 0
#define RTCSCFG_ENABLE_STATS 0
#define RTCSCFG_ENABLE_GATEWAYS 0
#define FTPDCFG_USES_MFS 0
#define RTCSCFG_ENABLE_SNMP 0
#define TELNETDCFG_NOWAIT FALSE
#define HTTPDCFG_POLL_MODE 0
#define HTTPDCFG_STATIC_TASKS 0
#define HTTPDCFG_DYNAMIC_TASKS 0
4. BSP包代码的调试
4.1. 创建一个 简单任务并运行
为了证明所创建的BSP是可以正常工作的,这里建一个最简单的IAR的工程,如图9所示,它包含了我们所创建的基于MQX 4.0的 K10DN512 的BSP库。
图9 建立一个IAR工程
选择保存工程的文件目录位置如下:C:FreescaleFreescale_MQX_4_0demoK10DN512 Demo。在main.c中添加如下的代码:
#include
#include
#define MAIN_TASK 15
#define STACK_SIZE 1024
#define MAIN_STACK STACK_SIZE
extern void main_task(uint_32);
extern “C” const TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
// Task Index, Function, Stack, Priority, Name, Attributes, Param, Time Slice */
{ MAIN_TASK, main_task, MAIN_STACK, 11, “main_task”, MQX_AUTO_START_TASK, 0, 0 },
{ 0 }
};
void main_task(uint_32 parameter)
{
while(1)
{
puts(“A”);
}
}
需要将C:FreescaleFreescale_MQX_4_0libK10DN512.iardebugsp中的bsp.a库文件,以及C:FreescaleFreescale_MQX_4_0libK10DN512.iardebugpsp中的psp.a库文件添加到工程中去。如下图10所示,点击main选择右键option for node “main”,并在C/C++ Compiler的预处理器preprocessor和Assembler中设置文件的路径如下。
C:FreescaleFreescale_MQX_4_0libK10DN512.iardebugsp
C:FreescaleFreescale_MQX_4_0libK10DN512.iardebugpsp
C:FreescaleFreescale_MQX_4_0libK10DN512.iardebugspGenerated_Code
C:FreescaleFreescale_MQX_4_0libK10DN512.iardebug
图10. 在Option选项中设置
注意需要将 文件拷贝到C:FreescaleFreescale_MQX_4_0libK10DN512.iardebugpsp文件夹中。
编译完成后,通过JLINK等烧写工具将软件下载到目标板后开始运行,系统运行的界面如图11所示。如果系统进不了main函数,说明MQX bsp系统移植还有问题,需要按照前面介绍的步骤进行仔细的检查。
图11 复位后运行进入main函数
系统进入main函数,在mqx函数处设置断点,点击图标go运行,程序进入mqx初始化部分,如图12所示。
图12 mqx初始化
在main_task中设置断点,再次运行,如图13所示,在IAR 的JLINK任务栏中可以找到TASK LIST列表。这里需要注意的是,需要在IAR的环境下,将option下debug插件的MQX勾选,如图14所示,勾选后才可以看到MQX的TASK等任务信息。
图13 主任务运行
图14 选取MQX
4.2 GPIO配置与任务调试
在MQX4.0安装目录C:FreescaleFreescale_MQX_4_0mqxexamples下可以找到很多参考例程,包括ADC、 Hello、 I2C、 Lowpower、 Timer等。这里采用使用的最多的GPIO例程来验证BSP是否能正常工作。
由于在默认的bsp包中user_config.h中没有配置使能BSPCFG_ENABLE_GPIODEV外设,需要在该文件中加入语句#define BSPCFG_ENABLE_GPIODEV 1,如下图15所示。
图15 使能GPIO任务配置
在这里,为了验证MQX4.0版本操作系统对于MQX3.8等早期版本软件代码的兼容性,本例使用的源程序 代码,可以在MQX3.8版本的安装目录中C:FreescaleFreescale MQX 3.8mqxexamplesgpio找到。直接将该文件添加到工程中,如图16所示,在IAR的主程序中,在读IO状态处设置断点,系统执行到此断点处,如果开启IAR任务栏的TASK List, 在Stack Uage Summary窗口可以看到任务和栈的运行情况。
图16 GPIO任务 运行
这里需要注意的是,代码中用到了一些BSP_BUTTON1,BSP_LED1等宏定义,这些宏定义在MQX4.0的安装目录C:FreescaleFreescale_MQX_4_0mqxsourcespK10DN512的K10DN512.H文件中可以找到,例如BSP_LED1中的宏定义如下:
#define BSP_LED1 (GPIO_PORT_A | GPIO_PIN11)
如果目标板中的LED引脚和默认的设置不一样,需要对其进行修改,然后重新编译。
另外在通过下载工具调试代码的时候,需要指定icf配置文件,如图17所示。这里K10DN512和K60DN512的Flash大小一样,不需要做修改。如果使用其他不同配置的芯片则需要对Memory Region进行调整。
图17 ICF文件的位置指定
5. 总结
本文介绍了如何基于飞思卡尔的MQX操作系统,创建并移植目标MCU的 BSP包,并可以针对不同的开发平台(CW, KEIL, IAR)定制适合目标芯片的BSP。
评论
查看更多