1. 中断控制器基础概念
各位同学好,我是你们的嵌入式Linux讲师。今天咱们开始聊中断控制器,这是设备树配置里最绕不开的一块。说实话,我早年刚接触驱动开发时,被中断搞得晕头转向——明明代码写对了,中断就是不来。后来才发现,是设备树里中断描述符配错了。
好,咱们从头捋一遍。
1.1 什么是中断
中断,说白了就是CPU停下当前工作,去处理一个紧急事件。
你想想看,CPU平时在流水线上跑指令,突然外设说「我这里有数据要处理」,或者「我出错了」。CPU就得暂停手头的活,跳到一个专门的地方去处理这个事件。处理完了,再回来接着干。
我习惯把中断比作你正在写代码,突然电话响了。你放下键盘接电话,处理完再继续写。这个「电话铃声」就是中断信号。
中断的好处很明显:
- 提高效率:CPU不用轮询等待外设状态,省电又省时间
- 实时响应:紧急事件能立刻得到处理
- 多任务支持:不同外设可以共享CPU时间
1.2 中断控制器的作用
一个SoC里可能有几十个外设,每个外设都可能产生中断。如果每个中断都直接连到CPU,那CPU的引脚根本不够用。这时候就需要中断控制器。
中断控制器就像个「总机接线员」。它的核心职责是:
- 收集中断:接收来自各个外设的中断请求
- 优先级管理:决定先处理哪个中断
- 分发中断:把中断信号送给CPU
- 中断屏蔽:可以临时关闭某些中断
- 中断状态记录:告诉CPU是哪个外设触发了中断
举个例子。我在调试一块i.MX6ULL板子时,GPIO按键和UART同时产生中断。如果没有中断控制器,CPU根本不知道先处理谁。有了GIC,它会根据优先级决定——通常UART优先级更高,因为串口数据可能丢失。
1.3 GIC架构简介
GIC,全称Generic Interrupt Controller,是ARM体系里最常用的中断控制器。从Cortex-A系列到Cortex-R系列,基本都在用GIC。
GIC的版本有v1、v2、v3、v4。目前主流的是GICv2和GICv3。咱们重点讲GICv2,因为它在嵌入式Linux里最常见。
GICv2的架构分两大部分:
| 组件 | 全称 | 作用 |
|---|---|---|
| Distributor | 分发器 | 管理所有中断源,配置优先级、使能/屏蔽、触发方式 |
| CPU Interface | CPU接口 | 每个CPU核一个,负责把中断送给对应的CPU |
GIC支持三种中断类型:
- SPI(Shared Peripheral Interrupt):共享外设中断,可以路由到任意CPU核。比如UART、I2C这些外设的中断。
- PPI(Private Peripheral Interrupt):私有外设中断,只发给特定的CPU核。比如每个核自己的定时器中断。
- SGI(Software Generated Interrupt):软件触发的中断,一个CPU核可以给另一个核发中断。常用于核间通信。
中断号的分配是这样的:
ID0-ID15: SGI(软件中断)
ID16-ID31: PPI(私有外设中断)
ID32-ID1019: SPI(共享外设中断)
嗯,这里要注意。设备树里描述中断时,interrupt-cells属性决定了用几个cell来描述一个中断。对于GICv2,通常是3个cell:
interrupt-cells = <3>;
第一个cell: 中断类型(0=SPI, 1=PPI)
第二个cell: 中断号(SPI从32开始编号,但设备树里通常从0开始)
第三个cell: 触发方式(0=电平触发, 1=边沿触发, 4=高电平有效, 8=低电平有效等)
举个例子。我在配置一个UART中断时,设备树里这样写:
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart";
reg = <0x02020000 0x4000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
};
这里GIC_SPI是宏定义,值为0,表示SPI中断。26是中断号(对应硬件上的ID 32+26=58)。IRQ_TYPE_LEVEL_HIGH表示高电平触发。
关键点:GIC的Distributor负责全局配置,CPU Interface负责把中断送给具体哪个核。在多核系统里,你可以通过interrupt-affinity属性指定中断发到哪个CPU核。
我曾经踩过一个坑。有次调试一个网卡驱动,中断一直不触发。查了半天,发现是设备树里interrupt-parent指向错了——我指向了另一个中断控制器,而不是GIC。这个错误在编译时不会报错,运行时也不崩溃,就是中断不工作。所以,interrupt-parent一定要确认指向正确的节点。
GICv3相比v2,主要改进是支持更多CPU核(超过8个),以及引入了Redistributor组件。不过对于咱们嵌入式Linux开发,GICv2已经够用了。我建议初学者先把GICv2吃透,再去看v3的扩展。
好了,这一节就到这里。中断控制器的概念是设备树配置的基础,后面咱们会深入每个属性的具体写法。记住一句话:中断配置错了,驱动写得再好也白搭。