1. 中断概念与硬件基础

中断,说白了就是CPU正在忙着干活,突然被一个外部事件打断了。

我刚开始接触嵌入式时,总觉得中断是个很玄乎的东西。后来调试一个网络驱动,发现数据包老是丢,查了三天才发现是中断处理太慢导致的。嗯,从那以后,我对中断的理解就深刻多了。

1.1 什么是中断

中断是一种硬件机制。它让外设可以主动通知CPU:嘿,我有事找你!

没有中断的话,CPU只能轮询——不停地问每个外设:你有事吗?你有事吗?这效率,你想想看,得多低。

中断的核心流程其实很简单:

  • 外设产生中断信号
  • 中断控制器接收并转发给CPU
  • CPU暂停当前任务,保存现场
  • CPU跳转到中断服务程序(ISR)执行
  • 执行完毕,恢复现场,继续原来的工作

我在项目中遇到过一个问题:某个传感器中断触发太频繁,导致系统响应变慢。后来我加了一个中断合并机制,把多次中断合并成一次处理,问题就解决了。

1.2 中断控制器——GIC

GIC,全称Generic Interrupt Controller,是ARM架构下标准的中断控制器。

你想想看,一个SoC里可能有几十上百个中断源。如果每个都直接连到CPU,那CPU的引脚根本不够用。GIC就是中间人,负责管理所有中断。

GIC的架构分为两部分:

  • 分发器(Distributor):负责中断的使能、优先级、路由等配置
  • CPU接口(CPU Interface):负责与CPU核交互,发送中断信号

GIC版本演进:

  • GICv1:支持最多8个CPU核,每个核最多1020个中断
  • GICv2:增加了虚拟化支持,广泛用于Cortex-A系列
  • GICv3:支持更多CPU核,引入了独立的中断路由
  • GICv4:进一步优化虚拟化中断性能

我个人习惯用GICv2,因为它在大多数嵌入式Linux平台上都支持得很好。调试起来也方便。

下面我用一张图来展示GIC的工作流程:

GIC中断处理流程 外设 中断信号 GIC分发器 使能/优先级/路由 转发 GIC CPU接口 与CPU交互 IRQ/FIQ CPU核 GIC支持的中断类型: • SGI (Software Generated Interrupt):软件触发的中断,用于核间通信 • PPI (Private Peripheral Interrupt):私有外设中断,每个核独享 • SPI (Shared Peripheral Interrupt):共享外设中断,可路由到任意核 • LPI (Locality-specific Peripheral Interrupt):基于消息的中断,GICv3引入 图1:GIC中断处理流程示意图

1.3 中断号

每个中断源都有一个唯一的中断号。在Linux里,中断号分两种:

  • 硬件中断号:由芯片厂商定义,比如某个GPIO的中断号是32
  • 软件中断号(IRQ number):Linux内核映射后的逻辑中断号

我记得第一次写驱动时,直接在代码里写死了硬件中断号。结果换了一个板子,中断号变了,驱动就炸了。后来我才知道,应该用platform_get_irq()这样的接口动态获取。

小技巧:在设备树里,中断号通常用三个字段描述:

interrupts = <GIC_SPI 42 IRQ_TYPE_EDGE_RISING>;

第一个字段是中断类型,第二个是中断号,第三个是触发方式。

1.4 中断触发方式

中断触发方式,说白了就是外设怎么告诉CPU:我有事!

触发方式 说明 典型应用
电平触发(Level-triggered) 信号保持高电平或低电平 按键、网络中断
边沿触发(Edge-triggered) 信号上升沿或下降沿触发 GPIO中断、定时器
脉冲触发(Pulse-triggered) 短脉冲信号 DMA完成中断

这里有个坑,我必须要说。电平触发的中断,如果ISR没有及时清除中断源,中断会一直触发。我曾经调试一个网卡驱动,发现中断风暴把CPU占满了,查了半天才发现是电平中断没清干净。

避坑指南:

  • 电平触发:一定要在ISR里清除中断源,否则会无限触发
  • 边沿触发:可能会丢失中断,如果两次中断间隔太短
  • 共享中断:多个设备共用一根中断线,ISR要判断是谁触发的

1.5 中断优先级与嵌套

GIC支持中断优先级。高优先级的中断可以打断低优先级的中断处理,这就是中断嵌套。

我个人习惯把实时性要求高的中断设高优先级,比如定时器、网络。把一些不那么紧急的中断设低优先级,比如按键、串口。

但要注意,中断嵌套太多会导致栈溢出。我在一个项目里就遇到过,三层中断嵌套直接把内核栈撑爆了,系统直接panic。后来我限制了嵌套层数,最多两层。

关键点总结:

  • 中断是CPU与外设通信的高效机制
  • GIC是ARM架构的标准中断控制器
  • 中断号分硬件号和软件号,驱动里用软件号
  • 触发方式选错了,调试起来很痛苦
  • 优先级设置要合理,别让中断嵌套太深

好了,中断的硬件基础就聊到这里。这些概念搞清楚了,后面讲Linux中断子系统的实现时,你就能理解为什么代码要那么写了。