写在前面:

      作者以前在工作中使用过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的内核源码目录如下:

a6b2514fc4bbdf74a3a92236e54c683c.png

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

a60e3d6205fb52b97e9259ab0199ed52.png

bsp:板级支持包

components:RT-Thread组件

doc:此版本内核的一些官方说明文档

include:存放的相关头文件

libcpu:与处理器相关的接口文件

src:RT-Thread的内核源码

AUTHORS、ChangeLog.md、LICENSE、README.md:这四个文件是一些作者说明、代码迭代说明等。

在移植以前,建议大家将官方doc对这一版内核的说明详细浏览一遍),相关文档如下。

15dbba60e54058ecafa4d4ff1b9259d8.png

作者把这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 。

5f6a8cf79e00f6e1104368bd1bb03d86.png

接下来打开准备好的基础裸机工程,新建rtthread文件夹,在rthread文件夹分组下面添加以下代码文件:

• 添加工程下 rtthread/src/ 文件夹中所有文件到工程;

• 添加工程下 rtthread/libcpu/ 文件夹中相应内核的 CPU 移植文件及上下文    切换文件:cpuport.c 以及 context_rvds.S ;

• 添加 rtthread/ 文件夹下的 board.

5d88395df7e722d12e86289c7b214e10.png

rtthread  nano源码与配置文件

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

6b8a5ee2faf641091536f4b905b9968e.png

RT-Thread  kernel文件:

95176e717acabcd409c84de29474f822.png

板级配置代码:

b3165e24982e18a935c8c824b3191266.png

    3.2 添加头文件路径

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

7b4335b85a41e0e0c9945993fda38911.png

4、适配RT-Thread Nano到自己的硬件开发平台上

    4.1 中断与异常处理

        异常处理函数HardFault_Handler()和悬挂处理函数PendSV_Handler(),

这两个函数会由rtthread接管并实现,所以我们要先删除工程里面的这两个函数,以便避免重复定义的错误。

178b2f92014b7937ea6e265c74b8fe9a.png

d2cd1bce1da2bb6e5c647fa146ae15b3.png

找到上面这两个函数,删掉。

    4.2 系统时钟配置

        其实在哪里实现这个都可以,但是为了和官方统一,也为了方便管理,我们在board.c中实现《系统时钟配置》和《OS Tick配置》。

        系统时钟配置:为MCU内核、外设提供工作时钟。

        OS Tick:为操作系统提供心跳/节拍。

4f429e113f8901265b76988bc9b3cabc.png

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

34213cd8cccc8c970fa4c69f3622979b.png

    4.3 内存堆初始化

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

f8f395ed30840ea7c7975e153f50224e.png

这和系统内存堆大小配置相关,默认不开启。系统内存堆的初始化是在

rt_hw_board_init( )函数中完成的,是否启用,取决于宏RT_USING_HEAP是否开启。开启系统堆就可以正常使用动态内存功能,列入:rt_malloc、rt_free和各种系统动态创建对象的API函数。

84dbe05676936d4f639f7e08ade16cda.png

从上图函数原型可知,内存堆初始化函数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、编写应用程序

    当完成上述几点移植后,我们就可以编写我们的应用程序了。

066022336389956757e446cf8131b1e3.png

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

f12ea14d7409aaaaaee7290977b53bfd.png

        (官方说明摘要): RT-Thread 启动代码统一入口为 rtthread_startup() ,芯片启动文件在完成必要工作(如初始化时钟、配置中断向量表、初始化堆栈等)后,最终会在程序跳转时,跳转至 RT-Thread 的启动入口中。

RT-Thread 的启动流程如下:

1. 全局关中断,初始化与系统相关的硬件。

2. 打印系统版本信息,初始化系统内核对象(如定时器、调度器)。

3. 初始化用户 main 线程(同时会初始化线程栈),在 main 线程中对各类模块依次进行初始化。

4. 初始化软件定时器线程、初始化空闲线程。

5. 启动调度器,系统切换到第一个线程开始运行(如 main 线程),并打开全局中断。

       在启动流程中设计到一些除了移植之外的一些rtthread知识点,后续我们会在分析rtthread源码的时候和大家一起讨论,我们这期只讨论移植。

       好了,溜了溜了!!! 不继续码字了,腰酸背痛,浪去了。下周见!!!

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