3. RTOS基础回顾
在 Linux 与 RTOS 多系统协同开发中,Linux 侧通常负责复杂协议栈、文件系统与人机交互,而 RTOS 侧承担硬实时控制、采样与执行动作。若对 RTOS 的任务调度、同步通信、中断与内存机制理解不深,就会出现“Linux 明明发了指令,RTOS 却延迟抖动很大”或“共享数据偶发错乱”的问题。本节把 RTOS 的关键机制串成一条可验证的知识链,为后续核间通信与协同调度打基础。
一、任务调度:优先级、就绪态与抢占
RTOS 调度的核心不是“公平”,而是“可预测”。任务通常处于运行、就绪、阻塞、挂起等状态,调度器在 SysTick 或 PendSV 触发的节拍上选择最高优先级就绪任务运行。以 FreeRTOS 为例,抢占式调度下高优先级任务一旦就绪,可立即打断低优先级任务;同优先级任务可按时间片轮转。关键参数包括任务优先级、栈深度、阻塞时间与节拍频率。
/* FreeRTOS 任务创建示例:优先级与栈深度的选择直接影响实时性 */
xTaskCreate(vControlTask, "ctrl", 512, NULL, 5, &xCtrlHandle);
xTaskCreate(vCommTask, "comm", 1024, NULL, 3, &xCommHandle);
xTaskCreate(vLogTask, "log", 2048, NULL, 1, &xLogHandle);
/* 节拍频率决定时间片粒度,也影响功耗与中断负载 */
#define configTICK_RATE_HZ 1000 /* 1 ms 一个 tick */
优先级分配要遵循“速率单调”思想:周期越短、截止时间越紧的任务优先级越高。若把日志、打印等非实时任务设为高优先级,会直接破坏控制环路的确定性。
二、同步与通信:信号量、互斥量与队列
任务之间需要交换数据或互斥访问外设。二值信号量常用于任务与中断的同步,计数信号量用于资源计数,互斥量(Mutex)带优先级继承,适合保护共享资源,队列则用于传递结构化数据。选择错误会引入优先级反转或数据覆盖。
| 机制 | 典型用途 | 是否可从中断调用 | 风险点 |
|---|---|---|---|
| 二值信号量 | 中断通知任务处理 | 是(FromISR) | 重复 give 导致计数丢失 |
| 计数信号量 | 缓冲区槽位计数 | 是 | 计数与真实资源不一致 |
| 互斥量 | 保护共享外设/变量 | 否 | 在中断中使用会断言失败 |
| 消息队列 | 任务间传递采样值 | 是 | 队列满时阻塞或丢包 |
| 事件组 | 多条件同时满足再唤醒 | 是 | 位定义冲突、未清标志 |
三、中断管理:上半部与下半部
RTOS 中断处理遵循“快进快出”。ISR 中只做清标志、取数据、发信号量等短操作,把耗时处理交给任务(下半部)。中断优先级数值在不同内核中含义相反:Cortex-M 中数值越小优先级越高,且 RTOS 可管理的中断优先级不能高于 configMAX_SYSCALL_INTERRUPT_PRIORITY,否则在 ISR 中调用 RTOS API 会破坏内核临界区。
void EXTI0_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line0);
xSemaphoreGiveFromISR(xAdcSem, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
常见误区是把串口解析、浮点运算放进 ISR,导致中断响应时间被拉长,Linux 侧看到的通信抖动随之增大。
四、内存管理与实时性指标
RTOS 内存管理强调确定性。动态堆分配(malloc)可能产生碎片和不确定耗时,实时路径上更推荐静态分配、内存池或固定块分配。FreeRTOS 提供 heap_1 到 heap_5 多种策略:heap_1 只分配不释放,heap_4 支持合并相邻空闲块,heap_5 支持多内存区域。
衡量实时性常用指标包括:中断延迟(从中断发生到 ISR 第一条指令)、任务切换时间、最坏执行时间(WCET)、截止时间错过率与抖动(Jitter)。在协同系统中,还要关注跨核通信的端到端延迟。
五、案例与复盘:采样控制环路的抖动治理
某设备用 Linux 做界面与网络,RTOS 做 1 kHz 电流环。现场出现电机噪声增大,示波器测得控制周期抖动约 300 μs。排查发现:日志任务优先级被设为 4,与控制任务相同,且日志任务中调用了 printf 与动态内存;同时串口 ISR 中做了整帧解析。整改措施如下:
- 日志任务降为优先级 1,并改用环形缓冲区与 DMA 发送。
- 串口 ISR 只把字节写入环形缓冲区并 give 信号量,解析移到任务。
- 控制任务栈改为静态分配,关闭该任务路径上的 malloc。
- 把 configMAX_SYSCALL_INTERRUPT_PRIORITY 与串口中断优先级重新核对,确保 ISR 可安全调用 FromISR API。
整改后抖动降到约 40 μs,满足控制要求。复盘结论是:实时性不是单点优化,而是“中断—调度—同步—内存”全链路的确定性设计。
掌握以上机制后,后续讨论 Linux 与 RTOS 的核间通信、共享内存与协同调度时,才能准确判断延迟来自哪一层,并给出可测量的优化手段。