4. 中断系统基础:中断向量、中断优先级、中断嵌套与CPU响应流程

在UART驱动开发中,中断是实现CPU与DMA协同工作的核心机制。中断系统决定了外设(如UART)如何通知CPU数据已就绪、传输完成或发生错误。理解中断向量、优先级、嵌套以及CPU的响应流程,是编写可靠、高效中断服务程序(ISR)的前提。

核心概念速览: 中断向量是ISR的入口地址表;中断优先级决定多个中断同时触发时的响应顺序;中断嵌套允许高优先级中断抢占低优先级中断;CPU响应流程包含中断采样、判优、保存现场、执行ISR、恢复现场五个阶段。

4.1 中断向量:中断服务程序的入口索引

中断向量表(IVT, Interrupt Vector Table)是存储在固定内存地址的一张函数指针表。每个中断源(如UART接收中断、定时器溢出中断)对应表中的一个表项,表项内容为该中断对应的中断服务程序(ISR)的起始地址。

中断源 向量号 向量地址(典型ARM Cortex-M) 说明
复位 1 0x0000_0004 系统启动入口
UART0 接收 33 0x0000_0084 UART接收FIFO达到触发阈值
UART0 发送 34 0x0000_0088 UART发送FIFO空或传输完成
DMA 传输完成 46 0x0000_00B8 DMA通道传输结束
嵌入式开发提示: 在Linux内核中,中断向量表由体系结构相关代码(如arch/arm/kernel/entry-armv.S)初始化。设备驱动通过request_irq()注册ISR,内核自动将ISR地址填入对应中断描述符的action链表,而非直接操作硬件向量表。
中断向量表结构示意图 中断向量表基址 (VTOR = 0x0000_0000) 向量0: 栈指针 向量1: 复位 向量2: NMI 向量3: 硬错误 ... 向量33: UART0 RX 向量34: UART0 TX 向量46: DMA完成 UART0_RX_ISR: 读取RDR → 清除中断标志 DMA_Complete_ISR: 通知CPU数据已就绪

4.2 中断优先级:谁先获得CPU服务

当多个中断同时发生时,中断优先级仲裁逻辑决定CPU先响应哪一个。优先级通常分为抢占优先级和子优先级(或响应优先级)。

  • 抢占优先级: 决定是否允许中断嵌套。高抢占优先级的中断可以打断正在执行的低抢占优先级ISR。
  • 子优先级: 当两个中断的抢占优先级相同时,子优先级高的先执行,但不产生嵌套。
中断源 抢占优先级 子优先级 行为描述
UART0 RX (DMA模式) 0 (最高) 0 可抢占任何其他中断
UART0 TX (轮询模式) 1 0 可被UART0 RX抢占
系统定时器Tick 1 1 与UART0 TX同级,子优先级较低
DMA传输完成 2 (最低) 0 可被所有其他中断抢占
优先级配置陷阱: 在UART+DMA协同模式中,建议将DMA传输完成中断的优先级设置为低于UART接收中断。否则,当DMA完成中断正在执行时,UART接收FIFO可能溢出,导致数据丢失。典型配置:UART RX中断优先级0,DMA完成中断优先级1。

4.3 中断嵌套:高优先级打断低优先级

中断嵌套(Interrupt Nesting)是指CPU正在执行一个低优先级ISR时,一个高优先级中断到达,CPU暂停当前ISR,转而执行高优先级ISR,待高优先级ISR返回后,再恢复低优先级ISR的执行。

中断嵌套执行时序图 时间→ 主程序 (main) 低优先级ISR 高优先级ISR 恢复执行 低优先级中断到达 高优先级中断到达 中断嵌套执行步骤 ① CPU执行主程序时,低优先级中断到达,CPU保存现场,跳转到低优先级ISR。 ② 低优先级ISR执行过程中,高优先级中断到达,CPU再次保存现场(压栈)。 ③ CPU执行高优先级ISR,完成后恢复现场,返回低优先级ISR继续执行。 ④ 低优先级ISR执行完毕,恢复现场,返回主程序。
嵌套深度控制: 在UART驱动中,建议将嵌套深度限制在2层以内(主程序→UART RX ISR→DMA完成ISR)。过深的嵌套会导致栈溢出,尤其在资源受限的MCU上。Linux内核通过local_irq_disable()和spin_lock_irqsave()来管理嵌套临界区。

4.4 CPU响应中断的完整流程

