3. 中断控制器基础:中断向量表、中断优先级、中断嵌套、中断屏蔽与使能机制

中断控制器是嵌入式系统响应外部和内部异步事件的核心硬件单元。在 VxWorks BSP 中,中断控制器(如 GIC-400、i8259、INTC)的初始化与联动调试直接决定了系统的实时响应能力。本节从四个核心概念入手,建立中断控制器的硬件抽象视图。

核心观点:中断向量表决定“中断源 → 处理函数”的映射;中断优先级决定“谁先执行”;中断嵌套决定“能否抢占”;中断屏蔽与使能决定“何时响应”。这四个机制共同构成 VxWorks 中断子系统的硬件基础。

3.1 中断向量表(Interrupt Vector Table, IVT)

中断向量表是一张存储在固定内存地址的跳转表,每个表项对应一个中断源,存放该中断的服务例程入口地址或跳转指令。在 ARM Cortex-A 系列中,IVT 通常位于 0x00000000 或 0xFFFF0000;在 PowerPC 中,IVT 基址由 IVPR 寄存器指定。

架构 IVT 基址 表项大小 最大中断数 VxWorks 配置宏
ARM Cortex-A9 0x00000000 / 0xFFFF0000 4 字节(跳转指令) 256 INCLUDE_GIC
PowerPC e500 IVPR 可编程 8 字节(异常向量) 128 INCLUDE_INTC
x86 (i8259) 0x00000000(实模式) 4 字节(段:偏移) 256 INCLUDE_I8259
RISC-V mtvec 可编程 4 字节(直接/向量模式) 1024 INCLUDE_PLIC

在 VxWorks BSP 中,中断向量表的初始化流程如下:

  1. BSP 启动阶段:在 sysHwInit() 中调用 intVecBaseSet() 设置 IVT 基址。
  2. 中断注册:驱动通过 intConnect() 将 ISR 地址写入 IVT 对应表项。
  3. 异常向量保留:前 16 个向量通常保留给 CPU 异常(Reset、Undef、SWI、Prefetch Abort 等)。
  4. 中断向量偏移:外部中断从向量 16(ARM)或 32(x86)开始。
调试要点:在 BSP 调试初期,使用 intVecGet() 检查 IVT 表项是否被正确填充。常见错误包括:IVT 基址未对齐、表项被 Bootloader 覆盖、中断号与向量号偏移计算错误。
中断向量表结构示意图 中断向量表(IVT)结构 IVT 基址(intVecBaseSet 设置) 向量 0 (Reset) 向量 1 (Undef) 向量 2 (SWI) 向量 3 (PrefAbort) 向量 16 (IRQ0) 向量 17 (IRQ1) ... Reset_Handler sysTimerIsr 偏移 = 中断号 × 表项大小(4 或 8 字节)

3.2 中断优先级(Interrupt Priority)

中断优先级决定了当多个中断同时到达时,CPU 优先响应哪一个。VxWorks 支持两种优先级模型:

  • 固定优先级模型:每个中断源分配一个静态优先级,由硬件寄存器配置。高优先级中断可以抢占低优先级中断。
  • 动态优先级模型:优先级可在运行时通过 intPrioritySet() 调整,适用于需要 QoS 保障的场景。
中断控制器 优先级范围 优先级寄存器 默认优先级 VxWorks API
GIC-400 0–255(0 最高) ICD_IPRIORITYRn 0xA0(160) intPrioritySet()
i8259 0–7(0 最高) OCW1 / OCW2 IRQ0=0, IRQ7=7 sysIntLvl()
PowerPC INTC 0–15(15 最高) SIUx / EISR 可编程 intVecBaseSet()
常见陷阱:在 GIC 中,优先级值越小优先级越高,这与直觉相反。BSP 移植时容易将优先级写反,导致高优先级中断被低优先级阻塞。调试时使用 intPriorityGet() 验证配置。

3.3 中断嵌套(Interrupt Nesting)

中断嵌套是指一个中断服务例程(ISR)正在执行时,另一个更高优先级的中断到达,CPU 暂停当前 ISR 转而执行更高优先级的 ISR。VxWorks 默认支持中断嵌套,但需要满足以下条件:

  1. 硬件条件:中断控制器支持优先级抢占(如 GIC 的 Priority Mask 机制)。
  2. 软件条件:ISR 中未调用 intLock() 或 taskLock() 禁止中断。
  3. 栈条件:中断栈(ISR Stack)必须足够深,以容纳嵌套的上下文保存。
