Rtthread源码
个人使用体验
之前使用过UCOSII,UCOSIII,FreeRTOS,还有别人自己写的RTOS等等,功能不外乎:多任务,各种任务通讯机制等。UCOS收费所以不用,"自己写的RTOS"我总感觉其中会有问题,一个人维护的RTOS怎么比得上一群人维护的RTOS?于是也不用了。后面公司常用FreeRTOS,主要是免费,于是就常用这个了,但是感觉很普通。直到听指导老师推荐,去接触了RT-Tthread!国人开发,免费!
RT-Thread的内核跟其他的RTOS差不多,但是他多了自己的特点,组件,软件包。
基于这个系统,可以把一个产品开发大致分为:驱动开发,应用层代码开发。
应用层代码开发人员:基于抽象的驱动接口用同一套驱动代码开发应用层程序就行。
驱动开发开发人员:关心硬件如何适配入内核系统。
这种方式,如果换一个硬件平台,只需要硬件开发人员改底层接口就行,应用层程序不会变。当然要完全做到还是比较困难,很多问题会产生。但是RT-thread已经把能这样的这样做了。
也是基于这种方式,官网出了很多的软件包。因为他可以基于抽象的硬件接口开发驱动。
这个系统非常适用于STM32系列单片机。于是我后面做产品经常会是这样的。
如果用主控STM32
- 内存小:还是裸机程序运行。
- 内存大的+外设多的:直接上RT-Tthread。而且在做功能板的时候,我会配合已有的软件包来做,这样就懒得后面自己折腾驱动了!!!
== 下面是我学习中记录,一些注意事项,指令记录。以及给自己一些映像==
使用版本
计划后续持续使用以下版本
版本选择
RT-Thread 的版本 / 分支有以下几种可供选择:
开发分支(master 主分支)、长期支持分支(lts-v3.1.x 分支)、发布版本(release),推荐用户使用已发布的版本。
RT-thread我的开发风格
[RT-Thread开发笔记] 第1章 RT-Thread 开发环境搭建 (Keil+env) - 知乎 (zhihu.com)
RT Thread学习之使用Env工具生成MDK工程_rtthread studio 能否导出成keil-CSDN博客
env 工具使用手册 - 《RT-Thread工具手册》 - 书栈网 · BookStack
scons --target=mdk5 生成mdk5
scons 编译工程
scons --dist 生成个工程
menuconfig 图形配置
pkgs —upgrade 升级本地包内容
pkgs --update 下载包并加入到工程
【注1】软件更新
**下载** :如果软件包在本地已被选中,但是未下载,此时输入:pkgs --update ,该软件包自动下载;
**更新** :如果选中的软件包在服务器端有更新,并且版本号选择的是 latest 。此时输入: pkgs --update ,该软件包将会在本地进行更新;
**删除** :某个软件包如果无需使用,需要先在 menuconfig 中取消其的选中状态,然后再执行: pkgs --update 。此时本地已下载但未被选中的软件包将会被删除。
- **下载** :如果软件包在本地已被选中,但是未下载,此时输入:`pkgs --update` ,该软件包自动下载;
- **更新** :如果选中的软件包在服务器端有更新,并且版本号选择的是 **latest** 。此时输入: `pkgs --update` ,该软件包将会在本地进行更新;
- **删除** :某个软件包如果无需使用,需要先在 menuconfig 中取消其的选中状态,然后再执行: `pkgs --update` 。此时本地已下载但未被选中的软件包将会被删除。
Kconfig
顶层Kconfig文件在文件中通过source语句显示地调用各子目录下的Kconfig文件
SCons
设置编译器:
set RTT_CC=keil
set RTT_EXEC_PATH=C:/Keilv5
set RTT_CC=gcc
set RTT_EXEC_PATH=D:\software\RaspberryPi-Pico\gcc\2020-q4-major\bin
scons --dist
搭建项目框架,使用此命令会在 BSP 目录下生成 dist 目录,这便是开发项目的目录结构,包含了RT-Thread源码及BSP相关工程,不相关的BSP文件夹及libcpu都会被移除,并且可以随意拷贝此工程到任何目录下使用
3.3.1 生成 Keil-MDK / IAR 工程
如果使用 MDK/IAR 来进行项目开发,在生成 MDK 或者 IAR 工程前,需要检查 rtconfig.py 文件中 EXEC_PATH
变量所保存的对应 IDE 的安装路径是否正确:
- 当修改了 rtconfig.h 打开或者关闭某些组件时,需要使用以下命令中的其中一种重新生成对应的定制化的工程,然后在 MDK/IAR 进行编译下载:
scons --target=iar
scons --target=mdk4
scons --target=mdk5
源码结构
外设配置总结
堆栈解释
二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
自动初始化宏接口:
初始化顺序 | 宏接口 | 描述 |
---|---|---|
1 | INIT_BOARD_EXPORT(fn) | 非常早期的初始化,此时调度器还未启动 |
2 | INIT_PREV_EXPORT(fn) | 主要是用于纯软件的初始化、没有太多依赖的函数 |
3 | INIT_DEVICE_EXPORT(fn) | 外设驱动初始化相关,比如网卡设备 |
4 | INIT_COMPONENT_EXPORT(fn) | 组件初始化,比如文件系统或者 LWIP |
5 | INIT_ENV_EXPORT(fn) | 系统环境初始化,比如挂载文件系统 |
6 | INIT_APP_EXPORT(fn) | 应用初始化,比如 GUI 应用 |
LIBC介绍:
NetDev网卡:
netdev(network interface device),即网络接口设备,又称网卡。每一个用于网络连接的设备都可以注册成网卡,为了适配更多的种类的网卡,避免系统中对单一网卡的依赖,RT-Thread 系统提供了 netdev 组件用于网卡管理和控制。
netdev 组件主要作用是解决设备多网卡连接时网络连接问题,用于统一管理各个网卡信息与网络连接状态,并且提供统一的网卡调试命令接口。 其主要功能特点如下所示:
- 抽象网卡概念,每个网络连接设备可注册唯一网卡。
- 提供多种网络连接信息查询,方便用户实时获取当前网卡网络状态;
- 建立网卡列表和默认网卡,可用于网络连接的切换;
- 提供多种网卡操作接口(设置 IP、DNS 服务器地址,设置网卡状态等);
- 统一管理网卡调试命令(ping、ifconfig、netstat、dns 等命令);
网卡状态
netdev 组件提供对网卡网络状态的管理和控制,其类型主要包括下面四种:up/down、link_up/link_down、internet_up/internet_down、dhcp_enable/dhcp_disable。
- up/down: 底层网卡初始化完成之后置为 up 状态,用于判断网卡开启还是禁用。
- link_up/link_down: 用于判断网卡设备是否具有有效的链路连接,连接后可以与其他网络设备进行通信。该状态一般由网卡底层驱动设置。
- internet_up/internet_down: 用于判断设备是否连接到因特网,接入后可以与外网设备进行通信。
- dhcp_enable/dhcp_disable: 用于判断当前网卡设备是否开启 DHCP 功能支持。
其中up/down
状态以及 dhcp_enable/dhcp_disable
状态可以通过 netdev 组件提供的接口设置,可以在应用层控制。其他状态是由网卡底层驱动或者 netdev 组件根据当前网卡网络连接情况自动设置。
ifconfig w0 192.168.12.93 192.168.10.1 255.255.0.0 /* 设置指定网卡 IP 地址*/
网卡操作相关头文件
#include <arpa/inet.h>
#include <netdev.h> /* 当需要网卡操作是,需要包含这两个头文件 */
SAL套接字抽象层
- 该组件完成对不同网络协议栈或网络实现接口的抽象并对上层提供一组标准的 BSD Socket API,这样开发者只需要关心和使用网络应用层提供的网络接口,而无需关心底层具体网络协议栈类型和实现
目前 SAL 组件支持的协议栈或网络实现类型有:lwIP 协议栈、AT Socket 协议栈、WIZnet 硬件 TCP/IP 协议栈。
Ulog使用:
日志的定义:日志是将软件运行的状态、过程等信息,输出到不同的介质中(例如:文件、控制台、显示屏等),并进行显示和保存。为软件调试、维护过程中的问题追溯、性能分析、系统监控、故障预警等功能,提供参考依据。可以说,日志的使用,几乎占用的软件生命周期的至少 80% 的时间。
- 日志输出的后端多样化,可支持例如:串口、网络,文件、闪存等后端形式。
- 日志输出被设计为线程安全的方式,并支持异步输出模式。
- 日志系统高可靠,在中断 ISR 、Hardfault 等复杂环境下依旧可用。
- 日志支持运行期 / 编译期设置输出级别。
- 日志内容支持按关键词及标签方式进行全局过滤。
- API 和日志格式可兼容 linux syslog。
- 支持以 hex 格式 dump 调试数据到日志中。
- 兼容 rtdbg (RTT 早期的日志头文件)及 EasyLogger 的日志输出 API。
级别 | 名称 | 描述 |
---|---|---|
LOG_LVL_ASSERT | 断言 | 发生无法处理、致命性的的错误,以至于系统无法继续运行的断言日志 |
LOG_LVL_ERROR | 错误 | 发生严重的、不可修复的错误时输出的日志属于错误级别日志 |
LOG_LVL_WARNING | 警告 | 出现一些不太重要的、具有可修复性的错误时,会输出这些警告日志 |
LOG_LVL_INFO | 信息 | 给本模块上层使用人员查看的重要提示信息日志,例如:初始化成功,当前工作状态等。该级别日志一般在量产时依旧保留 |
LOG_LVL_DBG | 调试 | 给本模块开发人员查看的调试日志,该级别日志一般在量产时FAL关闭 |
![]() |
FAL组件
- 支持静态可配置的分区表,并可关联多个 Flash 设备;
- 分区表支持 自动装载 。避免在多固件项目,分区表被多次定义的问题;
- 代码精简,对操作系统 无依赖 ,可运行于裸机平台,比如对资源有一定要求的 Bootloader;
- 统一的操作接口。保证了文件系统、OTA、NVM(例如:EasyFlash) 等对 Flash 有一定依赖的组件,底层 Flash 驱动的可重用性;
- 自带基于 Finsh/MSH 的测试命令,可以通过 Shell 按字节寻址的方式操作(读写擦) Flash 或分区,方便开发者进行调试、测试;
虚拟文件系统
DFS 是 RT-Thread 提供的虚拟文件系统组件,全称为 Device File System,即设备虚拟文件系统,文件系统的名称使用类似 UNIX 文件、文件夹的风格,目录结构如下图所示:
POSIX 接口层
POSIX 表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写 POSIX),POSIX 标准定义了操作系统应该为应用程序提供的接口标准,是 IEEE 为要在各种 UNIX 操作系统上运行的软件而定义的一系列 API 标准的总称。
• DevFS 即设备文件系统,在 RT-Thread 操作系统中开启该功能后,可以将系统中的设备在 /dev 文件夹下虚拟成文件,使得设备可以按照文件的操作方式使用 read、write 等接口进行操作。
更多配置
FatFs 本身支持非常多的配置选项,配置非常灵活。下面文件为 FatFs 的配置文件,可以修改这个文件来定制 FatFs。
components/dfs/filesystems/elmfat/ffconf.h
挂载管理
文件系统的初始化过程一般分为以下几个步骤:
- 初始化 DFS 组件。
- 初始化具体类型的文件系统。
- 在存储器上创建块设备。
- 格式化块设备。
- 挂载块设备到 DFS 目录中。
- 当文件系统不再使用,可以将它卸载。
取值 | 文件系统类型 |
---|---|
elm | elm-FAT 文件系统 |
jffs2 | jffs2 日志闪存文件系统 |
nfs | NFS 网络文件系统 |
ram | RamFS 文件系统 |
rom | RomFS 只读文件系统 |
uffs | uffs 文件系统 |
lfs | littlefs 文件系统 |
USB
USB基础知识
USB按接口类型分
控制器/主机(controller/host)
设备(peripheral)
OTG(on-the-go),通过id线确定作为主机还是作为设备
按照USB速度分
低速(low speed)
全速(full speed)
高速(high speed)
USB接口一般是4根线,VCC GND DM(D-) DP(D+)
低速设备:在DM线上接入上拉
全速设备:在DP线上接入上拉
高速设备:在DP线上接入上拉,在主机对设备进行复位后进一步的确认
FLASH-SFUD:
SFUD 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
sfud/port/sfud_port.c:移植关注
各种外设配置问题
W5500+WIZnet
W25Q32
在潘多拉上使用SFUD操作Flash (rt-thread.org)
1.SPI初始化,
2.挂载总线,
3.将总线SPI抽象成块(注意块名称要在stdu_flash_def.h”中找。
注意事项
1. Flash 先擦后写
写入之前请先擦除,这是 flash 特性决定的,因为 flash 的编程原理就是只能将 1 写为 0,而不能将 0 写为 1。擦除动作就是相应的页 / 块的所有位变为 1(所有字节均为 0xFF),所以不擦除直接写入会有问题。
2. Flash 按页 / 块擦除
Flash 页大小一般是 4K、8K、16K 等,一个块也可能有 192、256、384、512 个页。Flash 按页擦除、按块擦除也是 flash 的特性之一。
在上面步骤(2)中使用了 sf erase 命令进行擦除。虽然 sf erase 0 10
命令的意思是从 0 地址开始擦除 10 个字节,但是该 flash 是按照 4K 字节进行擦除的,所以会擦出从 0 开始的 4K 字节。使用读取 sf read 4090 20
命令进行验证,读取从 4090 开始的 20 个字节时,发现从 4096 及之后均未进行擦除,也就是擦除了从 0 开始的 4K 字节。
sf erase 2 10
也是擦除从 0 开始的 4K 字节,而不是从 2 开始的 4K 字节。
flash总结:
- flash写前必须擦除
- flash实际按页,按块擦除。所以如果同一块区域有两个不相关数据块时,都会被擦除!
- Flash 写粒度,可以理解为写分辨率,比如至少一次写入8bit数据
msh >sf write 4094 01 02 03 04 05 06 07 08
Too many args ! We only Use:
sf write 4094 01 02 03 04 05 06 07
Write the sf_cmd flash data success. Start from 0x00000FFE, size is 7.
Write data: 1 2 3 4 5 6 7 .
msh >sf read 0 100
Read the sf_cmd flash data success. Start from 0x00000000, size is 100. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000000] 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 …
[00000010] 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 …
[00000020] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000030] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000040] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000050] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000060] FF FF FF FF …
msh >sf read 4094 100
Read the sf_cmd flash data success. Start from 0x00000FFE, size is 100. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000FFE] 01 02 03 04 05 06 07 FF FF FF FF FF FF FF FF FF …
[0000100E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000101E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000102E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000103E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000104E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000105E] FF FF FF FF …
msh >sf erase 0 100
Erase the sf_cmd flash data success. Start from 0x00000000, size is 100.
msh >sf read 0 100
Read the sf_cmd flash data success. Start from 0x00000000, size is 100. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000000] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000010] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000020] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000030] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000040] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000050] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[00000060] FF FF FF FF …
msh >sf read 4094 100
Read the sf_cmd flash data success. Start from 0x00000FFE, size is 100. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000FFE] FF FF 03 04 05 06 07 FF FF FF FF FF FF FF FF FF …
[0000100E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000101E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000102E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000103E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000104E] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF …
[0000105E] FF FF FF FF