STM32 RT-Thread Nano(1)基于 Keil MDK 移植

本文介绍如何基于 Keil MDK 移植 RT-Thread Nano ,并以一个 stm32f103 的基础工程作为示例进行讲解。

开发平台:Keil MDK 5.24

硬件平台:XNUCLEO-F103RB 链接地址

移植系统:RT-Thread Nano V3.1.3 下载链接

 

实现内容:

  • 主程序中LED3实现间隔2秒亮灭
  • 创建一个线程实现LED4间隔500ms亮灭
  • 创建一个动态线程
  • 实现Finsh控制台,并可在控制台启动动态线程
  • 实现Finsh自定义命令

本文只实现第1条,后面内容在文章2/3中实现。

 

准备内容:

  • 准备一份基础的裸机源码工程,如一份 stm32 的 LED 指示灯闪烁示例代码。
  • 在 KEIL 上安装 RT-Thread Nano Pack。

 

移植步骤:

移植步骤是按照官网的文章《基于 Keil MDK 移植 RT-Thread Nano》来安装的,这里重新复制过来主要是安装过程中的一些问题写入其中。且官网的内容是基于HAL库编写的,我是基于STM32F10x_StdPeriph_Driver库函数来编写,所以有些不同。

 

1、Nano Pack 安装

Nano Pack 可以通过在 Keil MDK IDE 内进行安装,也可以手动安装。

方法一:在 IDE 内安装

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

Packs 安装

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

Packs 管理

方法二:手动安装

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

Packs 手动安装

 

2、添加 RT-Thread Nano 到工程

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

MDK RTE

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

添加 Nano 内核

现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 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

 

3、适配 RT-Thread Nano

中断与异常处理

RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。

我的补充:这里我们需要注释掉stm32f10x_it.c文件中内容:

 

4、系统时钟配置

需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 os tick 的配置(为操作系统提供心跳 / 节拍)。

如下图所示,SystemCoreClockUpdate() 配置了系统时钟,_SysTick_Config() 配置了 OS Tick。此处 OS Tick 使用滴答定时器 systick 实现,需要用户在 board.c 中实现 SysTick_Handler() 中断服务例程,调用 RT-Thread 提供的 rt_tick_increase() 。

系统时钟与 OS Tick 配置

OS Tick 的实现

由于 SysTick_Handler() 中断服务例程由用户在 board.c 中重新实现,做了系统 OS Tick,所以还需要删除工程里中原本已经实现的 SysTick_Handler() ,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。

 

5、内存堆初始化

系统内存堆的初始化在 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() 将被调用,如下所示:

系统 heap 初始化

初始化内存堆需要堆的起始地址与结束地址这两个参数,系统中默认使用数组作为 heap,并获取了 heap 的起始地址与结束地址,该数组大小可手动更改,如下所示:

默认 heap 的实现

注意:开启 heap 动态内存功能后,heap 默认值较小,在使用的时候需要改大,否则可能会有申请内存失败或者创建线程失败的情况,修改方法有以下两种:

  • 可以直接修改数组中定义的 RT_HEAP_SIZE 的大小,至少大于各个动态申请内存大小之和,但要小于芯片 RAM 总大小。
  • 也可以参考《RT-Thread Nano 移植原理》——实现动态内存堆 章节进行修改,使用 RAM ZI 段结尾处作为 HEAP 的起始地址,使用 RAM 的结尾地址作为 HEAP 的结尾地址,这是 heap 能设置的最大值的方法。

我的补充:当我在添加控制台和Finsh时,间隔500ms的LED闪烁线程并不能创建,后面发现是heap内存太小,修改了RT_HEAP_SIZE的值正常了。可能是控制台和FinSH占用了太多动态内存导致动态内存不足而不能创建线程。如果芯片RAM足够的话,尽量设置的大一些。

 

6、编写第一个应用

移植好 RT-Thread Nano 之后,则可以开始编写第一个应用代码验证移植结果。此时 main() 函数就转变成 RT-Thread 操作系统的一个线程,现在可以在 main() 函数中实现第一个应用:板载 LED 指示灯闪烁,这里直接基于裸机 LED 指示灯进行修改。

  1. 首先在文件首部增加 RT-Thread 的相关头文件 <rtthread.h> 。
  2. 在 main() 函数中(也就是在 main 线程中)实现 LED 闪烁代码:初始化 LED 引脚、在循环中点亮 / 熄灭 LED。
  3. 将延时函数替换为 RT-Thread 提供的延时函数 rt_thread_mdelay()。该函数会引起系统调度,切换到其他线程运行,体现了线程实时性的特点。

RT-THREAD main

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

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

与裸机 LED 闪烁应用代码的不同

1). 延时函数不同: RT-Thread 提供的 rt_thread_mdelay() 函数可以引起操作系统进行调度,当调用该函数进行延时时,本线程将不占用 CPU,调度器切换到系统的其他线程开始运行。而裸机的 delay 函数是一直占用 CPU 运行的。

2). 初始化系统时钟的位置不同:移植好 RT-Thread Nano 之后,不需要再在 main() 中做相应的系统配置(如 hal 初始化、时钟初始化等),这是因为 RT-Thread 在系统启动时,已经做好了系统时钟初始化等的配置,这在上一小节 “系统时钟配置” 中有讲解。

 

我的补充:我是基于STM32F10x_StdPeriph_Driver库函数编写的。实现了LED3间隔两秒的亮灭。


   
   
  1. int main(void)
  2. {
  3. GpioInit();
  4. while( 1)
  5. {
  6. GPIO_WriteBit(LED3_GPIO_Port, LED3_GPIO_Pin, Bit_SET);
  7. rt_thread_mdelay( 2000);
  8. GPIO_WriteBit(LED3_GPIO_Port, LED3_GPIO_Pin, Bit_RESET);
  9. rt_thread_mdelay( 2000);
  10. }
  11. return 0;
  12. }

 

7、配置 RT-Thread Nano

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

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

MDK 的配置向导 configuration Wizard 可以很方便的对工程进行配置,Value 一栏可以选中对应功能及修改相关值,等同于直接修改配置文件 rtconfig.h。更多细节配置详见 《 RT-Thread Nano 配置》

Nano 配置

Nano 配置

 

8、获取示例代码

Keil MDK 中集成的 RT-Thread Nano 软件包附带示例代码,如果需要参照示例代码,则可以在 Keil 中打开相应的示例代码工程。

首先点击 Pack Installer,进入下图所示界面:

在 keil 中打开示例代码

右侧界面切换到 Examples,然后在左侧界面搜索 Device 或者 Boards,点击搜索出的芯片或者开发板,会显示与其相关的所有示例代码,同时可以看到 RT-Thread 的示例代码也在其中,点击 Copy,选择一个路径,然后点击 OK 即可打开示例代码工程。

 

参考文章:

基于 Keil MDK 移植 RT-Thread Nano

在 RT-Thread Nano 上添加控制台与 FinSH

rt-thread创建动态线程失败

RTT NANO 入门2

RTT NANO 入门3--FinSH

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值