返回列表 发新帖我要提问本帖赏金: 200.00元(功能说明)

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

[复制链接]
19581|18
 楼主| gaoyang9992006 发表于 2021-8-25 00:10 | 显示全部楼层 |阅读模式
本帖最后由 gaoyang9992006 于 2021-8-26 08:45 编辑

#申请原创# @21小跑堂 注意:文末有视频链接。
之前我发过多篇移植RTT到新唐单片机的帖子,不过都是能满足要求,但是还不够完美,本次帖子,完美解决之前的不完美。
该帖基于最新版的RT-Thread Nano 3.1.5版本。
为了体现帖子的完美性,这次我从头开始说关键点。
第一步,基于RTE创建工程,应选择下图的选项
843766125101ea1c40.png
第二步,工程应至少包含以下4个基本库文件
185106125106a1a946.png

第三步,工程的配置
因为我们可以不使用printf,所以我们可以不包含MicroLIB,甚至我们不用在工程配置里包含STD标准库的头文件进来。
因为BSP的标准库基于AC5编写,所以我们这里最好选择AC5,如果选择AC6,应在警告设置AC5-like ,否则编译会因为打印几百个警告而变慢。
第四步,rtconfig.h配置
25640612512b28bdaa.png
第五步,按照#error设定的4个部分配置时钟和硬件初始化,串口初始化,串口输出,串口输入。
时钟初始化,我们可以找到一个厂家提供的模板,复制SYS_Init();并在其中完善滴答定时器的启动与配置。
打开board.c添加系统初始化代码
  1. void SYS_Init(void)
  2. {
  3.     /*---------------------------------------------------------------------------------------------------------*/
  4.     /* Init System Clock                                                                                       */
  5.     /*---------------------------------------------------------------------------------------------------------*/
  6.     /* Unlock protected registers */
  7.     SYS_UnlockReg();

  8.     /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
  9.     PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

  10.     /* Enable HIRC clock (Internal RC 48 MHz) */
  11.     CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

  12.     /* Wait for HIRC clock ready */
  13.     CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

  14.     /* Set core clock as 51MHz from PLL */
  15.     CLK_SetCoreClock(FREQ_51MHZ);
  16.         
  17.                 /* System Tick Configuration */
  18.                 CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);

  19.     /* Enable UART clock */
  20.     CLK_EnableModuleClock(UART0_MODULE);

  21.     /* Select UART clock source from HIRC */
  22.     CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
  23.                
  24.     /* Update System Core Clock */
  25.     /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
  26.     SystemCoreClockUpdate();

  27.     /* Set GPB multi-function pins for UART0 RXD and TXD */
  28.     SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \
  29.                     (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);
  30.     /* Lock protected registers */
  31.     SYS_LockReg();
  32. }

CLK_EnableSysTick这个滴答时钟中断使能与配置函数,可以设置滴答定时器的时钟源,重载值,并使能其中断。
然后就要完成滴答定时器中断的内容:
  1. /* systick 中断服务例程 */
  2. void SysTick_Handler(void)
  3. {
  4.         rt_os_tick_callback();
  5. }
其中内部的回调函数,rtt的board.c已经帮我们完成,只需要添加以上代码段即可,也可修改回调函数的名字为中断入口。
将系统初始化代码填入#error "TODO 1: OS Tick Configuration."后面,并注释掉该行,确保编译时候不再报错提示该位置。
串口初始化,按如下代码进行初始化
  1. static int uart_init(void)
  2. {
  3. //#error "TODO 2: Enable the hardware uart and config baudrate."

  4.     /* Reset UART0 */
  5.     SYS_ResetModule(UART0_RST);

  6.     /* Configure UART0 and set UART0 baud rate */
  7.     UART_Open(UART0, 115200);
  8.         
  9.     return 0;
  10. }
串口输出功能
之前我用了printf实现这部分,但是有个缺点就是要启用MicroLIB,这样就增加了代码存储空间,其实可以使用STD标准库函数实现如下所示,串口写入函数一共三个参数,第一个选用的串口名,第二个是要发送的字符串地址,这里因为类型不同进行了转换,也可以不转换而修改该预设函数的参数类型。第三个是要发送的字符串长度,我们这里用rt的库函数计算一下传入的长度,这样就做到了一个函数一行就搞定了串口打印的映射。
  1. void rt_hw_console_output(const char *str)
  2. {
  3.         //#error "TODO 3: Output the string 'str' through the uart."
  4.                
  5.         UART_Write(UART0,(uint8_t *)str,rt_strlen(str));        
  6. }

