我们要实现移植RT-Thread,并且用led和串口证明移植成功。
一. 准备工作
下载 Cube MX 5.0 ,下载地址 https://www.st.com/en/development-tools/stm32cubemx.html
在 CubeMX 上下载 RT-Thread Nano pack 安装包。
1.Nano Pack安装
要获取 RT-Thread Nano 软件包,需要在 CubeMX 中添加 https://www.rt-thread.org/download/cube/RealThread.RT-Thread.pdsc 。
具体步骤:进入打开 CubeMX,从菜单栏 help 进入 Manage embedded software packages 界面,点击 From Url 按钮,进入 User Defined Packs Manager 界面,其次点击 new,填入上述网址,然后点击 check,如下图所示:
check 通过后,点击 OK 回到 User Defined Packs Manager 界面,再次点击 OK,CubeMX 自动连接服务器,获取包描述文件。回到 Manage embedded software packages 界面,就会发现 RT-Thread Nano 3.1.5 软件包,选择该软件包,点击 Install Now,如下图所示:
点击安装之后,弹出 Licensing Agreement ,同意协议,点击 Finish,如下图所示:
等待安装完成,成功安装后,版本前面的小蓝色框变成填充的黄绿色,现象如下图所示:
至此,RT-Thread Nano 软件包安装完毕,退出 Manage embedded software packages 界面,进入 CubeMX 主界面。
2.创建基础工程
在 CubeMX 主界面的菜单栏中 File 选择 New Project,如下图所示
新建工程之后,在弹出界面芯片型号中输入某一芯片型号,方便锁定查找需要的芯片,双击被选中的芯片,如下图所示
时钟树的配置直接使用默认即可,然后还需要配置下载方式。
二.添加RT-Thread Nano到工程
1.选择Nano组件
选中芯片型号之后,点击 Softwares Packages->Select Components,进入组件配置界面,选择 RealThread, 然后根据需求选择 RT-Thread 组件,然后点击 OK 按钮,如下图所示:
注意:RT-Thread Nano 软件包中包含 kernel, shell 和 device 三个部分, 仅选择 kernel 表示只使用 RT-Thread 内核,工程中会添加内核代码; 选择 kernel 与 shell 表示在使用 RT-Thread Nano 的基础上使用FinSH Shell 组件,工程中会添加内核代码与 FinSH 组件的代码,FinSH 的移植详见 《在 RT-Thread Nano上添加控制台与 FinSH》。再选择 device 表示使用 rt-thread 的 device 框架,用户基于此框架编写外设驱动并注册后,就可以使用 device 统一接口操作外设。
2.配置Nano
选择组件之后,对组件参数进行配置。在工程界面 Pinout & Configuration 中,进入所选组件参数配置区,按照下图进行配置
3. 配置MCU()
可以按照自己需求来配置,下面是我对MCU的配置
(1)配置RCC与Debug
进入System Core-SYS设置,选择Debug为Serial wire。其他参数默认
进入System Core-RCC设置,分别配置HSE为Crystal/Ceramic Resonator(晶体/陶瓷谐振器)。其他参数默认
(2)选择GPIO引脚与功能
在右侧的单片机上选择连接有LED灯,比如我的单片机系统的PA0连接了LED灯
配置输出引脚。
在连接了LED灯的引脚上单击左键,选择Output功能。
在PA0上右键,选择Enter User Label,键入别名,输入LED。。
(3)配置GPIO
进入System Core-GPIO设置,上方选择GPIO引脚设置。
配置输出引脚PA0.。选中上方的PA0。
- 引脚上电时的默认状态。(高电平/低电平) 因我的LED灯的阴极连接的单片机引脚,所以选择高电平,表示默认熄灭。
- 引脚模式。(推挽输出/开漏输出) 这里选择推挽输出。
- 开启引脚外部上拉或下拉。(浮空/上拉/下拉) 这里选择上拉。
- 引脚输出速度。(低/中/高/很高) 默认即可。
- 引脚别名。 这里之前选择GPIO时已经配置过就不用在配置。
(4)时钟配置
进入时钟配置界面。根据单片机系统中采用的晶振频率设置HSE,我的单片机系统采用的8M晶振。这里必须使能System Core-RCC中的HSE才可以设置。刚才我们已经配置过了。
配置系统主频,时钟源选择HSE,系统主频选择PLLCLK,再在HCLK框中输入系统推荐的主频,点击回车,软件即可自动配置各个分频器的值。(对于我的stm32f407vet6的时钟配置)
配置简要解释
这里说明一下,为什么要另外选择一个时钟作为STM32的时钟心跳。我们注意看第二步,在配置NVIC的时候,会发现SysTick已经由rt-thread管理了,也就是SysTick是作为rt-thread的心跳。rt-thread进行一些关于系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等都是需要这个时钟提供心跳的。
那为什么不将STM32HAL库的时钟和将rt-thread的时钟作为同一个时钟源呢?如果你尝试过这样做,会发现,一开始系统很小,可能没什么问题,但是后面功能多了,你会发现,系统会一直卡在判断当前时间跳不出循环。因为HAL库在初始化或者其他的一些操作会调用HAL_Delay函数,这个与时间有关的函数,而由于中断优先级的问题,系统会跳不出当前Systick所在优先级的中断,而Systick是被rt-thread管理的,不能更改,就造成了系统的卡死。
到了最需要注意的的的两步了,第一步配置Stm32的系统时钟,由默认的SysTick改为任意一个时钟,个人建议改为普通的定时器。
说完了系统时钟的问题,说一下硬件错误和PSV异常中断。当发生硬件错误,比如内存越界,野指针导致的错误等等,就不会进入STM32HAL库原来的硬件中断函数,进入rt-thread的硬件中断错误函数,并会打印相关寄存器的值和错误类型,还是挺方便的。PSV,PendSV 异常会被初始化为最低优先级的异常。每次需要进行上下文切换的时候,会手动触发 PendSV 异常,在 PendSV 异常处理函数中进行上下文切换。
硬件错误打印例子:提示硬件错误发生在rs485线程
psr: 0x21000000
pc: 0x08010d9a
lr: 0x08010cbd
r12: 0x00000000
r03: 0x000001f4
r02: 0x00000008
r01: 0x20005558
r00: 0x0000012d
hard fault on thread: rs485
thread pri status sp stack size max used left tick error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
heartbea 0x19 suspend 0x00000100 0x00000200 0x00000100 0x00000005 000
hall 0x13 suspend 0x00000118 0x00000400 0x00000118 0x0000000a 000
stepper_ 0x04 suspend 0x00000100 0x00000400 0x00000100 0x00000005 000
flowmete 0x14 suspend 0x00000108 0x00000400 0x00000108 0x00000005 000
nrf24l01 0x15 suspend 0x00000108 0x00000400 0x00000108 0x00000014 000
comm_ove 0x08 suspend 0x00000100 0x00000400 0x00000100 0x00000005 000
breath_t 0x12 suspend 0x00000100 0x00000400 0x00000100 0x00000005 000
debug 0x18 suspend 0x00000118 0x00000400 0x00000118 0x00000005 000
h_l_stat 0x0b suspend 0x00000128 0x00000400 0x00000148 0x00000005