HC32F460基于Keil MDK 移植 RT-Thread Nano

由于大环境影响目前正在更换使用HC32F460 ,HC32F460各个模块也在根据厂家demo摸索移植中,rtos也准备替换为更给力的rtthead。记录一下自己学习移植rtt过程。

软件:根据厂家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结束

HC32F460基于Keil MDK 移植 RT-Thread Nano

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值