源码 移植_实时操作系统RTThread(Nano)的移植
写在前面:作者以前在工作中使用过ucos这款久负盛名的rtos,对于Freertros并没有使用过,当时使用的时候基本都只是调用相关的API接口函数来完成对应的东西,并没有深入的去探究rtos内部的处理机制。前段时间项目上要用到RT-Thread这款国产rtos,经过一段时间的使用,我觉得RT-Thread简直是RTOS界的巅峰之作(个人观点)。 此后这段时间,我...
写在前面:
作者以前在工作中使用过ucos这款久负盛名的rtos,对于Freertros并没有使用过,当时使用的时候基本都只是调用相关的API接口函数来完成对应的东西,并没有深入的去探究rtos内部的处理机制。前段时间项目上要用到RT-Thread这款国产rtos,经过一段时间的使用,我觉得RT-Thread简直是RTOS界的巅峰之作(个人观点)。
此后这段时间,我有空就会把自己对于rt-thtred的源码的实现机制的个人理解写成文字分析的形式分享出来,欢迎大家一起交流进步。这个过程可能会花费不少精力,但是我觉得很值,分析rtthread源码的主要目的如下:
1>真正的理解rtos的具体实现机制,让你在项目中使用的时候真正的做到心中有数。
2>因为作者本身是学电出身,软件方面还有很多欠缺,通过对rt-thread源码浏览可以加强自己的编码内功(rtthread源码中大量的使用了很多高级的数据结构形式和编码形式)。
3>为更进一步的学习嵌入式linux,打下基础,rtthread的编码风格和linux很是接近。
好了,圈子暂时就画这么大,千里之行,始于足下,让我们从RT-Thread的移植开始吧!
1、RT-Thread Nano源码包下载
相关网站:https://www.rt-thread.org/
首先,我们从官网上下载最新的th-thread nano的源码包(现在最新的是3.1.3)。解压之后,可以看到rt-thread的内核源码目录如下:

我们用vscode,直接打开整个文件夹,可以更方便的浏览其内核源码目录架构组成。

bsp:板级支持包
components:RT-Thread组件
doc:此版本内核的一些官方说明文档
include:存放的相关头文件
libcpu:与处理器相关的接口文件
src:RT-Thread的内核源码
AUTHORS、ChangeLog.md、LICENSE、README.md:这四个文件是一些作者说明、代码迭代说明等。
在移植以前,建议大家将官方doc对这一版内核的说明详细浏览一遍),相关文档如下。

作者把这8个官方文档挨个大致看了一遍(我比较笨,只能全看,一点一点来吧)。
2、准备一份裸机工程
比如,我们准备一个cpu内核为Cortex-M4内核的硬件平台裸机工程。
3、添加RT-Thread Nano到裸机工程
3.1 添加RT-Thread源文件
在准备好的 keil 裸机工程下面新建 rtthread 文件夹,并在该文件中添加以下文件:
• Nano 源码中的 include、libcpu、src 文件夹。
• 配置文件:源码代码 rtthread/bsp 文件夹中的两个文件:board.c 与 rtconfig.h 。

接下来打开准备好的基础裸机工程,新建rtthread文件夹,在rthread文件夹分组下面添加以下代码文件:
• 添加工程下 rtthread/src/ 文件夹中所有文件到工程;
• 添加工程下 rtthread/libcpu/ 文件夹中相应内核的 CPU 移植文件及上下文 切换文件:cpuport.c 以及 context_rvds.S ;
• 添加 rtthread/ 文件夹下的 board.

rtthread nano源码与配置文件
Cortex-M芯片内核移植代码:

RT-Thread kernel文件:

板级配置代码:

3.2 添加头文件路径
将内核源码中的所有头文件路径都添加到基础工程中。

4、适配RT-Thread Nano到自己的硬件开发平台上
4.1 中断与异常处理
异常处理函数HardFault_Handler()和悬挂处理函数PendSV_Handler(),
这两个函数会由rtthread接管并实现,所以我们要先删除工程里面的这两个函数,以便避免重复定义的错误。


找到上面这两个函数,删掉。
4.2 系统时钟配置
其实在哪里实现这个都可以,但是为了和官方统一,也为了方便管理,我们在board.c中实现《系统时钟配置》和《OS Tick配置》。
系统时钟配置:为MCU内核、外设提供工作时钟。
OS Tick:为操作系统提供心跳/节拍。

如上图所示,systemCoreClockUpdate( )配置了系统时钟,_SysTick_Config( )配置了OS_Tick。这块我们配置为1ms进来一次,即产生一次系统滴答中断,具体自己配置,这块不展开说了。OS_Tick使用滴答定时器systick实现。在上图中为SysTick_Handler( )中断服务函数,调用rtthread的rt_tick_increase( ) 函数。SysTICK_Handler( )我们在board.c这块已经做了重新定义,所以删除掉/屏蔽基础工程中的这个函数,避免产生重复定义错误。

4.3 内存堆初始化
我们这时候再来浏览板级配置文件board.c ,发现还有一个文件我们还没有适配,如下:

这和系统内存堆大小配置相关,默认不开启。系统内存堆的初始化是在
rt_hw_board_init( )函数中完成的,是否启用,取决于宏RT_USING_HEAP是否开启。开启系统堆就可以正常使用动态内存功能,列入:rt_malloc、rt_free和各种系统动态创建对象的API函数。

从上图函数原型可知,内存堆初始化函数rt_system_heap_init( ) 有两个参数------堆的起始地址、堆的结束地址。系统默认使用数组来作为heap(默认数组大小为4K(1024 * 4)),这个堆数组大小可以手动修改,并且获取了heap的起始地址和结束地址。
注意:堆数组大小修改时需注意,这个大小的标准是大于各个动态申请内存大小之和,并且小于MCU的芯片RAM大小。最好的一种方法就是:使用RAM ZI段结尾作为heap堆的起始地址,使用RAM 的结尾地址作为heap堆的结尾地址(在项目中我们也是经常这样用的)。
对了,rtthread的编码风格十分严谨和规范,刚刚需要开启的系统堆内存管理的宏RT_USING_HEAP在rtconfig.h文件中,rtconfig.h文件是rtthread的功能配置文件,通过此文件的宏选择,可以对rtthread的功能进行有效裁剪。
5、编写应用程序
当完成上述几点移植后,我们就可以编写我们的应用程序了。

这块我是根据自己的项目编写的应用程序的main.c文件,具体大家可以根据自己的需要编写。这块也涉及到一个rtthread的启动流程。官网上有详细说明,大家自己去看,大致如下:

(官方说明摘要): RT-Thread 启动代码统一入口为 rtthread_startup() ,芯片启动文件在完成必要工作(如初始化时钟、配置中断向量表、初始化堆栈等)后,最终会在程序跳转时,跳转至 RT-Thread 的启动入口中。
RT-Thread 的启动流程如下:
1. 全局关中断,初始化与系统相关的硬件。
2. 打印系统版本信息,初始化系统内核对象(如定时器、调度器)。
3. 初始化用户 main 线程(同时会初始化线程栈),在 main 线程中对各类模块依次进行初始化。
4. 初始化软件定时器线程、初始化空闲线程。
5. 启动调度器,系统切换到第一个线程开始运行(如 main 线程),并打开全局中断。
在启动流程中设计到一些除了移植之外的一些rtthread知识点,后续我们会在分析rtthread源码的时候和大家一起讨论,我们这期只讨论移植。
好了,溜了溜了!!! 不继续码字了,腰酸背痛,浪去了。下周见!!!
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)