3. 中断控制器概念:中断控制器(Interrupt Controller)在SoC中的作用与层级
中断控制器(Interrupt Controller)是 SoC 内部管理中断请求的核心硬件单元。它位于外设与 CPU 之间,负责收集、仲裁、路由和传递中断信号,是嵌入式系统实时响应能力的基石。在设备树中,中断控制器通过特定的属性描述其拓扑结构,驱动开发者必须理解其层级关系才能正确配置中断映射。
3.1 中断控制器的核心作用
中断控制器在 SoC 中承担以下关键职能:
- 中断收集:接收来自多个外设(GPIO、定时器、DMA、I2C、SPI 等)的中断请求信号。
- 优先级仲裁:根据预设的优先级策略,决定哪个中断请求优先传递给 CPU。
- 中断屏蔽:允许软件通过寄存器单独启用或禁用某个中断源,实现精细控制。
- 中断路由:将中断请求导向指定的 CPU 核心(在多核系统中尤为重要)。
- 中断类型转换:将外设的边沿触发或电平触发信号转换为 CPU 可识别的中断信号。
- 中断状态管理:提供中断挂起状态寄存器,供软件查询和清除中断标志。
关键概念: 中断控制器是 CPU 与外部事件之间的“交通警察”。没有中断控制器,CPU 将不得不通过轮询方式检查每个外设的状态,导致严重的性能浪费。
3.2 中断控制器的层级结构
现代 SoC 通常包含多级中断控制器,形成树形层级结构。这种设计可以管理数百个中断源,同时保持硬件和软件的清晰性。
层级设计动机: 单级中断控制器的输入引脚数量受限于硬件实现成本。通过级联多个中断控制器,SoC 可以支持大量外设中断,同时保持每个控制器的逻辑复杂度可控。
3.2.1 典型的三级中断层级
| 层级 | 名称 | 位置 | 管理中断源数量 | 典型实例 |
|---|---|---|---|---|
| L1 | 根中断控制器 | CPU 核心附近 | 16~64 | GIC-400(ARM Cortex-A 系列) |
| L2 | SoC 级中断控制器 | SoC 内部总线 | 32~128 | TI OMAP 的 INTC、NXP i.MX 的 GPC |
| L3 | 外设子系统中控制器 | 外设模块内部 | 8~32 | GPIO 控制器内部的 interrupt controller |
在设备树中,这种层级通过 interrupt-parent 属性和 interrupts 属性串联起来。每个中断控制器节点本身也可能是一个中断消费者,连接到上一级控制器。
3.2.2 中断层级关系 SVG 图
3.3 中断控制器的设备树表示
在设备树中,中断控制器节点需要声明以下关键属性:
| 属性 | 含义 | 示例值 |
|---|---|---|
interrupt-controller |
空属性,声明该节点是一个中断控制器 | 无值 |
#interrupt-cells |
指定中断描述符所需的单元数 | 2(通常表示中断号和触发类型) |
interrupt-parent |
指向上一级中断控制器的 phandle | &gic |
interrupts |
该控制器自身连接到父控制器的中断描述 | <0 89 4> |
reg |
中断控制器的寄存器地址范围 | <0x00a01000 0x1000> |
3.3.1 设备树中断层级示例
/* L1: 根中断控制器 - GIC */
gic: interrupt-controller@00a01000 {
compatible = "arm,gic-400";
reg = <0x00a01000 0x1000>,
<0x00a02000 0x2000>;
interrupt-controller;
#interrupt-cells = <3>; /* 中断类型、中断号、触发标志 */
};
/* L2: SoC 级中断控制器 - GPIO 控制器本身作为中断控制器 */
gpio2: gpio@020a0000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x020a0000 0x4000>;
interrupt-controller;
#interrupt-cells = <2>; /* 中断号、触发类型 */
interrupt-parent = <&gic>;
interrupts = <0 66 4>; /* 连接到 GIC 的中断线 */
};
/* L3: 外设节点 - 使用 GPIO 作为中断源 */
button@0 {
compatible = "gpio-keys";
interrupt-parent = <&gpio2>;
interrupts = <3 2>; /* GPIO2_IO03,下降沿触发 */
label = "user-button";
};
常见错误: 初学者容易混淆
interrupt-parent 和 interrupts 的层级关系。每个节点(包括中断控制器自身)的 interrupt-parent 指向的是它的“上级”控制器,而不是它管理的下级设备。GPIO 控制器作为中断控制器时,它自己的中断要连接到 GIC,而 GPIO 引脚上的外设中断则连接到 GPIO 控制器。
3.4 中断控制器的分类
根据架构和功能,中断控制器可分为以下几类:
| 类型 | 特点 | 典型代表 | 应用场景 |
|---|---|---|---|
| 向量中断控制器(VIC) | 硬件直接提供中断服务函数地址,响应速度快 | ARM PrimeCell VIC | ARM7/ARM9 传统 SoC |
| 通用中断控制器(GIC) | 支持多核、多优先级、中断虚拟化 | ARM GIC-400/500/600 | Cortex-A 系列多核处理器 |
| 高级中断控制器(AIC) | 集成多种触发模式、自动嵌套 | Atmel AIC | AT91SAM 系列 MCU |
| GPIO 中断控制器 | 每个 GPIO 引脚可配置为中断源 | i.MX GPIO、STM32 EXTI | 通用嵌入式 Linux 设备 |
3.5 中断控制器层级与设备树中断映射
设备树通过 interrupt-map 和 interrupt-map-mask 属性处理跨层级的中断路由,特别是在 PCIe 桥接或复杂总线桥接场景中。
3.5.1 中断映射流程 SVG 图
3.6 中断控制器层级对驱动开发的影响
驱动开发者在编写中断处理代码时,必须清楚中断控制器的层级关系:
- 中断号获取:
platform_get_irq()返回的是 Linux 内核虚拟中断号(IRQ number),该号由内核根据设备树层级自动分配。 - 中断触发类型:设备树中
interrupts属性的第三个 cell 通常指定触发类型(上升沿、下降沿、高电平、低电平),驱动可通过irq_set_irq_type()确认。 - 中断嵌套:多级中断控制器可能导致中断响应延迟,驱动应避免在中断上下文中执行耗时操作。
- 共享中断:多个外设可能共享同一根中断线,驱动必须检查中断状态寄存器确认中断来源。
实践建议: 在调试中断问题时,首先检查设备树中
interrupt-parent 的 phandle 是否正确指向了预期的中断控制器节点。使用 cat /proc/interrupts 可以查看当前系统中所有中断的分配情况,帮助验证中断层级配置是否正确。