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。
实时性提示: 硬件去抖会增加中断响应延迟。在实时性要求高的场景(如编码器信号捕获),建议禁用硬件去抖,在软件中断处理中通过定时器或工作队列进行软件去抖。
GPIO 中断产生硬件路径 GPIO 中断产生硬件路径 外部信号 GPIO 引脚 去抖电路 触发检测 ISR 置位 GIC 路径:外部信号 → GPIO 引脚 → 去抖 → 触发检测 → ISR 置位 → 中断请求到 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
性能陷阱: 在多核系统中,如果 GPIO 中断的目标 CPU 配置不当(如所有中断都发往 CPU0),会导致 CPU0 负载过高,中断响应延迟增加。应使用 GICD_ITARGETSR 寄存器将中断分散到不同核心,或使用内核的 irqbalance 服务。
GIC 架构与中断分发 GIC-400 架构与中断分发 GPIO 中断 UART 中断 Timer 中断 分发器 优先级仲裁 目标 CPU 选择 触发方式配置 CPU 接口 0 ICC_IAR/EOIR CPU 接口 1 ICC_IAR/EOIR CPU 接口 2 ICC_IAR/EOIR CPU0 CPU1 CPU2 GIC 中断分发流程 外设中断 → 分发器 (优先级/目标选择) → CPU 接口 (ACK/EOI) → 目标 CPU 核心 中断延迟 = 外设延迟 + GIC 仲裁延迟 + CPU 响应延迟

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 唤醒源、低电平有效信号 高,需注意电平保持与中断屏蔽
边沿 vs 电平触发选择原则:
  • 边沿触发: 适合短脉冲信号,中断处理函数执行完毕后,即使信号电平保持,也不会再次触发。但容易在信号抖动时产生多次中断。
  • 电平触发: 适合需要持续响应的信号,中断处理函数必须清除中断源(如读取数据寄存器),否则会无限触发。在共享中断线时,电平触发是更安全的选择。

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 相关行的计数,确认中断是否正常触发。
中断号映射与触发方式选择 中断号映射与触发方式选择 硬件中断线 #64 GIC 中断号 Linux IRQ 号 处理函数 触发方式配置 (GICD_ICFGR) 边沿触发 (Edge) → 适合短脉冲,注意防抖 电平触发 (Level) → 适合持续信号,注意清除中断源

1.5 本章小结

GPIO 中断的硬件基础涉及 GPIO 控制器内部的中断状态寄存器、去抖电路和触发检测逻辑。GIC 作为中断管理的核心,通过分发器和 CPU 接口实现中断的优先级仲裁与多核分发。中断号的映射(硬件中断线 → GIC 中断号 → Linux IRQ 号)和触发方式的选择(边沿 vs 电平)直接影响中断的可靠性和实时响应性能。掌握这些基础概念,是后续进行中断延迟测量、优先级提升和内存访问优化的前提。