2、中断硬件架构:中断控制器、中断向量表、优先级与嵌套
好,咱们进入中断系统的硬件核心。说实话,很多做嵌入式开发的朋友,写中断服务程序写得飞起,但一问到中断控制器怎么工作的,就有点含糊了。我个人觉得,搞懂这部分,才算真正入了实时系统的门。
中断硬件架构,说白了就是一套「硬件级的调度系统」。CPU 不可能自己去轮询每个外设有没有事,那太傻了。它得有个「管家」——也就是中断控制器,来帮它打理这些杂事。
2.1 中断控制器:GIC 与 PIC
中断控制器是 CPU 和外设之间的桥梁。它的核心职责就三个:收中断、判优先级、发中断。
常见的两种架构:
- PIC(可编程中断控制器):老牌选手,x86 时代的经典。比如 8259A,级联后最多管 15 个中断源。我在一个工控项目里用过它,配置起来确实有点繁琐,每个中断要单独设触发方式和优先级。
- GIC(通用中断控制器):ARM 体系的标配,现在 Cortex-A/R 系列基本都用它。GIC 比 PIC 强大多了,支持多达 1020 个中断源,还能区分 SPI(共享外设中断)、PPI(私有外设中断)和 SGI(软件触发中断)。
核心区别:PIC 是「集中式」管理,所有中断走一条线;GIC 是「分布式」架构,支持多核、多优先级组,更适合现代复杂 SoC。
嗯,这里要注意:GIC 的版本也分好几代。GICv2 是经典款,Cortex-A7/A9 常用;GICv3/v4 支持更多核和虚拟化,服务器级的芯片才用得上。你想想看,一个手机 SoC 里可能有几十个外设同时申请中断,没有 GIC 这种级别的管家,CPU 早就崩了。
2.2 中断向量表:CPU 的「紧急联络簿」
中断来了,CPU 怎么知道该跳到哪里去执行?答案就是中断向量表。
中断向量表,本质上是一张地址表。每个中断源对应一个表项,表项里存的是中断服务程序的入口地址。CPU 收到中断后,硬件自动根据中断号去查表,然后跳转。
我举个例子,ARM Cortex-M 系列的向量表:
; 向量表起始地址(默认 0x00000000)
__Vectors DCD __initial_sp ; 栈顶指针
DCD Reset_Handler ; 复位中断
DCD NMI_Handler ; 不可屏蔽中断
DCD HardFault_Handler ; 硬错误
DCD MemManage_Handler ; 内存管理
DCD BusFault_Handler ; 总线错误
DCD UsageFault_Handler ; 用法错误
; ... 后面是外设中断
DCD TIM2_IRQHandler ; 定时器2中断
DCD USART1_IRQHandler ; 串口1中断
我在项目中遇到过一个问题:某个芯片上电后一直跑飞,查了半天发现是向量表被意外改写了。从那以后,我习惯把向量表放在只读区域,或者加上写保护。
避坑指南:我曾经在 RTOS 移植时,忘了重新映射向量表到 RAM,结果动态注册的中断全都不生效。记住,如果你的系统支持运行时修改中断服务函数,一定要把向量表拷贝到 RAM 里,并且告诉 CPU 新的基地址。
2.3 中断优先级:谁更紧急?
多个中断同时来了怎么办?优先级说了算。
中断优先级,通常分两层:
- 硬件优先级:由中断控制器决定,数值越小优先级越高(有些芯片反过来)。GIC 支持 16 级优先级,PIC 一般是 8 级。
- 软件优先级:由操作系统或用户配置,可以在一定范围内调整。
为什么要有优先级?你想想看,一个按键中断和一個定时器中断同时发生,按键可能只是记录一下,定时器却关系到电机控制。如果优先级搞反了,电机可能就抖起来了。
我个人的习惯是:时间敏感的中断给高优先级,数据量大的中断给低优先级。比如 CAN 通信中断,数据帧丢了就丢了,但步进电机的脉冲中断,一个都不能少。
优先级分组:GIC 支持把优先级分成「抢占优先级」和「子优先级」。抢占优先级决定能否打断当前中断,子优先级决定同抢占优先级下的响应顺序。这个设计很巧妙,能灵活控制嵌套深度。
2.4 中断嵌套:中断里还能有中断?
中断嵌套,就是高优先级中断打断低优先级中断的服务程序。听起来简单,但实现起来有不少坑。
中断嵌套的硬件支持:
- CPU 自动保存当前中断的上下文(至少是 PC 和状态寄存器)
- 中断控制器允许更高优先级的中断信号通过
- 中断服务程序必须可重入(reentrant)
我曾经在一个项目中,中断嵌套层数达到了 4 层。结果栈空间不够,直接 HardFault。从那以后,我给自己定了个规矩:中断嵌套不超过 3 层,每层栈预留至少 128 字节。
警告:中断嵌套不是越多越好。每嵌套一层,就要多保存一次上下文,多消耗栈空间。而且嵌套太深容易导致优先级反转——低优先级中断被高优先级中断反复打断,迟迟执行不完。实时系统里,这可能是致命的。
嗯,这里还要提一个概念:中断延迟。从硬件发出中断信号,到 CPU 开始执行第一条中断服务指令,这个时间就是中断延迟。嵌套越深,延迟越大。所以,如果你的系统对响应时间有硬性要求(比如 10 微秒以内),最好限制嵌套层数,甚至禁止嵌套。
2.5 知识体系总览
下面这张图,是我自己总结的中断硬件架构核心逻辑。你看一眼,基本就能把前面讲的内容串起来:
这张图从左到右,就是中断从产生到处理完成的完整路径。你仔细看,中断控制器是中间最关键的一环——它决定了哪个中断能进、哪个得等着。
2.6 小结
中断硬件架构,说白了就是一套「硬件级的任务调度系统」。中断控制器是调度器,向量表是跳转表,优先级是调度策略,嵌套是抢占机制。搞懂了这些,你写中断服务程序的时候,心里就有底了。
我个人建议,新手可以先从 PIC 入手理解基本原理,然后切换到 GIC 学习现代架构。别一上来就啃 GICv3 的几百页手册,容易劝退。先搞懂 GICv2 的 Distributor 和 CPU Interface 两个模块怎么配合,后面就顺了。
实战建议:下次调试中断问题时,先检查三件事:① 中断控制器里对应的中断使能了没?② 优先级配置对不对?③ 向量表地址有没有映射错?这三步能解决 80% 的中断问题。
公众号:蓝海资料掘金营,微信 deep3321