避免弯路:基于新唐BSP标准库函数完美移植RT-Thread注意事项

之前我发过多篇移植RTT到新唐单片机的帖子,不过都是能满足要求,但是还不够完美,本次帖子,完美解决之前的不完美。
该帖基于最新版的RT-Thread Nano 3.1.5版本。
为了体现帖子的完美性,这次我从头开始说关键点。
第一步,基于RTE创建工程,应选择下图的选项

第二步,工程应至少包含以下4个基本库文件


第三步,工程的配置
因为我们可以不使用printf,所以我们可以不包含MicroLIB,甚至我们不用在工程配置里包含STD标准库的头文件进来。
因为BSP的标准库基于AC5编写,所以我们这里最好选择AC5,如果选择AC6,应在警告设置AC5-like ,否则编译会因为打印几百个警告而变慢。
第四步,rtconfig.h配置

第五步,按照#error设定的4个部分配置时钟和硬件初始化,串口初始化,串口输出,串口输入。
时钟初始化,我们可以找到一个厂家提供的模板,复制SYS_Init();并在其中完善滴答定时器的启动与配置。
打开board.c添加系统初始化代码
复制
void SYS_Init(void)

{

    /*---------------------------------------------------------------------------------------------------------*/

    /* Init System Clock                                                                                       */

    /*---------------------------------------------------------------------------------------------------------*/

    /* Unlock protected registers */

    SYS_UnlockReg();

    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */

    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable HIRC clock (Internal RC 48 MHz) */

    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Wait for HIRC clock ready */

    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Set core clock as 51MHz from PLL */

    CLK_SetCoreClock(FREQ_51MHZ);

        

                /* System Tick Configuration */

                CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);

    /* Enable UART clock */

    CLK_EnableModuleClock(UART0_MODULE);

    /* Select UART clock source from HIRC */

    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));

                

    /* Update System Core Clock */

    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */

    SystemCoreClockUpdate();

    /* Set GPB multi-function pins for UART0 RXD and TXD */

    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \

                    (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

    /* Lock protected registers */

    SYS_LockReg();

}

CLK_EnableSysTick这个滴答时钟中断使能与配置函数,可以设置滴答定时器的时钟源,重载值,并使能其中断。
然后就要完成滴答定时器中断的内容:
复制
/* systick 中断服务例程 */

void SysTick_Handler(void)

{

        rt_os_tick_callback();

}
其中内部的回调函数,rtt的board.c已经帮我们完成,只需要添加以上代码段即可,也可修改回调函数的名字为中断入口。
将系统初始化代码填入#error "TODO 1: OS Tick Configuration."后面,并注释掉该行,确保编译时候不再报错提示该位置。
串口初始化,按如下代码进行初始化
复制
static int uart_init(void)

{

//#error "TODO 2: Enable the hardware uart and config baudrate."

    /* Reset UART0 */

    SYS_ResetModule(UART0_RST);

    /* Configure UART0 and set UART0 baud rate */

    UART_Open(UART0, 115200);

        

    return 0;

}
串口输出功能
之前我用了printf实现这部分,但是有个缺点就是要启用MicroLIB,这样就增加了代码存储空间,其实可以使用STD标准库函数实现如下所示,串口写入函数一共三个参数,第一个选用的串口名,第二个是要发送的字符串地址,这里因为类型不同进行了转换,也可以不转换而修改该预设函数的参数类型。第三个是要发送的字符串长度,我们这里用rt的库函数计算一下传入的长度,这样就做到了一个函数一行就搞定了串口打印的映射。
复制
void rt_hw_console_output(const char *str)

{

        //#error "TODO 3: Output the string 'str' through the uart."

                

        UART_Write(UART0,(uint8_t *)str,rt_strlen(str));        

}

串口输入功能
串口输入功能的配置在finsh_port.c
我们完善该弱函数的内容即可,注释掉error提示行。我实现的方法如下:这里是参考了重定向文件里的方法
复制
RT_WEAK char rt_hw_console_getchar(void)

{

    /* Note: the initial value of ch must < 0 */

    int ch = -1;

//#error "TODO 4: Read a char from the uart and assign it to 'ch'."

        if((UART0->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)

        {

                        return (UART0->DAT);

        }

        return ch;

}


最后给大家晒一下关键的board.c完整内容
复制
/*

 * Copyright (c) 2006-2019, RT-Thread Development Team

 *

 * SPDX-License-Identifier: Apache-2.0

 *

 * Change Logs:

 * Date           Author       Notes

 * 2021-05-24                  the first version

 */

#include <rthw.h>

#include <rtthread.h>

#include <NuMicro.h>

#include <stdio.h>

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)

/*

 * Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP

 * the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes

 */

#define RT_HEAP_SIZE (15*1024)

static rt_uint8_t rt_heap[RT_HEAP_SIZE];

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

void rt_os_tick_callback(void)

{

    rt_interrupt_enter();

    

    rt_tick_increase();

    rt_interrupt_leave();

}

/**

 * This function will initial your board.

 */

void SYS_Init(void)

