【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

目录

背景:移植RT-Thread nano,并基于  nano 添加 FinSH/shell

前提及准备工作

step1:添加rt-thread nano到裸机工程

1.1、Nano Pack 安装

方法一:Pack Installer 安装

方法二:手动安装

1.2、基础工程准备

1.3、开始移植rtt nano到裸机工程

1.4、适配 RT-Thread nano

1.5、RT-Thread Nano 配置(选配)

1.6 常见问题

step2:添加finsh到工程

2.1、添加finsh源码

2.2、实现uart驱动

2.3、修改console名称

2.4、下载验证

2.5 附录一份uart驱动供参考

2.6 常见问题


背景:移植RT-Thread nano,并基于  nano 添加 FinSH/shell

在nano上添加finsh可以有两种方法:

1、移植finsh基于device框架【这个官方文档中心有相关的文章了,链接:https://www.rt-thread.org/document/site/tutorial/nano/nano_finsh/an0033-nano-finsh/

2、移植finsh不基于device框架【本文讲解这个不基于device框架的,从头讲解,如果移植rtt nano,然后基于这个nano 再移植finsh】【本文基于 rtt nano 3.1.2 /3.1.1】要移植3.1.3请至rtt官网查看,有教程。

前提及准备工作

  1. 安装了mdk
  2. 一个stm32 mdk裸机工程:要一份能运行的基本工程,如一个f103的可以跑led的裸机工程即可。(这里基于hal库做的mdk工程)
  3. 一个nano源码:我们直接从keil中下载nano的pack包
  4. 注意,本文基于 rtt nano 3.1.2 版本,3.1.1也行

step1:添加rt-thread nano到裸机工程

注意:step1 是参考了RTT文档中心的教程。

1.1、Nano Pack 安装

Nano Pack 可以通过 MDK 联网安装,也可以手动安装。下面开始介绍两种安装方式。

方法一:Pack Installer 安装

打开 MDK 软件,点击工具栏的 Pack Installer 图标:

点击右侧的 Pack,展开 Generic,可以找到 RealThread::RT-Thread,点击 Action 栏对应的 Install ,就可以在线安装 Nano Pack 了。另外,如果需要安装其他版本,则需要展开 RealThread::RT-Thread,进行选择。

方法二:手动安装

我们也可以从官网下载安装文件,RT-Thread Nano 离线安装包下载,下载结束后双击文件进行安装。

RT-Thread Nano 离线安装包下载路径:https://www.rt-thread.org/download/mdk/RealThread.RT-Thread.3.0.3.pack

1.2、基础工程准备

在开始创建 RT-Thread 小系统之前,我们需要准备一个能正常运行的裸机工程。作为示例,本文使用的是基于 STM32L475-Pandora 和 HAL 库的一个 LED 闪烁程序。程序的主要截图如下:

在我们的例程中主要做了系统初始化与LED闪烁功能,编译下载程序后,就可以看到 LED 闪烁了。读者可以根据自己的需要使用其他芯片,完成一个简单的类似裸机工程。

1.3、开始移植rtt nano到裸机工程

打开已经准备好的可以运行的裸机程序,将 RT-Thread 添加到工程。如下图,点击 Manage Run-Time Environment。、

在 Manage Rum-Time Environment 里”Software Component” 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击”OK” 就添加 RT-Thread 内核到工程了。

现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 RTOS,可以看到添加到工程的文件:

 

Cortex-M 芯片内核移植代码:


   
   
  1. context_rvds .s
  2. cpuport .c

kernel文件


   
   
  1. clock .c
  2. components .c
  3. device .c
  4. idle .c
  5. ipc .c
  6. irq .c
  7. kservice .c
  8. mem .c
  9. object .c
  10. scheduler .c
  11. thread .c
  12. timer .c

 应用代码及配置文件:


   
   
  1. board .c
  2. rtconfig .h

1.4、适配 RT-Thread nano

RT-Thread 会用到了异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),以及 Systick 中断服务函数 SysTick_Handler(),所以用户代码需要保证这几个函数没有被使用,若编译提示函数重复定义,请删除自己定义的函数。

RT-Thread Nano 在 board.c 中默认完成了 systick 的配置,用户可以修改宏 RT_TICK_PER_SECOND 的值配置每秒 systick 数。

RT-Thread Nano 默认是使用数组作为 heap。

替换例程中的 delay 函数:

1). 包含 RT-Thread 的相关头文件 <rtthread.h>

2). 删除之前在裸机工程中做的系统配置(如hal初始化、时钟初始化等),这是因为RT-Thread在系统启动时已经配置完成,否则会重复配置。

3). 将 delay() 函数替换成 rt_thread_mdelay(),如 rt_thread_mdelay(500) 将延时 500ms。

下面是完成修改的代码:

编译程序之后下载到芯片就可以看到基于 RT-Thread 的程序运行起来了,LED 正常闪烁。

注意事项:当添加 RT-Thread 之后,裸机中的 main() 函数会自动变成 RT-Thread 系统中 main 线程 的入口函数。由于线程不能一直独占 CPU,所以此时在 main() 中使用 while(1) 时,需要有让出 CPU 的动作,比如使用 rt_thread_mdelay() 系列的函数让出 CPU。另外3.0.3版本中还没有 rt_thread_mdelay() 接口,可以使用 rt_thread_delay()

1.5、RT-Thread Nano 配置(选配)

用户可以根据自己的需要通过修改 rtconfig.h 文件里面的宏定义配置相应功能。

RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务及信号量。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。

MDK 的配置向导 configuration Wizard 可以很方便的对工程进行配置,Value 一栏可以选中对应功能及修改相关值,等同于直接修改配置文件 rtconfig.h。

1.6 常见问题

Q1:如何升级 pack?

