1. GPIO 中断基础:硬件原理、GIC 架构与触发方式
GPIO 中断是嵌入式 Linux 实时系统中最常用的外设事件通知机制。理解其硬件原理、中断控制器架构以及触发配置,是后续进行中断延迟优化和内存访问调优的基石。本节将从 SoC 芯片级视角,拆解 GPIO 中断的完整硬件链路。
1.1 GPIO 硬件原理与中断产生
GPIO(General Purpose Input/Output)引脚在输入模式下,可以检测外部电平变化。当引脚电平满足预设条件(如上升沿、下降沿或电平状态)时,GPIO 模块内部的中断状态寄存器(ISR)相应位会被硬件置位,并向中断控制器发出中断请求信号。
- GPIO 控制器寄存器组: 数据寄存器 (DATA)、方向寄存器 (DIR)、中断使能寄存器 (IE)、中断触发类型寄存器 (ITYPE)、中断状态寄存器 (ISR)。
- 去抖电路 (Debounce): 部分 SoC 内置硬件去抖,可配置采样周期,避免机械开关抖动产生误中断。
- 中断请求线 (IRQ Line): GPIO 控制器将多个 GPIO 引脚的中断合并为一条或几条共享中断线,连接到 GIC。
1.2 中断控制器 (GIC) 架构
在 ARM Cortex-A 系列多核处理器中,通用中断控制器 (Generic Interrupt Controller, GIC) 是中断管理的核心。GIC 负责接收来自各个外设(包括 GPIO 控制器)的中断请求,进行优先级仲裁,并将中断分发给指定的 CPU 核心。
GIC 架构主要分为两个逻辑单元:分发器 (Distributor) 和 CPU 接口 (CPU Interface)。
| 组件 | 功能描述 | 关键寄存器/特性 |
|---|---|---|
| 分发器 (Distributor) | 集中管理所有中断源,配置中断优先级、触发方式、目标 CPU,并控制中断的使能/禁用。 | GICD_ISENABLER, GICD_IPRIORITYR, GICD_ITARGETSR, GICD_ICFGR |
| CPU 接口 (CPU Interface) | 每个 CPU 核心拥有独立的 CPU 接口,负责与核心交互,提供中断应答 (ACK) 和结束中断 (EOI) 机制。 | ICC_IAR, ICC_EOIR, ICC_BPR, ICC_PMR |
irqbalance 服务。
1.3 中断号与触发方式
在 Linux 内核中,每个中断源都有一个唯一的中断号 (IRQ number)。对于 GPIO 中断,中断号的分配有两种常见方式:
- 静态分配: 在设备树 (Device Tree) 中通过
interrupts = <GIC_SPI 100 IRQ_TYPE_EDGE_RISING>直接指定硬件中断号。 - 动态分配: 使用 GPIO 子系统 API,如
gpio_to_irq(),由内核动态分配虚拟中断号,映射到 GPIO 控制器的硬件中断线。
中断触发方式决定了中断产生的条件,配置不当会导致中断丢失或频繁触发。
| 触发方式 | 宏定义 (Linux) | 适用场景 | 实时性影响 |
|---|---|---|---|
| 上升沿触发 | IRQ_TYPE_EDGE_RISING |
按键按下、脉冲计数 | 低,仅检测边沿 |
| 下降沿触发 | IRQ_TYPE_EDGE_FALLING |
按键释放、信号下降 | 低,仅检测边沿 |
| 双边沿触发 | IRQ_TYPE_EDGE_BOTH |
编码器信号、电平变化 | 中等,可能产生双倍中断 |
| 高电平触发 | IRQ_TYPE_LEVEL_HIGH |
中断控制器级联、电平敏感外设 | 高,需注意电平保持与中断屏蔽 |
| 低电平触发 | IRQ_TYPE_LEVEL_LOW |
唤醒源、低电平有效信号 | 高,需注意电平保持与中断屏蔽 |
- 边沿触发: 适合短脉冲信号,中断处理函数执行完毕后,即使信号电平保持,也不会再次触发。但容易在信号抖动时产生多次中断。
- 电平触发: 适合需要持续响应的信号,中断处理函数必须清除中断源(如读取数据寄存器),否则会无限触发。在共享中断线时,电平触发是更安全的选择。
1.4 设备树中的 GPIO 中断配置示例
以下是一个典型的设备树节点配置,展示了如何为 GPIO 按键定义中断:
/* 设备树片段:GPIO 按键中断配置 */
/ {
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
button@0 {
label = "USER_KEY";
gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; /* GPIO1_IO15 */
interrupts = <15 IRQ_TYPE_EDGE_FALLING>; /* 下降沿触发 */
linux,code = <KEY_ENTER>;
};
};
};
/* 对应的 GPIO 控制器节点 */
&gpio1 {
interrupt-parent = <&gic>; /* 中断父节点为 GIC */
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>; /* GPIO1 控制器中断线 */
#gpio-cells = <2>;
#interrupt-cells = <2>;
};
/proc/interrupts 可以查看系统中所有中断的统计信息,包括每个 CPU 核心处理的中断次数。对于 GPIO 中断,可以观察 gpio 或 gpio-keys 相关行的计数,确认中断是否正常触发。
1.5 本章小结
GPIO 中断的硬件基础涉及 GPIO 控制器内部的中断状态寄存器、去抖电路和触发检测逻辑。GIC 作为中断管理的核心,通过分发器和 CPU 接口实现中断的优先级仲裁与多核分发。中断号的映射(硬件中断线 → GIC 中断号 → Linux IRQ 号)和触发方式的选择(边沿 vs 电平)直接影响中断的可靠性和实时响应性能。掌握这些基础概念,是后续进行中断延迟测量、优先级提升和内存访问优化的前提。