{

    /*---------------------------------------------------------------------------------------------------------*/

    /* Init System Clock                                                                                       */

    /*---------------------------------------------------------------------------------------------------------*/

    /* Unlock protected registers */

    SYS_UnlockReg();

    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */

    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable HIRC clock (Internal RC 48 MHz) */

    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Wait for HIRC clock ready */

    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Set core clock as 51MHz from PLL */

    CLK_SetCoreClock(FREQ_51MHZ);

        

                /* System Tick Configuration */

                CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);

    /* Enable UART clock */

    CLK_EnableModuleClock(UART0_MODULE);

    /* Select UART clock source from HIRC */

    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));

                

    /* Update System Core Clock */

    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */

    SystemCoreClockUpdate();

    /* Set GPB multi-function pins for UART0 RXD and TXD */

    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \

                    (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

    /* Lock protected registers */

    SYS_LockReg();

}

/* systick 中断服务例程 */

void SysTick_Handler(void)

{

        rt_os_tick_callback();

}

void rt_hw_board_init(void)

{

//#error "TODO 1: OS Tick Configuration."

        

        SYS_Init();

        

    /* 

     * TODO 1: OS Tick Configuration

     * Enable the hardware timer and call the rt_os_tick_callback function

     * periodically with the frequency RT_TICK_PER_SECOND. 

     */

    /* Call components board initial (use INIT_BOARD_EXPORT()) */

#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

}

#ifdef RT_USING_CONSOLE

static int uart_init(void)

{

//#error "TODO 2: Enable the hardware uart and config baudrate."

    /* Reset UART0 */

    SYS_ResetModule(UART0_RST);

    /* Configure UART0 and set UART0 baud rate */

    UART_Open(UART0, 115200);

        

    return 0;

}

INIT_BOARD_EXPORT(uart_init);

void rt_hw_console_output(const char *str)

{

        //#error "TODO 3: Output the string 'str' through the uart."

                

        UART_Write(UART0,(uint8_t *)str,rt_strlen(str));        

}

#endif

朋友们,按照这个方法,全部使用BSP提供的库函数就完成了,程序也变的更加友好可读,占用资源更少。
另外注意,在启用了滴答定时器中断后,我们再用CLK_SysTickDelay(1000);延时就会卡住了,这时候系统通过中断接管了滴答定时器的控制权
可以使用rt_thread_mdelay(2000);实现延时。

最后我们测试例子,编写main.c
复制
#include "stdio.h"

#include <NuMicro.h>

#include <rtthread.h>

//配置优先级,栈大小,时间片,设置不对没法运行的。

#define THREAD_PRIORITY         5

#define THREAD_STACK_SIZE       256

#define THREAD_TIMESLICE        10

void led(void *parameter)

{

    printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %d Hz\n", SystemCoreClock);

    printf("+-------------------------------------------------+\n");

    printf("|    PB14(Output)  Sample Code     |\n");

    printf("+-------------------------------------------------+\n\n");

        rt_kprintf("Hello RTT_NANO\n");

        while(1)

                {

                                        PB14=0;

                                        rt_thread_mdelay(2000);

                                        printf("\nLED1 is ON\n");

                                        PB14=1;

                                        rt_thread_mdelay(2000);

                                        printf("\nLED1 is OFF\n");      

                }

//return 0;

}

/* 导出到 msh 命令列表中 */

MSH_CMD_EXPORT(led, RT-Thread first led sample);

void led2(void *parameter)

{

        rt_kprintf("Hello RTT_NANO\n");

        while(1)

                {

                                        PB14=0;

                                        rt_thread_mdelay(3000);

                                        printf("\nLED2 is ON\n");

                                        PB14=1;

                                        rt_thread_mdelay(3000);

                                        printf("\nLED2 is OFF\n");         

                }

//return 0;

}

MSH_CMD_EXPORT(led2, RT-Thread second led sample);

int led_sample(void)

{

static rt_thread_t tid = RT_NULL;

static rt_thread_t tid2 = RT_NULL;

        /* 创建线程1 */

    tid = rt_thread_create("thread1",

                            led, RT_NULL,

                            THREAD_STACK_SIZE,

                            THREAD_PRIORITY, THREAD_TIMESLICE);

    

    if (tid != RT_NULL)       

        rt_thread_startup(tid);

        /* 创建线程2 */

    tid2 = rt_thread_create("thread2",

                            led2, RT_NULL,

                            THREAD_STACK_SIZE,

                            THREAD_PRIORITY, THREAD_TIMESLICE);

    

    if (tid2 != RT_NULL)       

        rt_thread_startup(tid2);                

                //该例子共用PB14端口,所以一并在创建线程时候初始化为输出模式

                GPIO_SetMode(PB, BIT14, GPIO_MODE_OUTPUT);                

    return 0;

}

MSH_CMD_EXPORT(led_sample, RT-Thread sample);

/*---------------------------------------------------------------------------------------------------------*/

/*  Main Function                                                                                          */

/*---------------------------------------------------------------------------------------------------------*/

int32_t main(void)

{

        led_sample();

        return 0;

}


你学会了吗,这样你就不用等RT-Thread Studio支持新唐的芯片了,自己也可以完美移植RTT到新唐单片机了。最后补上我演示以上内容用的基于M471的工程  M471_RTT_nano.rar (152.94 KB, 下载次数: 37)
补上B站视频https://www.bilibili.com/video/BV1mf4y1n7vR/
基于新唐BSP标准库函数完美移植RT-Thread方法_哔哩哔哩_bilibili

---------------------
作者:gaoyang9992006
链接:https://bbs.21ic.com/icview-3158714-1-1.html
来源:21ic.com
此文章来自于21ic网站,著作权归21ic所有,未经允许禁止转载。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值