中断嵌套时序图 中断嵌套执行时序 t 主程序(优先级 0) ISR_Low (Prio 3) ISR_High (Prio 1) ISR_Low 恢复 主程序恢复 嵌套流程说明: 1. 主程序执行时,低优先级中断到达 → 进入 ISR_Low 2. ISR_Low 执行中,高优先级中断到达 → 抢占进入 ISR_High 3. ISR_High 完成后 → 恢复 ISR_Low → 恢复主程序
调试建议:在 BSP 调试阶段,使用 intContext() 判断当前是否处于中断上下文。如果发现 ISR 执行时间过长导致低优先级中断丢失,应检查中断嵌套是否被意外禁止(如 intLock() 未配对)。

3.4 中断屏蔽与使能机制

中断屏蔽与使能是控制中断响应窗口的基本手段。VxWorks 提供两级控制:

  • CPU 级:通过 intLock() / intUnlock() 全局屏蔽/使能所有可屏蔽中断。返回前中断状态保存在 intLockKey 中。
  • 中断控制器级:通过 intDisable() / intEnable() 单独屏蔽/使能某个中断源。
API 作用域 返回值 典型使用场景 注意事项
intLock() 全局(所有可屏蔽中断) 前中断状态(key) 临界区保护 必须与 intUnlock() 配对
intUnlock() 全局 无 退出临界区 传入 key 恢复原始状态
intDisable() 单中断源 前使能状态 关闭特定外设中断 不影响其他中断
intEnable() 单中断源 前使能状态 开启特定外设中断 需先配置优先级

在 GIC 中,中断屏蔽的硬件实现分为两个层次:

  1. 全局屏蔽:通过 CPU 接口寄存器 ICC_PMR(Priority Mask Register)设置优先级阈值。只有优先级高于阈值的中断才能被 CPU 响应。
  2. 单源屏蔽:通过 ICD_ICENABLERn / ICD_ISENABLERn 寄存器使能或禁用特定中断源。
关键调试命令:在 VxWorks shell 中,使用 i 命令查看中断状态,使用 intShow() 显示当前中断使能/屏蔽状态。如果发现中断未响应,首先检查 intLock() 是否被意外调用,然后检查 GIC 的 ICC_PMR 阈值是否设置正确。
中断屏蔽与使能机制架构 中断屏蔽与使能机制架构 中断源 0 (Timer) 中断源 1 (UART) 中断源 2 (DMA) 中断控制器 ICD_ISENABLER ICD_ICENABLER ICD_IPRIORITY ICC_PMR (阈值) CPU CPSR.I (IRQ mask) intLock() / intUnlock() 屏蔽路径: intDisable(IRQn) → 设置 ICD_ICENABLER[n] → 中断控制器不转发该中断 intLock() → 设置 CPSR.I → CPU 忽略所有 IRQ(但 FIQ 仍可响应)

3.5 中断控制器联动调试要点

在 BSP 调试中,中断控制器与硬件抽象层的联动是验证中断子系统正确性的关键。以下是基于实际调试经验总结的检查清单:

检查项 验证方法 常见故障 解决措施
IVT 基址对齐 intVecBaseGet() 基址未按 64 字节对齐 在 sysHwInit() 中强制对齐
中断优先级配置 intPriorityGet() 优先级值反转(GIC 中 0 最高) 检查 ICD_IPRIORITYRn 写入值
中断使能状态 intShow() 中断被意外屏蔽 检查 intLock() 嵌套计数
中断嵌套深度 在 ISR 中调用 intContext() 嵌套导致栈溢出 增大 ISR_STACK_SIZE
中断响应延迟 示波器测量 GPIO 翻转 延迟超过 100μs 检查 ICC_PMR 阈值和缓存一致性
调试避坑:在 GIC 中,如果 ICC_PMR 设置为 0xFF(最低阈值),所有中断都会被屏蔽。BSP 初始化时必须将 ICC_PMR 设置为 0xF0 或更低,否则即使 intEnable() 被调用,中断也不会被 CPU 响应。这是 GIC 移植中最常见的“中断不触发”原因。

通过本节的学习,你应该能够:

  • 理解中断向量表的布局和初始化流程
  • 区分固定优先级与动态优先级模型
  • 分析中断嵌套的硬件和软件条件
  • 掌握中断屏蔽与使能的两级控制机制
  • 使用 VxWorks 调试命令验证中断控制器状态