4. 中断系统基础

在 RTOS 环境中,中断是系统对外部事件做出快速响应的核心机制。理解中断系统的组成,是分析实时性能、定位抖动来源、优化响应时间的前提。本节从硬件与内核协同的角度,梳理中断源、中断向量表、中断优先级、中断嵌套,以及中断延迟与响应时间的构成。

一、中断源:事件的起点

中断源是能够触发中断请求的硬件或软件事件。按来源可分为外部中断与内部中断:外部中断来自 GPIO 电平变化、定时器溢出、串口收发、ADC 转换完成、DMA 传输结束等外设;内部中断则来自软件触发(如 SVC、PendSV)、异常(除零、总线错误)以及内核自身的系统节拍。

在 RTOS 中,中断源通常被抽象为“中断服务程序 + 事件通知”的组合。ISR 只做最紧急的硬件处理,然后通过信号量、消息队列或任务通知唤醒对应任务,把耗时逻辑交给任务上下文完成。这种“上半部/下半部”划分,是控制中断延迟的关键设计。

判断一个中断源是否适合直接唤醒任务,关键看它的处理时间是否会影响其他中断的响应。若 ISR 超过几十微秒,通常应拆分。

二、中断向量表:从异常号到入口地址

中断向量表是一张存放中断入口地址的表格,位于存储器固定位置(如 Cortex-M 的 0x0000_0000 或重映射后的地址)。每个中断源对应一个向量号,CPU 收到中断后,用向量号索引表格,跳转到对应 ISR。向量表通常包含初始栈指针、复位、NMI、HardFault、SysTick、以及各外设中断入口。

在 RTOS 移植中,向量表常被重定位到 RAM 或 Flash 的特定区域,以便动态注册 ISR。若向量表配置错误,会出现“中断触发后跑飞”或“进入 HardFault”的典型故障。

三、中断优先级与嵌套

中断优先级决定多个中断同时到达时谁先被响应,以及高优先级中断能否打断正在执行的低优先级 ISR。Cortex-M 使用 NVIC 管理优先级,数值越小优先级越高。优先级分为抢占优先级和子优先级:抢占优先级决定能否嵌套,子优先级决定同抢占级下的排队顺序。

中断嵌套允许高优先级中断打断低优先级 ISR,从而缩短高实时事件的响应时间。但嵌套层数过深会增大栈消耗,并可能引发优先级反转或栈溢出。RTOS 中通常将内核调度相关的 PendSV、SysTick 设为最低优先级,确保它们不会打断外设 ISR。

中断系统组成与响应时间链路 中断源 GPIO / 定时器 串口 / ADC / DMA 软件触发 / 异常 中断向量表 向量号 → 入口地址 复位 / NMI / HardFault SysTick / 外设 ISR NVIC 优先级 抢占优先级 子优先级 嵌套使能 CPU 内核 取向量 / 压栈 执行 ISR 返回任务 中断延迟与响应时间组成 事件发生 中断请求 开始响应 ISR 执行 返回任务 中断延迟 响应时间 ISR 处理 恢复上下文 中断嵌套示意 低优先级 ISR 高优先级 ISR 低优先级 ISR 继续 高优先级中断可打断低优先级 ISR,嵌套深度受栈空间与优先级配置约束。

四、中断延迟与响应时间的组成

中断延迟通常指“事件发生”到“ISR 第一条指令执行”之间的时间;响应时间则更宽泛,包含从中断请求到任务真正处理完事件的全过程。其组成可拆解为:

  • 硬件识别延迟:中断信号同步、优先级仲裁、取向量所需时钟周期。
  • 压栈与上下文保存:Cortex-M 自动压栈 R0-R3、R12、LR、PC、xPSR,通常 12 个周期左右。
  • 内核关中断时间:RTOS 临界区、调度器锁、驱动中的关中断操作会直接阻塞响应。
  • ISR 执行时间:与代码路径、分支预测、Flash 等待周期、Cache 命中率相关。
  • 任务唤醒与调度延迟:ISR 发送信号量后,任务何时被调度取决于当前就绪任务优先级与调度器状态。
组成环节 典型量级 主要影响因素 优化方向
硬件识别与仲裁 几个到十几个周期 NVIC 优先级、总线频率 提高主频、合理分组
自动压栈 约 12 周期 内核架构、FPU 是否使能 避免不必要的 FPU 上下文
关中断临界区 数微秒到数十微秒 RTOS API、驱动实现 缩短临界区、使用无锁队列
ISR 执行 数微秒到数百微秒 代码复杂度、Cache、Flash 等待 上半部精简、下半部下沉
任务调度 数微秒到数十微秒 就绪表、优先级、调度器 提高任务优先级、减少阻塞

五、案例:串口接收中断的响应链路

以 STM32 + FreeRTOS 的串口接收为例,典型链路如下:

USART1_IRQHandler:
  1. 读取 SR 与 DR,清除中断标志
  2. 将数据写入环形缓冲区
  3. 若缓冲区达到阈值,调用 xSemaphoreGiveFromISR()
  4. 触发 PendSV,请求任务切换

任务侧:
  xSemaphoreTake( rxSem, portMAX_DELAY );
  从环形缓冲区取数据并解析协议

若把协议解析直接放在 ISR 中,ISR 执行时间会从几微秒膨胀到几百微秒,导致其他中断被长时间阻塞。正确做法是 ISR 只搬运数据并通知任务,解析交给任务完成。

常见误区:把所有外设中断都设为最高抢占优先级。这会导致低优先级中断长期得不到响应,甚至看门狗复位。应按实时性要求分级,内核调度相关中断保持最低。

六、复盘:如何量化与优化

要优化中断响应,先要测量。可用 GPIO 翻转配合示波器,在 ISR 入口和出口各翻转一次,测量 ISR 执行时间;在事件发生处翻转,测量中断延迟。若延迟超标,按以下顺序排查:

  1. 检查是否有长临界区或关中断操作,定位到具体函数。
  2. 检查中断优先级分组是否合理,是否存在高优先级中断被低优先级长时间阻塞。
  3. 检查 ISR 是否过长,是否调用了非 ISR 安全的 RTOS API。
  4. 检查任务侧优先级与阻塞时间,确认唤醒后能及时调度。
  5. 检查 Flash 等待周期与 Cache 配置,必要时将 ISR 放入 RAM 执行。

中断系统的本质是“硬件事件 → 向量跳转 → 优先级仲裁 → ISR 执行 → 任务唤醒”的链路。理解每一段的耗时与约束,才能在 RTOS 中把实时性能从“感觉还行”变成“可测量、可优化、可保证”。