打印
[方案相关]

【华大测评】 HC32F460移植RT-Thread Nano

[复制链接]
4442|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Liyj336|  楼主 | 2020-9-20 17:58 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Liyj336 于 2020-11-28 09:28 编辑

这一次测评我将一步步分享RT-Thread Nano移植到HC32F460的过程。主要分三步讲解工程建立、RT-Thread移植、添加UART控制台和Finsh。
一、工程建立

1、首先我们需要建立程序工程文件,下面的工程我是在HC32F460官方例程基础上建立的。在一个总的工程文件夹下面,建立以下工程文件夹。红色划线部分文件夹可以先忽略。(可以按照自己习惯建立工程)


BSP:打算存放MCU外部外设部分程序。
documents:从官方例程中复制过来,存放HC32F460官方库使用说明。
driver:从官方例程复制过来,存放HC32F460的驱动库。
mcu:从官方例程复制过来,MDK工程需要里面的文件。保留下面两个文件夹就行

MDK:存放MDK工程文件。我从例程icg_hrc_osc_hw_startup复制过来的,该例程跟Systick有关。

source:从官方移植过来的,存放main.c和其他一些程序文件。

2、打开MDK目录下的icg_hrc_osc_hw_startup工程。从新加入project下的文件。忽略打叉或者划线的文件,从刚建立的工程中加入以下文件。


3、新建led.c和led.h文件放入到BSP下的src和inc文件夹内,并把led.c文件加入到MDK工程中。
led.c代码如下,只是一个简单的点灯代码,用来验证程序。

#include <led.h>

void LED_Init(void)
{
    /**************************************************************************/
   
    stc_port_init_t stcPortInit;

    /* configure structure initialization */
    MEM_ZERO_STRUCT(stcPortInit);

    /* LED0 Port/Pin initialization */
    LED0_OFF();
    stcPortInit.enPinMode = Pin_Mode_Out;
    PORT_Init(LED0_PORT, LED0_PIN, &stcPortInit);
}
led.h
#ifndef        __LED_H
#define        __LED_H

#include "hc32_ddl.h"

/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/

/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/* LED0 Port/Pin definition */
#define LED0_PORT                       (PortE)
#define LED0_PIN                        (Pin06)

#define LED0_ON()                       (PORT_SetBits(LED0_PORT, LED0_PIN))
#define LED0_OFF()                      (PORT_ResetBits(LED0_PORT, LED0_PIN))
#define LED0_TOGGLE()                   (PORT_Toggle(LED0_PORT, LED0_PIN))


void LED_Init(void);

#endif        /*__LED_H*/

4、接下来修改HDSC_HC32F46x.SFR文件路径,如下图红框内,其实我也不知道这个文件有什么作用。

然后从新加入头文件路径。


二、RT-Thread Nano移植

1、首先需要获取RT-Thread Nano源码,RT-Thread Nano是一个精简版的RT-Thread,去除很多板子的BSP和很多功能组件,组件上只保留了Finsh,当然RTOS的核心功能会保留着。RT-Thread Nano源码下载地址:https://www.rt-thread.org/page/download.html,目前最新版为V3.1.3。

获取到的RT-Thread文件夹目录如下。

2、在工程文件夹下,加入RT-thread文件夹,并在下RT-thread文件夹下加入Include、Port、Source文件夹,存放RT-thread所需文件。



3、将路径RT-Thread/3.1.3/include文件夹下的内容复制到新建的工程目录下的RT-thread/Include文件夹
将路径RT-Thread/3.1.3/components/finsh文件夹复制到新建的RT-thread/Include文件夹




4、将路径RT-Thread/3.1.3/source文件夹下面的 rtconfig.h和board.c文件复制到到工程目录下的source文件夹。

5、将路径RT-Thread/3.1.3/libcpu/arm/cortex-m3文件夹下面的 rtconfig.h和board.c文件复制到到工程目录下的port文件夹。


6、打开hc32f46x_interrupts.c把SysTick_Handler、PendSV_Handler、HardFault_Handler这三个中断函数注释掉,要不然编译会出现重定义错误。



7、修改RT-thread配置文件rtconfig.h头文件进行RTT的配置。里面是通过修改宏来实现的,可以根据实际情况进行修改。这里我不进行该文件修改,直接使用。rtconfig.h文件一些配置宏如下所示。


8、在 MDK source 目录下新建一个 board.h 头文件,用来包含HC32F460固件驱动库和BSP 相关的头文件。

board.h代码如下
#ifndef __BOARD_H
#define __BOARD_H

#include "hc32_ddl.h"
#include "led.h"
#include "uart.h"

void rt_hw_board_init(void);
void SysTick_Handler(void);

