- smb/resources/embedded/rtthread/RTT启动相关设置_设备驱动_应用程序启动相关实践.md
- smb/resources/embedded/rtthread/RTT驱动使用简介.md
- smb/resources/embedded/rtthread/RTT内存管理_关于堆.md
RT-Thread 实践笔记:启动流程、驱动分层与内存
自动初始化机制
RT-Thread 的组件自动初始化通过 INIT_*_EXPORT 系列宏完成,初始化顺序如下:
rti_start --> 0
BOARD_EXPORT --> 1
rti_board_end --> 1.end
DEVICE_EXPORT --> 2
COMPONENT_EXPORT --> 3
FS_EXPORT --> 4
ENV_EXPORT --> 5
APP_EXPORT --> 6
rti_end --> 6.end
其中 1.end 之前的部分在 rt_components_board_init() 中调用;2 ~ 6.end 的部分由 rt_components_init() 调用,最终是在 main 线程(main_thread_entry)中执行的。使用该机制时,驱动或组件的初始化函数必须用 INIT_BOARD_EXPORT(fn)、INIT_DEVICE_EXPORT(fn)、INIT_APP_EXPORT(fn) 等宏导出。
启动流程
rtthread_startup()rt_hw_board_init():系统启动后第一个调用的初始化函数,需要先初始化好串口,方便调试rt_components_board_init()(即INIT_BOARD_EXPORT导出的函数)- 显示版本号、初始化 timer、调度器
- 创建 main 线程、定时器线程(软件定时器)、idle 线程
- 启动调度器
- main 线程中执行
rt_components_init():INIT_PREV_EXPORT→INIT_DEVICE_EXPORT→INIT_COMPONENT_EXPORT→INIT_ENV_EXPORT→INIT_APP_EXPORT
编程实践:各 EXPORT 层级放什么
- 硬件底层驱动都使用
INIT_BOARD_EXPORT导出,完成所有硬件外设的初始化 PREV EXPORT:看具体情况,有些操作需要在设备驱动之前完成- 设备驱动使用
INIT_DEVICE_EXPORT,某个设备可能使用多个硬件外设 - COMPONENT 适合给中间件使用,例如 uORB 这种通讯组件
- ENV 初始化系统运行环境相关的,看具体情况
- APP EXPORT 放系统应用,创建具体的应用任务
驱动分层
- 硬件底层驱动(Drivers)
- 设备驱动(Device Drivers)
应用层最好直接使用设备驱动,也可以直接调用设备底层驱动;但直接使用底层驱动的应用程序不具备可移植性,只有比较特殊的需求才这么做。
两个实用驱动组件
| 组件 | 说明 |
|---|---|
| hwtimer | 计时器,用来做精准倒计时;驱动主要解决定时器溢出的问题 |
| cputime | 给系统一个高精度时钟,用来计时;需要一个 hwtimer 支持 |
内存笔记:堆、C 语言的栈与线程的栈
堆的末尾是 SRAM END,所以堆其实还挺大的。
这里需要区分 C 语言的栈和线程的栈:
- C 语言的栈更底层,是函数调用时使用的内存空间,比如局部变量都会使用栈空间
- gd32 和 stm32 工程里默认栈给了 0x400,也就是 1K 的栈空间
- 线程切换时,会把栈空间里使用的数据全部放到线程栈中,然后再进行切换
遗留问题:可不可以这么说——一个线程的栈永远不会超过 C 语言的栈?