A:Pack 升级步骤基本如同软件包,展开 RealThread::RT-Thread 后,选择比较新的 Nano 版本,点击 Install 进行安装。如下图所示,点击红色框中的 Install 进行升级,即可将 3.1.1 版本升级到 3.1.2。

step2:添加finsh到工程

2.1、添加finsh源码

点击Manage Run-Environment:

勾选device drivers与shell,这将自动把FinSH组件的源码到工程,并自动添加 #define RTE_USING_DEVICE#define RTE_USING_FINSH 宏:

2.2、实现uart驱动

实现uart驱动,主要实现初始化与读写接口,并借助了device注册接口,将uart注册到系统中,使其更方便的对接shell。需要实现的函数原型如下:


   
   
  1. rt_err_t (*init) ( rt_device_t dev);
  2. rt_err_t (*open) ( rt_device_t dev, rt_uint16_t oflag);
  3. rt_size_t (*read) ( rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
  4. rt_size_t (*write) ( rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
  5. //外加一个注册的函数,注册一个 rt_device 的实例,方便对接 FinSH 组件。

需要添加的代码如下所示:


   
   
  1. rt_err_t uart_init(rt_device_t dev)
  2. {
  3. ...
  4. }
  5. rt_err_t uart_open(rt_device_t dev, rt_uint16_t oflag)
  6. {
  7. return uart_init(dev);
  8. }
  9. rt_size_t uart_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  10. {
  11. ...
  12. }
  13. rt_size_t uart_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  14. {
  15. ...
  16. }
  17. struct rt_device uart_dev;
  18. static int uart_register(void)
  19. {
  20. uart_dev.init = uart_init;
  21. uart_dev.open = uart_open;
  22. uart_dev.read = uart_read;
  23. uart_dev.write = uart_write;
  24. rt_device_register(&uart_dev, "uart1", 0);
  25. return 0;
  26. }
  27. INIT_BOARD_EXPORT(uart_register);
  • uart_init():初始化串口,包括硬件引脚的初始化与串口传输模式及波特率等的设置。
  • uart_open():打开串口,使用该接口仅仅是为了对接 FinSH,没有实际意义,直接返回串口初始化即可。
  • uart_read():读入字符,长度size。
  • uart_write():输出字符,长度size。注意输出打印时,在遇到 \n 时,就在输出 \n 之前先输出一个 \r
  • uart_register():注册函数,将uart设备注册到系统中,务必使用INIT_BOARD_EXPORT()初始化该函数。

注意:RT-Thread 系统中已有的打印均以 “\n” 结尾,而并非 “\r\n”,所以在字符输出时,需要在输出“\n”之前输出“\r”完成回车与换行,否则系统打印出来的信息将只有换行。

2.3、修改console名称

打开rtconfig.h文件:将console的名称修改为刚注册到系统中的uart名称,这样FinSH就对接到了UART端口上。如上面注册名为“uart1”,则在rtconfig.h中修改 RT_CONSOLE_DEVICE_NAME 的定义为 uart1:

#define RT_CONSOLE_DEVICE_NAME      "uart1"
   
   

2.4、下载验证

下载到开发板进行验证,移植成功

2.5 附录一份uart驱动供参考


   
   
  1. static UART_HandleTypeDef UartHandle;
  2. rt_err_t uart_init(rt_device_t dev)
  3. {
  4. UartHandle.Instance = USART1;
  5. UartHandle.Init.BaudRate = 115200;
  6. UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  7. UartHandle.Init.Mode = UART_MODE_TX_RX;
  8. UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
  9. UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  10. UartHandle.Init.StopBits = UART_STOPBITS_1;
  11. UartHandle.Init.Parity = UART_PARITY_NONE;
  12. if (HAL_UART_Init(&UartHandle) != HAL_OK)
  13. {
  14. while ( 1);
  15. }
  16. return 0;
  17. }
  18. rt_err_t uart_open(rt_device_t dev, rt_uint16_t oflag)
  19. {
  20. return uart_init(dev);
  21. }
  22. rt_size_t uart_read(rt_device_t dev,
  23. rt_off_t pos,
  24. void *buffer,
  25. rt_size_t size)
  26. {
  27. while ( 1)
  28. {
  29. if (HAL_UART_Receive(&UartHandle, buffer, size, 20) == 0)
  30. {
  31. return size;
  32. }
  33. }
  34. }
  35. rt_size_t uart_write(rt_device_t dev,
  36. rt_off_t pos,
  37. const void *buffer,
  38. rt_size_t size)
  39. {
  40. rt_size_t i = 0;
  41. char a = '\r';
  42. const char *val = 0;
  43. val = ( const char *)(buffer);
  44. __HAL_UNLOCK(&UartHandle);
  45. for (i = 0; i < size; i++)
  46. {
  47. if (*(val + i) == '\n')
  48. {
  49. HAL_UART_Transmit(&UartHandle, ( uint8_t *)&a, 1, 20);
  50. }
  51. HAL_UART_Transmit(&UartHandle, ( uint8_t *)(val + i), 1, 20);
  52. }
  53. return 1;
  54. }
  55. struct rt_device uart_dev;
  56. static int uart_register(void)
  57. {
  58. uart_dev.init = uart_init;
  59. uart_dev.open = uart_open;
  60. uart_dev.read = uart_read;
  61. uart_dev.write = uart_write;
  62. rt_device_register(&uart_dev, "uart1", 0);
  63. return 0;
  64. }
  65. INIT_BOARD_EXPORT(uart_register);

2.6 常见问题

Q1:输出打印正常,却没有打印 msh >,也不能输入。

A:这是由于FinSH 没打开,所以只有打印功能,需要在rtconfig.h中打开 #define RTE_USING_FINSH 宏定义。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值