#endif    /*__BOARD_H*/
9、修改board.c文件。board.c里面主要完成RT-thread的初始化,并对外设硬件完成初始化。
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date           Author       Notes
* 2017-07-24     Tanek        the first version
* 2018-11-12     Ernest Chen  modify copyright
*/

#include <board.h>
#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>

static void SysTick_Init(void);

#if 0
#define _SCB_BASE       (0xE000E010UL)
#define _SYSTICK_CTRL   (*(rt_uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD   (*(rt_uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL    (*(rt_uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB  (*(rt_uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI    (*(rt_uint8_t  *)(0xE000ED23UL))

// Updates the variable SystemCoreClock and must be called
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);

// Holds the system core clock, which is the system clock
// frequency supplied to the SysTick timer and the processor
// core clock.
extern uint32_t SystemCoreClock;

static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
    if ((ticks - 1) > 0xFFFFFF)
    {
        return 1;
    }
   
    _SYSTICK_LOAD = ticks - 1;
    _SYSTICK_PRI = 0xFF;
    _SYSTICK_VAL  = 0;
    _SYSTICK_CTRL = 0x07;  
   
    return 0;
}

#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE];     // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif

/**
* This function will initial your board.
*/
void rt_hw_board_init()
{
    /* System Clock Update */
    //SystemCoreClockUpdate();
   
    /* System Tick Configuration */
   // _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
      CLK_SetSysClkSource(ClkSysSrcHRC);                        //设置时钟源
   
      SysTick_Init();                                                         //Systick时钟初始化
      
     LED_Init();                                                               //外设LED初始化
     LED0_ON();
  
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}

void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

static void SysTick_Init(void)
{
    stc_clk_freq_t stcClkFreq;

    /* configure structure initialization */
    MEM_ZERO_STRUCT(stcClkFreq);

    /* Config 1 sec trigger interrupt*/
    CLK_GetClockFreq(&stcClkFreq);
    SysTick_Config(stcClkFreq.sysclkFreq/RT_TICK_PER_SECOND);
}

10、到这里RT_thread移植已经完成了,我们还是写个点灯程序测试一下。修改main.c函数

#include "hc32_ddl.h"
#include "led.h"
#include "board.h"
#include "rtthread.h"


/*定义线程控制块*/
static struct rt_thread led1_thread;

/*定义线程空栈时要求RT_ALIGN_SIZE个字节对齐*/
ALIGN(RT_ALIGN_SIZE)

/*定义线程栈*/
static rt_uint8_t rt_led1_thread_stack[1024];

/*函数声明*/
static void led1_thread_entry(void * parameter);


/*******************************************************************************
** \brief  main function for ICG HRC function
**
** \param [in]  None
**
** \retval int32_t Return value, if needed
**
******************************************************************************/
int32_t main(void)
{
    rt_thread_init(&led1_thread,
                                "led1",
                                led1_thread_entry,
                                RT_NULL,
                                &rt_led1_thread_stack,
                                sizeof(rt_led1_thread_stack),
                                3,
                                20);
    rt_thread_startup(&led1_thread);

}

static void led1_thread_entry(void * parameter)
{
    while(1)
    {
        LED0_ON();
        rt_thread_delay(500);
        LED0_OFF();
        rt_thread_delay(500);
    }   
}

11、好了,编译下载可以看看LED灯正常闪烁。


三、添加UART控制台和Finsh组件
在 RT-Thread Nano 上添加 UART 控制台打印功能后,就可以在代码中使用 RT-Thread 提供的打印函数 rt_kprintf() 进行信息打印。Finsh组件是 RT-Thread 的命令行组件(shell),提供一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息。
1、在MDK工程中增加RTT_Component目录,并在目录下添加RT-thread/Include/finsh目录下的cmd.c、msh.c、shell.c文件


2、在MDK工程source目录下增加uart.c和uart.h文件。


3、uart.c包含对uart的初始化和对rt_hw_console_output、rt_hw_console_getchar函数的实现。uart.c代码如下:

#include <uart.h>
#include "rtthread.h"

void Uart_Init(void)
{
      uint16_t u16RxData;
    en_result_t enRet = Ok;
    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 = {
        UsartIntClkCkNoOutput,
        UsartClkDiv_1,
        UsartDataBits8,
        UsartDataLsbFirst,
        UsartOneStopBit,
        UsartParityNone,
        UsartSamleBit8,
        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 */
   USART_UART_Init(USART_CH, &stcInitCfg);

    /* Set baudrate */
   USART_SetBaudrate(USART_CH, USART_BAUDRATE);

    /*Enable RX && TX function*/
    USART_FuncCmd(USART_CH, UsartRx, Enable);
    USART_FuncCmd(USART_CH, UsartTx, Enable);
}
INIT_BOARD_EXPORT(Uart_Init);

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)));
            }
}

