2. 中断子系统基础:中断向量表、中断控制器、中断优先级、中断嵌套
中断子系统是嵌入式实时操作系统的核心神经,它决定了系统对外部事件的响应速度与确定性。在 Zephyr RTOS 中,中断管理被抽象为硬件无关的接口层,但底层机制仍紧密依赖具体 SoC 架构。本章将深入剖析中断向量表、中断控制器、中断优先级与中断嵌套四个基础模块,为后续中断响应优化与 DMA 协同配置奠定理论基础。
2.1 中断向量表
中断向量表(Interrupt Vector Table, IVT)是处理器在响应中断时查找入口地址的跳转表。每个中断源对应表中的一个条目,条目内容通常为中断服务例程(ISR)的起始地址或跳转指令。
| 架构 | 向量表基址 | 条目大小 | 重定位方式 |
|---|---|---|---|
| ARM Cortex-M | VTOR 寄存器 | 4 字节(函数指针) | 写 VTOR 寄存器 |
| RISC-V | mtvec/stvec | 4 字节(PC 偏移) | 写 mtvec/stvec |
| x86 | IDTR | 8 字节(门描述符) | LIDT 指令 |
Zephyr 在启动阶段通过 _PrepC() 或 z_arm_interrupt_init() 等架构相关函数完成向量表的初始化与重定位。对于 ARM Cortex-M 系列,Zephyr 默认将向量表放置在 RAM 中,允许运行时动态修改中断入口。
关键点:Zephyr 使用
ISR_TABLES 编译选项生成软件中断表,将硬件向量号映射到 Zephyr 的 IRQ 编号,实现跨架构统一的中断管理接口。
优化提示:在性能敏感场景中,可将向量表放置在 TCM(Tightly Coupled Memory)或 ITCM 中,减少中断响应时的指令获取延迟。
2.2 中断控制器
中断控制器负责收集多个外设中断请求,进行优先级裁决后向 CPU 核发送中断信号。不同架构的中断控制器差异显著,Zephyr 通过 struct device 和 irq_connect_dynamic() 等 API 提供统一抽象。
| 控制器类型 | 典型 SoC | 最大中断源 | 优先级位数 | Zephyr 驱动 |
|---|---|---|---|---|
| NVIC | ARM Cortex-M | 240 | 8(3 位用于优先级分组) | arch/arm/core/nvic.c |
| PLIC | RISC-V | 1023 | 7(3 位优先级) | drivers/interrupt_controller/plic.c |
| GIC | ARM Cortex-A | 1020 | 16(4 位优先级) | drivers/interrupt_controller/gic.c |
| APIC | x86 | 255 | 16(4 位优先级) | arch/x86/core/apic.c |
以 ARM Cortex-M 的 NVIC(Nested Vectored Interrupt Controller)为例,其核心特性包括:
- 可编程优先级:每个中断源可独立配置抢占优先级和子优先级。
- 尾链(Tail-Chaining):连续中断响应时跳过出栈/入栈,降低延迟。
- 迟来(Late-Arriving):更高优先级中断在入栈期间到达时,优先响应高优先级中断。
- 咬尾(咬尾中断):相同优先级中断连续触发时,复用栈帧。
注意:Zephyr 在 ARM Cortex-M 上默认使用
CONFIG_ZERO_LATENCY_IRQS 选项标记零延迟中断,这些中断将绕过 Zephyr 的中断调度框架,直接由硬件 NVIC 管理,适用于对延迟要求极高的场景(如 DMA 完成中断)。
2.3 中断优先级
中断优先级决定了当多个中断同时发生时,哪个中断被优先响应。Zephyr 支持两种优先级模型:
- 静态优先级:在编译时通过
IRQ_CONNECT()宏指定,优先级值越小优先级越高。 - 动态优先级:运行时通过
irq_connect_dynamic()设置,适用于需要动态调整中断优先级的场景。
| 架构 | 优先级范围 | 默认空闲优先级 | Zephyr 配置宏 |
|---|---|---|---|
| ARM Cortex-M | 0 ~ 255(实际有效位数由硬件决定) | 0(最高) | CONFIG_NUM_IRQ_PRIO_BITS |
| RISC-V PLIC | 0 ~ 7 | 0(最高) | CONFIG_PLIC_MAX_PRIORITY |
| x86 APIC | 0 ~ 15 | 0(最高) | CONFIG_APIC_IRQ_PRIORITY |
优先级分组(Priority Grouping):ARM Cortex-M 支持将优先级寄存器拆分为抢占优先级和子优先级。抢占优先级决定是否可嵌套,子优先级用于同抢占优先级下的仲裁。Zephyr 通过
CONFIG_ARM_IRQ_PRIORITY_GROUPING 启用此特性。
/* Zephyr 中断优先级配置示例 */
#define UART_IRQ_PRIO 2 /* 高优先级,用于低延迟串口通信 */
#define DMA_IRQ_PRIO 1 /* 更高优先级,确保 DMA 传输完成及时处理 */
#define TIMER_IRQ_PRIO 3 /* 中等优先级,系统心跳 */
/* 静态连接中断 */
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(uart0)), UART_IRQ_PRIO, uart_isr, 0, 0);
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(dma0)), DMA_IRQ_PRIO, dma_isr, 0, 0);
/* 动态连接中断(运行时) */
irq_connect_dynamic(DT_IRQN(DT_NODELABEL(timer0)), TIMER_IRQ_PRIO, timer_isr, 0, 0);
irq_enable(DT_IRQN(DT_NODELABEL(timer0)));
2.4 中断嵌套
中断嵌套是指高优先级中断可以打断正在执行的低优先级中断服务例程。Zephyr 在 ARM Cortex-M 上默认支持硬件中断嵌套,无需软件干预。但在 RISC-V 平台上,需要软件保存和恢复上下文。
| 特性 | ARM Cortex-M (NVIC) | RISC-V (PLIC) | x86 (APIC) |
|---|---|---|---|
| 硬件嵌套支持 | 原生支持 | 需软件实现 | 原生支持 |
| 自动入栈 | 硬件自动压栈 xPSR、PC、LR、R0-R3、R12 | 需软件保存 | 硬件自动压栈 |
| 中断返回指令 | BX LR(EXC_RETURN) | MRET/SRET | IRET |
| Zephyr 配置 | CONFIG_ARM_NESTED_INTERRUPTS | CONFIG_RISCV_SOC_INTERRUPT_NESTING | 默认启用 |
嵌套风险:过度嵌套可能导致栈溢出。Zephyr 为每个中断优先级分配独立的栈空间(
CONFIG_ISR_STACK_SIZE),建议根据实际嵌套深度合理配置栈大小。在 DMA 与中断协同场景中,DMA 完成中断应设置为最高优先级,避免被其他中断延迟。
2.5 Zephyr 中断管理 API 速查
| API 函数 | 功能描述 | 使用场景 |
|---|---|---|
IRQ_CONNECT() |
编译时静态连接中断 | 固定外设中断,性能最优 |
irq_connect_dynamic() |
运行时动态连接中断 | 热插拔设备、动态优先级调整 |
irq_enable() |
使能指定中断 | 初始化完成后启用中断 |
irq_disable() |
禁用指定中断 | 临界区保护、设备暂停 |
irq_lock() |
全局关中断(返回关键锁) | 短临界区保护 |
irq_unlock() |
全局开中断(传入关键锁) | 退出临界区 |
irq_is_enabled() |
查询中断是否使能 | 调试与状态检查 |
性能建议:在 DMA 协同配置中,DMA 完成中断应使用
IRQ_CONNECT() 静态连接,并设置为最高可用优先级。同时使用 CONFIG_ZERO_LATENCY_IRQS 标记该中断,使其绕过 Zephyr 的中断调度层,直接由硬件 NVIC 管理,可将中断延迟降低至 12 个时钟周期以内。