从硬件中断信号拉高到ISR第一条指令执行,CPU经历以下5个标准阶段:

  1. 中断采样: CPU在每个指令周期的末尾采样中断请求线(IRQ/FIQ)。若检测到有效中断信号,进入下一阶段。
  2. 中断判优: 中断控制器(如ARM GIC、NVIC)比较当前所有挂起中断的优先级。若新中断优先级高于当前正在执行的中断优先级(或CPU当前允许中断),则触发中断响应。
  3. 保存现场: CPU自动将当前程序计数器(PC)、程序状态寄存器(PSR/CPSR)以及部分通用寄存器压入栈中。ARM Cortex-M系列硬件自动压栈8个寄存器(xPSR、PC、LR、R12、R3-R0)。
  4. 向量读取与跳转: CPU从中断向量表中读取对应中断源的ISR地址,并将PC设置为该地址。同时,硬件自动清除中断挂起标志(部分架构需要软件清除)。
  5. 执行ISR与恢复现场: CPU执行ISR代码。ISR末尾执行中断返回指令(如ARM的BX LR或MOVS PC, LR),CPU自动从栈中恢复现场,继续执行被中断的程序。
CPU中断响应完整流程图 ① 中断采样 ② 中断判优 ③ 保存现场 (压栈) ④ 向量读取 & 跳转 ⑤ 执行ISR & 恢复现场 关键硬件行为 • 采样中断请求线电平/边沿 • 比较优先级寄存器 • 自动压栈:PC, PSR, LR, R0-R3, R12 • 读取向量表 (4字节/表项) • 更新PC为ISR地址 • 硬件清除中断挂起位 • 执行ISR指令 • 执行中断返回指令 • 硬件自动出栈恢复现场 • 继续执行被中断的程序

4.5 中断响应流程中的关键寄存器操作

以ARM Cortex-M3/M4为例,中断响应过程中涉及以下关键寄存器:

寄存器 全称 中断响应中的作用
PRIMASK 优先级屏蔽寄存器 置1时屏蔽所有可屏蔽中断(除NMI和硬错误)
BASEPRI 基础优先级寄存器 设置中断屏蔽阈值,优先级数值大于等于该值的中断被屏蔽
FAULTMASK 错误屏蔽寄存器 置1时屏蔽所有中断,包括硬错误(除NMI)
ICSR 中断控制状态寄存器 包含当前挂起中断位、当前活跃中断编号等信息
VTOR 向量表偏移寄存器 定义中断向量表的基地址,支持重定位
UART驱动开发关键点: 在ISR中,必须首先读取UART状态寄存器确认中断源(如接收数据就绪、发送完成、错误标志),然后执行对应的处理逻辑,最后清除中断标志位。若未清除标志,CPU将反复进入同一ISR,导致系统卡死。典型代码结构如下:
// UART接收中断服务程序示例 (ARM Cortex-M)
void UART0_IRQHandler(void) {
    uint32_t status = UART0->SR;          // 读取状态寄存器
    if (status & (1 << 5)) {              // 检查RXNE位 (接收非空)
        uint8_t data = UART0->DR;         // 读取数据寄存器 (自动清除RXNE)
        // 将数据放入DMA缓冲区或软件FIFO
        ring_buffer_push(&rx_ring, data);
    }
    if (status & (1 << 6)) {              // 检查TC位 (发送完成)
        // 触发DMA发送下一批数据
        DMA_start_transfer(tx_dma_channel);
        UART0->SR &= ~(1 << 6);          // 软件清除TC标志 (部分MCU需要)
    }
    // 注意:不要在ISR中执行耗时操作,如打印日志、复杂计算
}
中断延迟与DMA协同: 在UART+DMA模式下,UART接收中断仅在DMA传输完成或FIFO溢出时触发,而非每个字节都触发。这大幅降低了中断频率。但CPU响应中断的延迟(中断延迟 = 中断采样到ISR第一条指令执行的时钟周期数)必须小于DMA传输完成到下一个DMA请求到达的时间窗口,否则可能丢失数据。典型ARM Cortex-M3中断延迟为12~16个时钟周期。

4.6 中断系统在UART+DMA协同中的角色总结

  • 中断向量: 为UART RX/TX和DMA通道分配独立的向量号,确保ISR入口唯一。
  • 中断优先级: UART RX中断优先级最高,确保接收数据及时处理;DMA完成中断次之;UART TX中断优先级最低(或使用轮询)。
  • 中断嵌套: 允许DMA完成中断打断UART TX ISR,但不允许UART RX ISR被任何其他中断打断(除非更高优先级的中断)。
  • CPU响应流程: 硬件自动完成采样、判优、压栈、向量跳转,ISR只需关注数据搬运和标志清除,恢复现场由硬件自动完成。