最近项目需要使用华大HC32F460跑RT-thread操作系统,因为考虑只需用到芯片容量也不大,项目也不是很复杂,无需使用RT-Thread Master版本中完整的组件和软件包等功能,只需最基本的内核部分就可以,所以选择了RT-thread Nano版本,话不多说作为一款完全由国内团队开发维护的嵌入式实时操作系(RTOS)官网上有很多相关资料,[RT-Thread Nano版说明](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-nano/an0038-nano-introduction)我们直接进入HC32F460移植RTthread Nano。
Nano下载
可以直接去他们官网下载,[Nano下载链接](https://www.rt-thread.org/page/download.html)
解压后得到以上目录,简单做下说明。
bsp
示例代码,仅作参考。
components
nano版本只要是一些FINSH组件,移植基本无需改动,copy到我们工程下就行(后面可能会用到Finsh 控制台做一些调试打印)。
doc
该目录下主要一些官方相关文档说明。
include
相关头文件,需要加入到我们工程。
libcpu
cpu相关移植文件,我们移植主要需要关注的,下面会重点讲。
src
Nano 内核源码,基本无需改动,copy到我们工程下就行。
至此,RT-Thread Nano的准备工作已经完成,接下去我们开始移植到HC32F460开发板上去。
Nano移植
1.这次我们开发使用的编译环境是keil,我们直接新建一个新工程,选择我们对应的MCU型号。
这里如果提示我们没有对应型号我们可以直接支持包下载链接,解压后直接在你keil安装目录点击安装即可。
然后点击软件运行组件中我们勾选CORE,然后确定,我们这里使用keil自带组件。
2.为了方便管理我按如下进行分组(实际可按个人编程习惯和风格,作为公司内部尽量都保持一致)。
这里简单说明下(主要还是分层思想):
app:到时放我们的应用程序。
api:这里我们会放一些对应驱动的api层接口。
drv:我们的底层驱动。
lib:放我们的官方驱动库函数。
startup:我们mcu相关启动文件。startup_hc32f460.s等。
rtos/cpu:RT-thread CPU一致相关文件。
rtos/scr:RT-thread 内核源码。
rtos/finsh:RT-thread finsh组件。
doc:readme文档主要记录版本变更等信息,方便日后查看。
3.我们按照上面分组添加对应源文件。
lib中官方库函数可以直接华大官方库文件下载链接](https://www.hdsc.com.cn/Category83-1487)下载,我们选择版本为2.2.0。
startup中添加启动文件,其中startup_hc32f460.s可以在官方example例程中直接拷贝使用。
rtos/cpu添加RTTcpu相关文件,cpuport和context_rvds(我们使用keil),这里注意因为我们华大HC32F460用的是M4内核,所以我们拷贝时注意要在cortex-m4目录下面。
rtos/scr添加RTT内核源码文件。
rtos/finsh 添加finsh组件相关源文件。
至此,我们把HC32F460库函数和RTT内核相关函数都已经添加到我们工程中,我们还需要添加下对应头文件路径和相关宏。但是编译发现缺少ddl_config.h文件(对华大设备驱动库可进行选择配置),我们可以直接拷贝官方例程中的直接到我们工程目录下即可。
再编译发现RTT部分也会报错缺少rtconfig.h文件,其实和上面类似,我们可以直接拷贝RTT内核源码官方例子中文件到我们指定工程目录,这里我们顺便把board.c也一同拷贝到我们指定的工程目录下,到时我们rrt一些底层驱动会在这里实现,然后rtconfig.h中打开finsh组件,记得别忘了添加头文件。
最后,想让RTT在我们开发板上能跑起来我们还要做最后一步,就是对board.c进行修改主要是时钟配置和增加提供RTT时基的中断服务函数(一般我们使用systick,1ms周期中断)。
//void rt_os_tick_callback(void)
//{
// rt_interrupt_enter();
//
// rt_tick_increase();// rt_interrupt_leave();
//}
/*==================================================================
* Function :SysTick_Handler
* Description :SysTick中断
* Input Para :None
* Output Para :None
* Return Value :None
==================================================================*/
void SysTick_Handler(void)
{/* enter interrupt */rt_interrupt_enter();rt_tick_increase();/* leave interrupt */rt_interrupt_leave();
}
/*==================================================================
* Function : DrvHrcInit
* Description : 内部高速晶振初始化
* Input Para :
* Output Para :
* Return Value: 返回主频
==================================================================*/
uint32_t DrvHrcInit(void)
{en_clk_sys_source_t enSysClkSrc;stc_clk_sysclk_cfg_t stcSysClkCfg;stc_clk_xtal_cfg_t stcXtalCfg;stc_clk_mpll_cfg_t stcMpllCfg;MEM_ZERO_STRUCT(enSysClkSrc);MEM_ZERO_STRUCT(stcSysClkCfg);MEM_ZERO_STRUCT(stcXtalCfg);MEM_ZERO_STRUCT(stcMpllCfg);stcSysClkCfg.enHclkDiv = ClkSysclkDiv1; // Max 168MHzstcSysClkCfg.enExclkDiv = ClkSysclkDiv2; // Max 84MHzstcSysClkCfg.enPclk0Div = ClkSysclkDiv1; // Max 168MHzstcSysClkCfg.enPclk1Div = ClkSysclkDiv2; // Max 84MHzstcSysClkCfg.enPclk2Div = ClkSysclkDiv4; // Max 60MHzstcSysClkCfg.enPclk3Div = ClkSysclkDiv4; // Max 42MHzstcSysClkCfg.enPclk4Div = ClkSysclkDiv2; // Max 84MHzCLK_SysClkConfig(&stcSysClkCfg); ////16MHZstcMpllCfg.pllmDiv = 1; // 分频 1分频stcMpllCfg.plln = 21; // VCO 倍频系数 20~480stcMpllCfg.PllpDiv = 2; // MPLLP 系统主频为stcMpllCfg.PllqDiv = 2; // MPLLQstcMpllCfg.PllrDiv = 7; // MPLLR 用于USB时钟48MHZCLK_SetPllSource(ClkPllSrcHRC); //CLK_MpllConfig(&stcMpllCfg);EFM_Unlock(); /* flash read wait cycle setting */EFM_SetLatency(EFM_LATENCY_5);EFM_Lock();CLK_MpllCmd(Enable); /* Enable MPLL. */while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy)); /* Wait MPLL ready. */CLK_SetSysClkSource(CLKSysSrcMPLL); /* Switch system clock source to MPLL. */stc_sram_config_t stcSramCfg;MEM_ZERO_STRUCT(stcSramCfg);stcSramCfg.u8SramIdx = Sram12Idx | Sram3Idx | SramRetIdx;stcSramCfg.enSramRC = SramCycle2;stcSramCfg.enSramWC = SramCycle2;SRAM_Init(&stcSramCfg);// ReadResetCause();stc_clk_freq_t stcClkFreq; /* Check source and frequence. */CLK_GetClockFreq(&stcClkFreq);return stcClkFreq.sysclkFreq;
}
按上图修改时钟配置后编译,报错如下图,因为我们使用RTthread时,系统调度会用到这三个中断服务程序接口,RTT已经帮我们实现,我们需要把华大库自带的屏蔽掉就行。
重新编译,RTT基于HC32F460完成移植。