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 中,中断向量表的初始化流程如下:
- BSP 启动阶段:在
sysHwInit()中调用intVecBaseSet()设置 IVT 基址。 - 中断注册:驱动通过
intConnect()将 ISR 地址写入 IVT 对应表项。 - 异常向量保留:前 16 个向量通常保留给 CPU 异常(Reset、Undef、SWI、Prefetch Abort 等)。
- 中断向量偏移:外部中断从向量 16(ARM)或 32(x86)开始。
调试要点:在 BSP 调试初期,使用
intVecGet() 检查 IVT 表项是否被正确填充。常见错误包括:IVT 基址未对齐、表项被 Bootloader 覆盖、中断号与向量号偏移计算错误。
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 默认支持中断嵌套,但需要满足以下条件:
- 硬件条件:中断控制器支持优先级抢占(如 GIC 的 Priority Mask 机制)。
- 软件条件:ISR 中未调用
intLock()或taskLock()禁止中断。 - 栈条件:中断栈(ISR Stack)必须足够深,以容纳嵌套的上下文保存。
调试建议:在 BSP 调试阶段,使用
intContext() 判断当前是否处于中断上下文。如果发现 ISR 执行时间过长导致低优先级中断丢失,应检查中断嵌套是否被意外禁止(如 intLock() 未配对)。
3.4 中断屏蔽与使能机制
中断屏蔽与使能是控制中断响应窗口的基本手段。VxWorks 提供两级控制:
- CPU 级:通过
intLock()/intUnlock()全局屏蔽/使能所有可屏蔽中断。返回前中断状态保存在intLockKey中。 - 中断控制器级:通过
intDisable()/intEnable()单独屏蔽/使能某个中断源。
| API | 作用域 | 返回值 | 典型使用场景 | 注意事项 |
|---|---|---|---|---|
intLock() |
全局(所有可屏蔽中断) | 前中断状态(key) | 临界区保护 | 必须与 intUnlock() 配对 |
intUnlock() |
全局 | 无 | 退出临界区 | 传入 key 恢复原始状态 |
intDisable() |
单中断源 | 前使能状态 | 关闭特定外设中断 | 不影响其他中断 |
intEnable() |
单中断源 | 前使能状态 | 开启特定外设中断 | 需先配置优先级 |
在 GIC 中,中断屏蔽的硬件实现分为两个层次:
- 全局屏蔽:通过 CPU 接口寄存器
ICC_PMR(Priority Mask Register)设置优先级阈值。只有优先级高于阈值的中断才能被 CPU 响应。 - 单源屏蔽:通过
ICD_ICENABLERn/ICD_ISENABLERn寄存器使能或禁用特定中断源。
关键调试命令:在 VxWorks shell 中,使用
i 命令查看中断状态,使用 intShow() 显示当前中断使能/屏蔽状态。如果发现中断未响应,首先检查 intLock() 是否被意外调用,然后检查 GIC 的 ICC_PMR 阈值是否设置正确。
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 调试命令验证中断控制器状态