个人一直在做linux底层相关的开发,没有什么实时操作系统rtos的使用经验,学习rtthread主要目的是理解实时操作系统相关的一些基础。理解实时和非实时的核心差别,选择性学习一下部分设计方案。
Real-time operating system:当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统做出快速响应,调度一切可利用的资源完成实时任务,并控制所有实时任务协调一致运行的操作系统。其特点是及时响应和高可靠性。 rtos分硬实时系统(规定的时间内必须完成操作,对操作系统和硬件都有要求)和软实时系统(按照优先级尽可能快完成)。
如:vxworks、uc/oc-ii、FreeRTOS、RT-Thread、RT-Linux(美国墨西哥理工学院开发的基于linux的嵌入式实时操作系统)。
分时操作系统:多用户的通用系统,交互能力更强,将系统处理机时间与内存空间按一定的时间间隔,轮流地切换给各终端用户的程序使用(时间片的概念),由于时间间隔很短,每个用户的感觉就像独占计算机一样,如 windows、Linux;
核心差别在设计目标:分时系统是设计成一个多用户的交互能力更强的通用系统(通用,有效增加资源的使用率),实时系统在于对响应任务及时性和可靠性的更高专用系统(专用,可靠,以被测物体能接受延迟为系统设计依据,不能随便修改);
Linux存在不可抢占调度如 1、中断;2、软中断;3、spinlock类锁 导致响应不能有效预期,同时linux调度策略很复杂 重点在整体性能,并不是优先级高一定优先调度,说明它就不是rtos。
Real Time-Thread:熊谱翔2006 年初发布,因为任务更类似于通用操作系统中的线程,并且这个系统支持基于优先级的抢占式任务调度算法,调度器的时间复杂度是 O(1),所以把它命名为 RT-Thread,即实时线程。广泛应用于智能家居、智慧城市、安防、工控、穿戴等众多行业领域,累计超过6亿台。主要特点:1、体积小,可伸缩、易裁剪最小资源占用 1.2KB RAM 和 2.5KB flash。2、针对物联网场景提供的众多组件和软件包,比如 AT组件、WiFi、蓝牙、LoRa、Sensor、AI 等等,以及针对安全和低功耗的优化,3、代码质量优秀,linux内核风格,增加了小程序、SMP 多核调度、PSA 安全支持等多项的功能。
1、RT-Thread 标准版:全功最常用,由内核层、组件和服务层、IoT 框架层、文件系统、图形库、设备框架等组成。包含完整的中间件组件,具备低功耗、安全、通信协议支持和云端连接能力,是一个完整的 IoT OS。
2、RT-Thread Nano:极简的硬实时内核,功能包括任务管理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。系统资源紧张或是项目功能较简单的场景,比如家电、消费、医疗、工控领域的32位入门级MCU。
3、RT-Thread Smart:高性能混合微内核操作系统,在传统RTOS 和大型操作系统之间。适用带 MMU 的中高端应用的芯片,例如ARM Cortex-A系列芯片、带MMU的RISC-V芯片等。广泛应用于安防、车载、军工、消费电子等领域。
RT-Thread内核系统实现了如多线程及其调度、信号量、邮箱、消息队列、内存管理、定时器等,与其他RTOS如FreeRTOS相比,还具备丰富的中间层组件和大量软件包支持,如下举例:
物联网相关的软件包:Paho MQTT、WebClient、mongoose、WebTerminal 等等。
脚本语言相关的软件包:目前支持 JerryScript、MicroPython。
多媒体相关的软件包:Openmv、mupdf。
工具类软件包:CmBacktrace、EasyFlash、EasyLogger、SystemView。
系统相关的软件包:RTGUI、Persimmon UI、lwext4、partition、SQLite 等等。
外设库与驱动类软件包:RealTek RTL8710BN SDK。
以下均总结至 官方文档,详细了解 建议直接查看文档内容。
时钟节拍OS Tick :系统最小时间单位,如线程的延时、时间片轮转调度和定时器等,一般是1ms–100ms(由RT_TICK_PER_SECOND配置定义,每次1/x秒);节拍实现:中断触发模式的硬件定时器产生,全局变量rt_tick每个节拍加1。节拍获取:通过rt_tick_get()返回当前rt_tick指;定时器:只提供按时钟节拍单位的软件定时器,支持单次触发和循环触发;
线程定义:基本调度单位,每个线程有独立上下文(寄存器变量、堆栈、内存信息等),优先级用于支持调度;分 内核创建的系统线程 和 应用创建的用户线程;调度原则:线程调度器是抢占式,从就绪线程列表中查找最高优先级线程,保证最高优先级的线程能够被运行,最高优先级任务一旦就绪总能得到CPU的使用权。优先级:最大支持 256 个线程优先级 (0~255),数值越小的优先级越高。时间片:线程时间片参数用于优先级相同的就绪态线程调度切换,单位是系统节拍(最高优先级有多个线程就按各自时间片调度)。状态切换:线程5种状态 和 典型切换条件 如下图:
RT-Thread主要有3种同步方式:
(1)信号量semaphore:类似linux相同概念,设置一个信号量初始值,线程获取时减1释放加1,获取时如果为0就不可用线程挂起(也支持无等待方式try)。(2)互斥量mutex:类似linux相同概念,一种特殊的二值信号量(相当于初值1,只有打开关闭状态),当锁保护资源使用;(3)事件集event:有些接近linux等待队列,可做多对多的同步,每个线程可拥有 32 个事件标志,采用一个 32 bit 无符号整型数进行记录。一个线程与多个事件的关系可设置为:其中任意一个事件唤醒线程,或几个事件都到达后才唤醒线程进行后续的处理;同样,事件也可以是多个线程同步多个事件。事件无排队性(多次发送同一事件 ,如未读走等同于只发一次)。
RT-Thread主要有3种线程间通信方式:
(1)邮箱:RT-Thread最基础的通信方式,每一封邮件固定4字节内容(可以传地址)。线程或中断服务例程把邮件发送(可设置非阻塞)到邮箱中,而一个或多个线程可以从邮箱中接收(可设置阻塞)这些邮件并进行处理。邮箱需要创建并通过handle访问,默认先进先出,可以发送紧急类型邮件直接到队列最前;
(2)消息队列:消息队列能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中。其他线程也能够从消息队列中读取相应的消息,而当消息队列是空的时候,可以挂起读取线程。当有新的消息到达时,挂起的线程将被唤醒以接收并处理消息。消息队列是一种异步的通信方式。
(3)信号:信号本质是软中断,用来通知线程发生了异步事件,用做线程之间的异常通知、应急处理。受到信号后线程可以 指定处理函数、或 忽略、或 保留系统的默认值。
RT-Thread应对不同size内存场景方案,针对性地提供了不同的内存分配管理算法。
1)小内存块的分配管理-小内存管理算法:针对系统资源比较少,如小于2MB。初始时它是一块大的内存,需要分配时分割出相匹配的内存块,空闲内存块还回给堆管理系统。每个内存块含一个12字节数据头(magic标识+used是否使用标志+双向指针),通过这个头把使用块与空闲块用双向链表的方式链接起来。释放时会查看相邻的内存块是否空闲,如果空闲就合并成大内存块。
2)大内存块的分配管理-slab 管理算法:系统资源比较丰富,多内存池管理算法的快速算法。RT-Thread 的 slab 分配器是在 DragonFly BSD 创始人 Matthew Dillon 实现的 slab 分配器基础上,针对嵌入式系统优化的内存分配算法。slab 分配器会根据对象的大小分成多个区(zone),也可以看成每类对象有一个内存池,如下图所示(此处不做展开):
3)多内存堆的分配情况-memheap管理算法:适用于系统存在多个内存堆的情况,将多个内存 “粘贴” 在一起,形成一个大的内存堆。首先将多块内存加入 memheap_item 链表进行粘合。当分配内存块时,会先从默认内存堆去分配内存,当分配不到时会查找 memheap_item 链表,尝试从其他的内存堆上分配内存块。
除了上面三种内存堆管理方式(内存堆管理器缺点:分配效率不高,每次都需要查询,容易产生内存碎片),RT-Thread还支持内存池方式,内存池在创建时先向系统申请一大块内存,然后分成同样大小的多个小内存块,小内存块直接通过链表连接起来管理(此概念以比较常见,不展开了)。
中断向量表:是所有中断处理程序的入口,调用rt_hw_interrupt_install让中断服务程序 (handler) 和指定的中断号关联起来;中断嵌套:在允许中断嵌套的情况下,中断服务过程中如果出现高优先级的中断,当前中断服务将被打断以执行高优先级中断,处理完成后被打断的中断才继续执行。中断源管理:通常在 ISR 准备处理某个中断信号之前,需要rt_hw_interrupt_mask先屏蔽该中断源,在 ISR 处理完状态或数据以后,及时的打开之前被屏蔽的中断源。全局中断开关:也称为中断锁,rt_hw_interrupt_disable,通过关闭中断的方式来保证当前线程不会被其他事件打断,也就是当前线程不会被抢占,除非这个线程主动放弃了处理器控制权。
优先级翻转问题:当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被一低优先级线程持有,而这个低优先级线程在运行过程中可能又被其它一些中等优先级的线程抢占,因此造成高优先级线程被许多具有较低优先级的线程阻塞,实时性难以得到保证。RT-Thread通过优先级继承协议解决:提高某个占有某种资源的低优先级线程的优先级,使之与所有等待该资源的线程中优先级最高的那个线程的优先级相等,然后执行,而当这个低优先级线程释放该资源时,优先级重新回到初始设定。
实时系统中对时间的要求非常严格:1)分配内存的时间确定。一般内存管理算法是根据需要存储的数据的长度在内存中去寻找一个与这段数据相适应的空闲内存块,然后将数据存储在里面,而寻找这样一个空闲内存块所耗费的时间是不确定的。2)内存分配释放累计碎片问题。嵌入式系统可能要常年不间断工作,相对通用系统碎片要求更高。3)嵌入式系统内存环境差异大,有数十KB也有数M内存。选择适合它们的高效率的内存分配算法,就将变得复杂化。
RT-Thread采用多种方案来解决这些问题,按需求选择,可见前面章节RT-Thread内存管理,总结如下:针对2M内小内存,提供简单的双向链表管理方式(低占用),内存足够使用slab分配,针对多个内存设备提供memheap管理算法让使用者感知到一个连续的内存。同时提供内存池操作,应对频繁的内存申请释放避免碎片产生。
树莓派基础操作和详细环境搭建见我这篇blog:https://blog.csdn.net/runafterhit/article/details/107871554
下载路径来着官网:https://gitee.com/rtthread/rt-thread ,下载的rt-thread-gitee_master分支(看了下这里支持raspi4-64)
├── AUTHORS
├── bsp # 芯片移植相关文件 板级支持包,如raspi2、stm32各类芯片
├── ChangeLog.md
├── components # 组件,包含驱动drivers实现,和如libc、dfs、vmm等实现
├── documentation # 相关文档,如编码规范等
├── examples # 用例
├── include # 对应于可见的头文件
├── Kconfig # 顶层配置文件
├── libcpu # cpu的适配封装
├── LICENSE
├── README.md # 基础介绍readme
├── README_zh.md # 基础介绍readme
├── src # 内核实现源文件,如signal.c、thread.c、slab.c、timer.c、irq.c等
└── tools # RT-Thread 命令构建工具的脚本文件
rt-thread官网指导文档
rt-thread官网:https://www.rt-thread.org/
rt-thread官网API手册:https://www.rt-thread.org/document/api/
rt-thread官网视频:https://www.rt-thread.org/page/video.html
rt-thread应用项目举例:https://club.rt-thread.org/ask/article/2292.html
RT-Thread编程手册(创始人熊谱翔):https://www.bookstack.cn/books/rtthread-manual-doc
ART-Pi(RT-Thread 团队推出的DIY开源硬件):https://art-pi.gitee.io/website/
创始人熊谱翔学习建议:https://www.zhihu.com/question/23147481/answer/136584216
从菜鸟到起飞的 RT-Thread 开发指南:https://blog.csdn.net/lu_embedded/article/details/111714543
用树莓派3b搭建rt-thread开发环境:https://blog.csdn.net/DP29syM41zyGndVF/article/details/104831951