2. RTOS基础回顾

在进入驱动框架与设备模型之前,有必要把 RTOS 的几个基础概念重新梳理一遍。驱动代码并不是孤立运行的,它始终处在“任务—调度器—内核对象—中断”构成的运行环境中。理解这些机制,才能解释为什么同一个外设驱动在裸机下工作正常,移植到 RTOS 后却出现丢数据、响应抖动或死锁。

一、实时性的本质:确定性优先于绝对速度

实时操作系统强调的不是“跑得快”,而是“响应时间可预测”。衡量指标通常包括中断延迟、任务切换时间和最坏情况执行时间(WCET)。硬实时系统要求所有关键任务都在截止时间内完成,一旦超时即视为系统失败;软实时则允许偶发超时,只降低体验。

对驱动开发而言,这意味着驱动中的临界区、阻塞等待和中断处理都必须有明确的时间上界。例如在中断服务程序(ISR)中执行长循环、动态内存分配或打印日志,都会破坏确定性,是典型的反面写法。

实时性 = 正确性 + 时间约束。驱动若无法给出最坏响应时间,就不能声称满足实时要求。

二、任务调度:优先级与状态迁移

RTOS 通常采用基于优先级的抢占式调度。每个任务有独立栈空间和优先级,调度器始终让就绪态中优先级最高的任务运行。任务在运行、就绪、阻塞、挂起之间迁移,驱动常通过阻塞态等待信号量或消息,从而让出 CPU。

常见调度策略包括:抢占式优先级调度、时间片轮转(同优先级)、以及协作式调度。多数 RTOS 还支持优先级继承,用于缓解优先级反转问题。

RTOS 任务状态迁移与驱动交互 就绪 Ready 运行 Running 阻塞 Blocked 挂起 Suspended 被调度选中 等待信号量/消息 事件到达 vTaskSuspend 恢复后重新就绪 驱动典型路径:ISR 释放信号量 → 阻塞中的驱动任务转为就绪 → 调度器按优先级切换 → 任务读取硬件数据。 关键约束:ISR 只做最短处理,耗时操作交给任务;阻塞等待必须有超时,避免永久挂起。

三、同步与通信机制

RTOS 提供多种内核对象用于任务间同步与数据传递,驱动开发中最常用的是信号量、互斥量、消息队列和事件标志组。

机制 典型用途 驱动场景 注意事项
二值信号量 任务与 ISR 同步 中断通知数据到达 不可用于互斥,无优先级继承
互斥量 保护共享资源 多任务访问同一寄存器组 支持优先级继承,不可在 ISR 使用
消息队列 传递数据块 串口接收帧、传感器采样值 注意队列深度与拷贝开销
事件标志组 多条件等待 等待“数据就绪 + 校验通过” 适合状态组合,不适合传数据

下面是一段典型的驱动任务与 ISR 协作代码,使用二值信号量把中断事件传递给任务:

static SemaphoreHandle_t xRxSem;

void UART_ISR(void) {
    BaseType_t xWoken = pdFALSE;
    /* 仅做最短处理:清中断标志、通知任务 */
    UART_ClearIRQ();
    xSemaphoreGiveFromISR(xRxSem, &xWoken);
    portYIELD_FROM_ISR(xWoken);
}

void UART_RxTask(void *pv) {
    for (;;) {
        if (xSemaphoreTake(xRxSem, pdMS_TO_TICKS(100)) == pdTRUE) {
            uint8_t data = UART_ReadByte();
            /* 解析、入队或上报 */
        } else {
            /* 超时处理:检查链路状态 */
        }
    }
}

四、对驱动开发的直接影响

  • 中断上下文的限制:ISR 中不能调用可能阻塞的 API,必须使用带 FromISR 后缀的接口,并正确传递唤醒标志。
  • 阻塞与超时:驱动等待硬件事件时应设置合理超时,避免任务永久阻塞导致系统失去响应。
  • 优先级设计:驱动任务优先级需与实时要求匹配,过高会挤占控制任务,过低会导致数据溢出。
  • 共享资源保护:多个任务访问同一外设时,必须用互斥量或临界区保护,防止寄存器配置被交叉破坏。
  • 内存与栈:驱动任务栈要按最坏调用深度估算,ISR 使用独立栈或系统栈,需关注溢出风险。
在驱动框架中,通常会把“中断处理”和“任务处理”分离:ISR 只负责通知,任务负责解析与业务。这种上下半部结构是 RTOS 驱动的基本范式。

五、常见误区与复盘

误区一:在 ISR 中调用普通信号量释放函数。正确做法是使用 xSemaphoreGiveFromISR,否则可能破坏内核状态。

误区二:用二值信号量做互斥。二值信号量没有优先级继承,容易引发优先级反转,应使用互斥量。

误区三:忽略中断优先级与内核临界区的关系。某些 RTOS 要求中断优先级数值高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 才能调用内核 API,配置错误会导致偶发死机。

驱动调试中若出现“偶发丢中断”或“任务卡死”,优先检查:ISR 是否过长、信号量是否配对、阻塞是否带超时、共享资源是否加锁。

把上述概念落实到驱动代码中,核心就是三句话:中断要短,等待要限时,共享要加锁。理解任务调度与同步机制,是后续学习驱动框架分层、设备模型和统一接口的前提。