串口输入功能
串口输入功能的配置在finsh_port.c
我们完善该弱函数的内容即可,注释掉error提示行。我实现的方法如下:这里是参考了重定向文件里的方法
  1. RT_WEAK char rt_hw_console_getchar(void)
  2. {
  3.     /* Note: the initial value of ch must < 0 */
  4.     int ch = -1;

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

  6.         if((UART0->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
  7.         {
  8.                         return (UART0->DAT);
  9.         }
  10.         return ch;
  11. }


最后给大家晒一下关键的board.c完整内容
  1. /*
  2. * Copyright (c) 2006-2019, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date           Author       Notes
  8. * 2021-05-24                  the first version
  9. */

  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <NuMicro.h>
  13. #include <stdio.h>

  14. #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
  15. /*
  16. * Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP
  17. * the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes
  18. */
  19. #define RT_HEAP_SIZE (15*1024)
  20. static rt_uint8_t rt_heap[RT_HEAP_SIZE];

  21. RT_WEAK void *rt_heap_begin_get(void)
  22. {
  23.     return rt_heap;
  24. }

  25. RT_WEAK void *rt_heap_end_get(void)
  26. {
  27.     return rt_heap + RT_HEAP_SIZE;
  28. }
  29. #endif

  30. void rt_os_tick_callback(void)
  31. {
  32.     rt_interrupt_enter();
  33.    
  34.     rt_tick_increase();

  35.     rt_interrupt_leave();
  36. }

  37. /**
  38. * This function will initial your board.
  39. */

  40. void SYS_Init(void)
  41. {
  42.     /*---------------------------------------------------------------------------------------------------------*/
  43.     /* Init System Clock                                                                                       */
  44.     /*---------------------------------------------------------------------------------------------------------*/
  45.     /* Unlock protected registers */
  46.     SYS_UnlockReg();

  47.     /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
  48.     PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

  49.     /* Enable HIRC clock (Internal RC 48 MHz) */
  50.     CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

  51.     /* Wait for HIRC clock ready */
  52.     CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

  53.     /* Set core clock as 51MHz from PLL */
  54.     CLK_SetCoreClock(FREQ_51MHZ);
  55.         
  56.                 /* System Tick Configuration */
  57.                 CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);

  58.     /* Enable UART clock */
  59.     CLK_EnableModuleClock(UART0_MODULE);

  60.     /* Select UART clock source from HIRC */
  61.     CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
  62.                
  63.     /* Update System Core Clock */
  64.     /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
  65.     SystemCoreClockUpdate();

  66.     /* Set GPB multi-function pins for UART0 RXD and TXD */
  67.     SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \
  68.                     (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);
  69.     /* Lock protected registers */
  70.     SYS_LockReg();
  71. }

  72. /* systick 中断服务例程 */
  73. void SysTick_Handler(void)
  74. {
  75.         rt_os_tick_callback();
  76. }

  77. void rt_hw_board_init(void)
  78. {
  79. //#error "TODO 1: OS Tick Configuration."
  80.         
  81.         SYS_Init();
  82.         
  83.     /*
  84.      * TODO 1: OS Tick Configuration
  85.      * Enable the hardware timer and call the rt_os_tick_callback function
  86.      * periodically with the frequency RT_TICK_PER_SECOND.
  87.      */

  88.     /* Call components board initial (use INIT_BOARD_EXPORT()) */
  89. #ifdef RT_USING_COMPONENTS_INIT
  90.     rt_components_board_init();
  91. #endif

  92. #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
  93.     rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
  94. #endif
  95. }

  96. #ifdef RT_USING_CONSOLE

  97. static int uart_init(void)
  98. {
  99. //#error "TODO 2: Enable the hardware uart and config baudrate."

  100.     /* Reset UART0 */
  101.     SYS_ResetModule(UART0_RST);

  102.     /* Configure UART0 and set UART0 baud rate */
  103.     UART_Open(UART0, 115200);
  104.         
  105.     return 0;
  106. }
  107. INIT_BOARD_EXPORT(uart_init);

  108. void rt_hw_console_output(const char *str)
  109. {
  110.         //#error "TODO 3: Output the string 'str' through the uart."
  111.                
  112.         UART_Write(UART0,(uint8_t *)str,rt_strlen(str));        
  113. }

  114. #endif



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

最后我们测试例子,编写main.c
  1. #include "stdio.h"
  2. #include <NuMicro.h>
  3. #include <rtthread.h>
  4. //配置优先级,栈大小,时间片,设置不对没法运行的。
  5. #define THREAD_PRIORITY         5
  6. #define THREAD_STACK_SIZE       256
  7. #define THREAD_TIMESLICE        10
  8. void led(void *parameter)
  9. {
  10.     printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %d Hz\n", SystemCoreClock);
  11.     printf("+-------------------------------------------------+\n");
  12.     printf("|    PB14(Output)  Sample Code     |\n");
  13.     printf("+-------------------------------------------------+\n\n");

  14.         rt_kprintf("Hello RTT_NANO\n");
  15.         while(1)
  16.                 {
  17.                                         PB14=0;
  18.                                         rt_thread_mdelay(2000);
  19.                                         printf("\nLED1 is ON\n");
  20.                                         PB14=1;
  21.                                         rt_thread_mdelay(2000);
  22.                                         printf("\nLED1 is OFF\n");      
  23.                 }
  24. //return 0;
  25. }
  26. /* 导出到 msh 命令列表中 */
  27. MSH_CMD_EXPORT(led, RT-Thread first led sample);
  28. void led2(void *parameter)
  29. {

  30.         rt_kprintf("Hello RTT_NANO\n");
  31.         while(1)
  32.                 {
  33.                                         PB14=0;
  34.                                         rt_thread_mdelay(3000);
  35.                                         printf("\nLED2 is ON\n");
  36.                                         PB14=1;
  37.                                         rt_thread_mdelay(3000);
  38.                                         printf("\nLED2 is OFF\n");         
  39.                 }
  40. //return 0;
  41. }
  42. MSH_CMD_EXPORT(led2, RT-Thread second led sample);
  43. int led_sample(void)
  44. {
  45. static rt_thread_t tid = RT_NULL;
  46. static rt_thread_t tid2 = RT_NULL;
  47.         /* 创建线程1 */
  48.     tid = rt_thread_create("thread1",
  49.                             led, RT_NULL,
  50.                             THREAD_STACK_SIZE,
  51.                             THREAD_PRIORITY, THREAD_TIMESLICE);
  52.    
  53.     if (tid != RT_NULL)      
  54.         rt_thread_startup(tid);
  55.         /* 创建线程2 */
  56.     tid2 = rt_thread_create("thread2",
  57.                             led2, RT_NULL,
  58.                             THREAD_STACK_SIZE,
  59.                             THREAD_PRIORITY, THREAD_TIMESLICE);
  60.    
  61.     if (tid2 != RT_NULL)      
  62.         rt_thread_startup(tid2);               
  63.                 //该例子共用PB14端口,所以一并在创建线程时候初始化为输出模式
  64.                 GPIO_SetMode(PB, BIT14, GPIO_MODE_OUTPUT);               
  65.     return 0;
  66. }
  67. MSH_CMD_EXPORT(led_sample, RT-Thread sample);
  68. /*---------------------------------------------------------------------------------------------------------*/
  69. /*  Main Function                                                                                          */
  70. /*---------------------------------------------------------------------------------------------------------*/
  71. int32_t main(void)
  72. {
  73.         led_sample();
  74.         return 0;
  75. }
48657612519e8d6030.png
92297612519fbe0e76.png

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



打赏榜单

21小跑堂 打赏了 200.00 元 2021-08-26
理由:恭喜通过原创奖文章审核!请多多加油哦!

评论

重定向文件中的硬件错误中断处理函数,已经被系统重写,因此会有重复定义的报错,这里注释掉重定向文件中的__asm int32_t HardFault_Handler(void)函数即可。在视频中已经说明。  发表于 2021-8-26 14:21
yangjiaxu 发表于 2021-8-25 13:07 | 显示全部楼层
挺不错,支持一波
wcheng13 发表于 2021-8-25 14:45 | 显示全部楼层
看看,先顶一个
kiwis66 发表于 2021-8-25 17:13 | 显示全部楼层
真不错,学习了~
caizhiwei 发表于 2021-8-27 15:31 | 显示全部楼层
200到手,羡慕啊,羔羊哥~
 楼主| gaoyang9992006 发表于 2021-8-29 12:34 | 显示全部楼层
caizhiwei 发表于 2021-8-27 15:31
200到手,羡慕啊,羔羊哥~

你也可以啊,申请个蓝V认证,然后写一篇STM32F103的基于HAL库函数完美移植RTT的,目前有很多人想看到这个题目的贴文。你先发了,200就是你的了。
liaoxr 发表于 2021-9-1 20:52 | 显示全部楼层
@gaoyang9992006 版主,为啥我用你的程序直接调试啥也没有改,程序全速运行是不行的,直接卡死在Reset_Handler。重定向文件中的__asm int32_t HardFault_Handler(void)我看你的程序已经屏蔽掉了,但是这个程序跑不起来是啥原因呢。
C:\Users\86158\Desktop\1.PNG
liaoxr 发表于 2021-9-1 20:56 | 显示全部楼层
补充图片
52584612f786ab793b.png
 楼主| gaoyang9992006 发表于 2021-9-1 21:19 | 显示全部楼层

请确认你是否在pack管理器正确安装了RTT nano 3.1.5,另外是否安装好了新唐的pack。
 楼主| gaoyang9992006 发表于 2021-9-1 21:23 | 显示全部楼层

你是没有这个开发板吧?然后你用的是仿真模式,这个工程只支持硬件模式,不支持simulation。
liaoxr 发表于 2021-9-2 10:28 | 显示全部楼层
gaoyang9992006 发表于 2021-9-1 21:23
你是没有这个开发板吧?然后你用的是仿真模式,这个工程只支持硬件模式,不支持simulation。 ...

版主,RTT nano我有安装了的,M471这个板子比较老,所以使用软件仿真。我这边重新按操作移植到M031SD的板子上,也是出现全速跑不了,直接进入Reset Hardler了。
liaoxr 发表于 2021-9-2 10:35 | 显示全部楼层
我是先采用官方的例程测试好GPIO功能和打印功能正常后,我再进行移植RTT Nano的,一直想学下这个,但是移植还是不知道哪里出问题了。
152076130384764d42.jpg

7241161303859066f7.jpg

449096130385ff2610.jpg











liaoxr 发表于 2021-9-2 10:39 | 显示全部楼层
版主,这是我移植的程序,可以帮忙看下哪里移植有问题不,感谢感谢。
链接:https://pan.baidu.com/s/1rJcTVnVdgsnM8HDSn-a_BA
提取码:lawr
 楼主| gaoyang9992006 发表于 2021-9-2 15:56 | 显示全部楼层
liaoxr 发表于 2021-9-2 10:39
版主,这是我移植的程序,可以帮忙看下哪里移植有问题不,感谢感谢。
链接:https://pan.baidu.com/s/1rJcT ...

给你修改了一下,你可能是在重定向文件中屏蔽了不该屏蔽的,这里只需要屏蔽错误中断处理函数即可,其他的不要动。
另外你没有完全按照我帖子说的配置工程。
M031BSP-master.rar (590.2 KB, 下载次数: 15)
你试试,这个功能能否正常运行。
 楼主| gaoyang9992006 发表于 2021-9-2 15:59 | 显示全部楼层
liaoxr 发表于 2021-9-2 10:39
版主,这是我移植的程序,可以帮忙看下哪里移植有问题不,感谢感谢。
链接:https://pan.baidu.com/s/1rJcT ...

以后上传工程,先清理一下工程,然后再打包,不然编译过程产生的中间文件都打包进来了,太大。

评论

收到,我这边验证下,感谢。  发表于 2021-9-2 16:39
邹姆斯特朗 发表于 2021-11-5 17:19 | 显示全部楼层
可以的,很详细
天灵灵地灵灵 发表于 2021-12-21 21:17 | 显示全部楼层
完整版也是这么移植的?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2052

主题

16404

帖子

222

粉丝
快速回复 在线客服 返回列表 返回顶部