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链表,而非直接操作硬件向量表。
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的执行。
嵌套深度控制: 在UART驱动中,建议将嵌套深度限制在2层以内(主程序→UART RX ISR→DMA完成ISR)。过深的嵌套会导致栈溢出,尤其在资源受限的MCU上。Linux内核通过
local_irq_disable()和spin_lock_irqsave()来管理嵌套临界区。
4.4 CPU响应中断的完整流程
从硬件中断信号拉高到ISR第一条指令执行,CPU经历以下5个标准阶段:
- 中断采样: CPU在每个指令周期的末尾采样中断请求线(IRQ/FIQ)。若检测到有效中断信号,进入下一阶段。
- 中断判优: 中断控制器(如ARM GIC、NVIC)比较当前所有挂起中断的优先级。若新中断优先级高于当前正在执行的中断优先级(或CPU当前允许中断),则触发中断响应。
- 保存现场: CPU自动将当前程序计数器(PC)、程序状态寄存器(PSR/CPSR)以及部分通用寄存器压入栈中。ARM Cortex-M系列硬件自动压栈8个寄存器(xPSR、PC、LR、R12、R3-R0)。
- 向量读取与跳转: CPU从中断向量表中读取对应中断源的ISR地址,并将PC设置为该地址。同时,硬件自动清除中断挂起标志(部分架构需要软件清除)。
- 执行ISR与恢复现场: CPU执行ISR代码。ISR末尾执行中断返回指令(如ARM的
BX LR或MOVS PC, LR),CPU自动从栈中恢复现场,继续执行被中断的程序。
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只需关注数据搬运和标志清除,恢复现场由硬件自动完成。