char rt_hw_console_getchar(void)
{
        int ch = -1;
            if (Set == USART_GetStatus(USART_CH, UsartRxNoEmpty))
            {
                    ch = USART_RecData(USART_CH);
            }

        return ch;
}

uart.h主要对uart.c内定义的函数进行声明。uart.h代码如下:
#ifndef        __UART_H
#define        __UART_H

#include "hc32_ddl.h"

/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/* USART channel definition */
#define USART_CH                        (M4_USART3)

/* USART baudrate definition */
#define USART_BAUDRATE                  (115200ul)

/* USART RX Port/Pin definition */
#define USART_RX_PORT                   (PortE)
#define USART_RX_PIN                    (Pin04)
#define USART_RX_FUNC                   (Func_Usart3_Rx)

/* USART TX Port/Pin definition */
#define USART_TX_PORT                   (PortE)
#define USART_TX_PIN                    (Pin05)
#define USART_TX_FUNC                   (Func_Usart3_Tx)


void Uart_Init(void);
void rt_hw_console_output(const char *str);
char rt_hw_console_getchar(void);

#endif        /*__UART_H*/
4、串口初始化函数Uart_Init()加入到board.c文件中。Uart_Init()需要在 board.c中的 rt_hw_board_init() 函数中调用。注意不要忘了board.h需要包含uart.h头文件。
void rt_hw_board_init()
{
    /* System Clock Update */
    //SystemCoreClockUpdate();
   
    /* System Tick Configuration */
   // _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
      CLK_SetSysClkSource(ClkSysSrcHRC);
   
      SysTick_Init();
      
     LED_Init();
     LED0_ON();
     Uart_Init();                      串口初始化
      //LED0_OFF();
    // while(1);
   
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#e

5、修改RT-thread配置文件rtconfig.h,在文件中加入使用Finsh组件的宏。
/* RT-Thread config file */

#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

#if defined(__CC_ARM) || defined(__CLANG_ARM)
#include "RTE_Components.h"

#if defined(RTE_USING_FINSH)
#define RT_USING_FINSH
#endif //RTE_USING_FINSH

#endif //(__CC_ARM) || (__CLANG_ARM)

#define RT_USING_FINSH                                               //使用Finsh组件

// <<< Use Configuration Wizard in Context Menu >>>
// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
// <i>Default: 32
#define RT_THREAD_PRIORITY_MAX 8
// <o>OS tick per second
// <i>Default: 1000 (1ms)
#define RT_TICK_PER_SECOND 1000
6、main.c不需重新修改上一章中main函数就行,编译下载验证。
复位开发板,看到输出一下信息。

输入help,输出命令列表。

输入list_thread,输出线程执行情况。

最后,RT-thread和uart控制台和Finsh组件功能增加完毕。

这一次的HC32H460开发板RT-thread Nano移植分享就结束了。有什么写得不对的地方,欢迎各位评论回复,大家一起交流。

@21小跑堂

代码地址:https://gitee.com/Liyj_336/hc32_rtt.git

使用特权

评论回复
沙发
zeshoufx| | 2020-9-20 18:41 | 只看该作者
谢谢分享【HC32F460移植RT-Thread Nano】

使用特权

评论回复
板凳
fcccc| | 2020-9-21 20:21 | 只看该作者
很好的操作

使用特权

评论回复
地板
Joen23| | 2020-11-23 14:56 | 只看该作者
可以发工程源码吗

使用特权

评论回复
5
Puremr| | 2020-11-26 09:19 | 只看该作者
支持下,如果有源码分享的话,那就更好了,RTT是个很不错的操作系统。

使用特权

评论回复
6
Liyj336|  楼主 | 2020-11-28 09:28 | 只看该作者
Joen23 发表于 2020-11-23 14:56
可以发工程源码吗

https://gitee.com/Liyj_336/hc32_rtt.git

使用特权

评论回复
7
Liyj336|  楼主 | 2020-11-28 09:29 | 只看该作者
Puremr 发表于 2020-11-26 09:19
支持下,如果有源码分享的话,那就更好了,RTT是个很不错的操作系统。

https://gitee.com/Liyj_336/hc32_rtt.git

使用特权

评论回复
8
过期的塔头| | 2020-11-29 15:19 | 只看该作者
存放MCU外部外设部分

使用特权

评论回复
9
华芯3284494788| | 2020-12-3 09:39 | 只看该作者
华大一级代理 QQ1593449604  提供样品!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

39

帖子

0

粉丝