国产MCU移植HC32F460基于Keil MDK 移植 RT-Thread Nano
Posted RT-Thread物联网操作系统
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了国产MCU移植HC32F460基于Keil MDK 移植 RT-Thread Nano相关的知识,希望对你有一定的参考价值。
本文由RT-Thread论坛用户@想当诸侯的小蚂蚁原创发布:https://club.rt-thread.org/ask/article/2966.html
软件
根据厂家demo重新新建工程,工程中包含了gpio、usart。
硬件:
gpio
/* GREEN_LED Port/Pin definition */
#define GREEN_LED_PORT (PortE)
#define GREEN_LED_PIN (Pin00)
/* RED_LED Port/Pin definition */
#define RED_LED_PORT (PortE)
#define RED_LED_PIN (Pin01)
usart4
/* USART RX Port/Pin definition */
#define USART_RX_PORT (PortC)
#define USART_RX_PIN (Pin07)
#define USART_RX_FUNC (Func_Usart4_Rx)
/* USART TX Port/Pin definition */
#define USART_TX_PORT (PortC)
#define USART_TX_PIN (Pin06)
#define USART_TX_FUNC (Func_Usart4_Tx)
添加 RT-Thread Nano 到工程
在 Manage Rum-Time Environment 内打开 RTOS 栏,勾选 kernal,点击 OK 后就将 RT-Thread 内核加入到工程中了。
适配 RT-Thread Nano
中断与异常处理
需要删除工程里中断服务例程文件 hc32f460_interrupts.c中异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,避免在编译时产生重复定义。
系统时钟配置
需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 os tick 的配置 (为操作系统提供心跳 / 节拍)。
void SysTick_Handler(void)
{
rt_os_tick_callback();
}
void rt_hw_board_init(void)
函数中调用系统时钟
SysClkConfig(); //系统时钟初始化
SysTick_Init(RT_TICK_PER_SECOND); //OS Tick 频率配置
void SysClkConfig(void)
所在文件system_hc32f460.c
void SysClkConfig(void)
{
stc_clk_sysclk_cfg_t stcSysClkCfg; //系统时钟
stc_clk_xtal_cfg_t stcXtalCfg; //晶振配置
stc_clk_mpll_cfg_t stcMpllCfg; //PLL
stc_sram_config_t stcSramConfig;
MEM_ZERO_STRUCT(stcSysClkCfg);
MEM_ZERO_STRUCT(stcXtalCfg);
MEM_ZERO_STRUCT(stcMpllCfg);
/* Set bus clk div. 分频 */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv1; // 100MHz
stcSysClkCfg.enExclkDiv = ClkSysclkDiv2; // 50MHz
stcSysClkCfg.enPclk0Div = ClkSysclkDiv1; // 100MHz
stcSysClkCfg.enPclk1Div = ClkSysclkDiv2; // 50MHz
stcSysClkCfg.enPclk2Div = ClkSysclkDiv4; // 25MHz
stcSysClkCfg.enPclk3Div = ClkSysclkDiv4; // 25MHz
stcSysClkCfg.enPclk4Div = ClkSysclkDiv2; // 50MHz
CLK_SysClkConfig(&stcSysClkCfg);//时钟分频
/* Switch system clock source to MPLL. */
/* Use Xtal as MPLL source. */
stcXtalCfg.enMode = ClkXtalModeOsc;//XTAL模式选择位
stcXtalCfg.enDrv = ClkXtalLowDrv;/*XTAL驱动能力选择
stcXtalCfg.enFastStartup = Enable;/*XTAL超高速驱动允许
CLK_XtalConfig(&stcXtalCfg);//CMU XTAL 配置寄存器
CLK_XtalCmd(Enable);//开启CMU XTAL
while(Set != CLK_GetFlagStatus(ClkFlagXTALRdy))
{
;
}
/* MPLL config. */
stcMpllCfg.pllmDiv = 1ul;//MPLL输入时钟分频系数
stcMpllCfg.plln =50ul;//MPLL倍频系数
stcMpllCfg.PllpDiv = 4ul;
stcMpllCfg.PllqDiv = 4ul;
stcMpllCfg.PllrDiv = 4ul;
CLK_SetPllSource(ClkPllSrcXTAL);//时钟源选择 XTAL
CLK_MpllConfig(&stcMpllCfg);//CMU MPLL 时钟分频配置
/* flash read wait cycle setting */
EFM_Unlock();
EFM_SetLatency(5ul);
EFM_Lock();
/* sram init include read/write wait cycle setting */
stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
stcSramConfig.enSramRC = SramCycle2;
stcSramConfig.enSramWC = SramCycle2;
stcSramConfig.enSramEccMode = EccMode3;
stcSramConfig.enSramEccOp = SramNmi;
stcSramConfig.enSramPyOp = SramNmi;
SRAM_Init(&stcSramConfig);
/* Enable MPLL. */
CLK_MpllCmd(Enable);//用于开始停止MPLL。0:MPLL动作开始 1:MPLL停止
/* Wait MPLL ready. */
while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
{
;
}
/* Switch system clock source to MPLL. */
CLK_SetSysClkSource(CLKSysSrcMPLL);//CMU 系统时钟源切换寄存器
}
en_result_t SysTick_Init(uint32_t u32Freq)
所在文件hc32f460_utility.c
__WEAKDEF en_result_t SysTick_Init(uint32_t u32Freq)
{
en_result_t enRet = Error;
if ((0UL != u32Freq) && (u32Freq <= 1000UL))
{
m_u32TickStep = 1000UL / u32Freq;
/* Configure the SysTick interrupt */
if (0UL == SysTick_Config(SystemCoreClock / u32Freq))
{
enRet = Ok;
}
}
return enRet;
}
内存堆初始化
系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认不开启内存堆功能,这样可以保持一个较小的体积,不用为内存堆开辟空间。
开启系统 heap 将可以使用动态内存功能,如使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。若需要使用系统内存堆功能,则打开 RT_USING_HEAP 宏定义即可,此时内存堆初始化函数 rt_system_heap_init() 将被调用,如下所示:
编写第一个应用
1.使用rt_thread_mdelay()函数
移植RT-Thread Nano之前跑马灯使用厂家库函数
移植RT-Thread Nano之后跑马灯使用
2.建立线程
在 Nano 上添加 UART 控制台
在 RT-Thread Nano 上添加 UART 控制台打印功能后,就可以在代码中使用 RT-Thread 提供的打印函数 rt_kprintf() 进行信息打印,从而获取自定义的打印信息,方便定位代码 bug 或者获取系统当前运行状态等。实现控制台打印(需要确认 rtconfig.h 中已使能 RT_USING_CONSOLE 宏定义),需要完成基本的硬件初始化,以及对接一个系统输出字符的函数。
实现串口初始化
rtconfig.h中 Configuration Wizard->Console Configuration开启RT_USING_CONSOLE
usart.c
int rt_Usart_Init(void)
{
uint32_t u32Fcg1Periph = PWC_FCG1_PERIPH_USART1 | PWC_FCG1_PERIPH_USART2 | \\
PWC_FCG1_PERIPH_USART3 | PWC_FCG1_PERIPH_USART4;
const stc_usart_uart_init_t stcInitCfg = {
UsartIntClkCkOutput,
UsartClkDiv_1,
UsartDataBits8,
UsartDataLsbFirst,
UsartOneStopBit,
UsartParityNone,
UsartSampleBit8,
UsartStartBitFallEdge,
UsartRtsEnable,
};
/* Enable peripheral clock */
PWC_Fcg1PeriphClockCmd(u32Fcg1Periph, Enable);
/* Initialize USART IO */
PORT_SetFunc(USART_RX_PORT, USART_RX_PIN, USART_RX_FUNC, Disable);
PORT_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_FUNC, Disable);
/* Initialize UART */
while(Ok != USART_UART_Init(USART_CH, &stcInitCfg));
/* Set baudrate */
while(Ok != USART_SetBaudrate(USART_CH, USART_BAUDRATE));
/*Enable RX && RX function*/
USART_FuncCmd(USART_CH, UsartRx, Enable);
USART_FuncCmd(USART_CH, UsartTx, Enable);
return 0;
}
INIT_BOARD_EXPORT(rt_Usart_Init);
实现 rt_hw_console_output
usart.c
void rt_hw_console_output(const char *str)
{
rt_size_t i = 0, size = 0;
char a = '\\r';
size = rt_strlen(str);
for (i = 0; i < size; i++)
{
if (*(str + i) == '\\n')
{
while (Reset == USART_GetStatus(USART_CH, UsartTxEmpty)) {}; /* Warit Tx data register empty */
USART_SendData(USART_CH,(uint16_t)a);
}
while (Reset == USART_GetStatus(USART_CH, UsartTxEmpty)){}; /* Warit Tx data register empty */
USART_SendData(USART_CH,(*(str + i)));
}
}
RT_WEAK修饰函数 board.c中rt_hw_console_output(const char *str)
,不然会报重定义。
RT_WEAK void rt_hw_console_output(const char *str)
{
//#error "TODO 3: Output the string 'str' through the uart."
}
验证结果
##在 Nano 上添加 FinSH 组件(实现命令输入)
####添加FinSH组件
点击 Manage Run-Environment,勾选 shell,这将自动把 FinSH 组件的源码到工程
rtconfig.h中 Configuration Wizard->Console Configuration开启RT_USING_CONSOLE
实现rt_hw_console_getchar(void)
函数
usart.c
char rt_hw_console_getchar(void)
{
int ch = -1;
if (Set == USART_GetStatus(USART_CH, UsartRxNoEmpty))
{
ch = USART_RecData(USART_CH);
}
return ch;
}
验证结果
HC32F460移植RT-Thread Nano结束
近来芯片缺货大幕拉开,掀起新一轮国产替代浪潮。RT-Thread发起一场国产MCU移植贡献活动,邀请开发者们参加!
活动详情:国潮崛起!RT-Thread国产MCU移植贡献活动开启!
以上是关于国产MCU移植HC32F460基于Keil MDK 移植 RT-Thread Nano的主要内容,如果未能解决你的问题,请参考以下文章
国产MCU移植手把手教你制作国产MCU的BSP-基于TAE32F5300
国产MCU系列在 HK32F030 上移植 RT-Thread Nano