1. 中断处理基础

1.1 中断概念与分类

中断(Interrupt)是嵌入式系统中CPU与外部设备异步通信的核心机制。当外设需要CPU关注时,通过硬件信号线向CPU发送中断请求,CPU暂停当前任务,转去执行中断服务程序(ISR),处理完成后返回断点继续执行。

核心要点:中断避免了CPU轮询外设状态带来的性能浪费,是实现低延迟、高吞吐驱动的基础。
分类维度 类型 说明
触发方式 电平触发 / 边沿触发 电平触发持续有效直到被清除;边沿触发仅在信号跳变时产生
硬件来源 IRQ / FIQ ARM架构中FIQ优先级更高,有独立寄存器组
软件角度 硬中断 / 软中断 硬中断由外设硬件产生;软中断由软件指令(如SWI)触发
可屏蔽性 可屏蔽中断 / 不可屏蔽中断(NMI) 可屏蔽中断可通过CPU标志位关闭;NMI用于紧急事件
中断分类体系图 中断分类 硬件中断 软件中断 异常 IRQ FIQ SWI 数据中止 未定义 注:ARM Cortex-A 系列支持 IRQ 和 FIQ 两种硬件中断模式,FIQ 拥有更高优先级和专用寄存器

1.2 中断向量表

中断向量表(Interrupt Vector Table, IVT)是存储在固定内存地址的跳转表,每个中断源对应一个表项,存放该中断的服务程序入口地址。CPU响应中断后,自动根据中断号从向量表中取出地址并跳转执行。

架构 向量表基址 表项大小 特点
ARM Cortex-M 0x00000000(可重定位) 4字节/项 向量表包含堆栈指针初始值,支持中断嵌套
ARM Cortex-A 0xFFFF0000 / 0x00000000 4字节/项 通过CP15协处理器配置向量基址
x86 实模式 0x00000;保护模式 IDTR 8字节/项 中断描述符表(IDT)支持任务门、中断门、陷阱门
RISC-V mtvec / stvec 寄存器指定 4字节/项 支持直接模式和向量模式
ARM Cortex-M 中断向量表结构 中断向量表(基址 0x00000000) 0x00: 初始SP值 0x04: Reset_Handler 0x08: NMI_Handler 0x0C: HardFault_Handler 0x10: MemManage 0x14: BusFault 0x18: UsageFault 0x1C~: 外部中断向量 复位后SP自动加载 复位后PC跳转

1.3 中断上下文

中断上下文(Interrupt Context)是指CPU在执行ISR期间所处的特殊运行环境。与进程上下文不同,中断上下文不可睡眠、不可调度、不可访问用户空间。

对比项 进程上下文 中断上下文
可睡眠 是(通过schedule()) 否(内核会触发BUG)
可被抢占 是 否(除非中断嵌套)
访问用户空间 是 否(current指针不可靠)
持有锁 普通锁 / 互斥锁 仅限 spinlock(自旋锁)
栈空间 进程内核栈(通常8KB) 中断栈(独立或借用内核栈)
in_interrupt() 返回0 返回非0
常见陷阱:在中断上下文中调用 kmalloc(GFP_KERNEL) 会导致睡眠,应使用 GFP_ATOMIC 标志。同样,mutex_lock() 在中断上下文中绝对禁止使用。
中断上下文 vs 进程上下文 进程上下文 可睡眠 可抢占 访问用户空间 使用互斥锁 中断上下文 不可睡眠 不可抢占 禁止访问用户空间 仅自旋锁 ⚡

1.4 中断处理流程概述

一个完整的中断处理流程从硬件信号产生到ISR执行完毕,通常经历以下阶段:

  1. 外设触发:外设硬件将中断请求信号拉高(电平触发)或产生跳变(边沿触发)。
  2. 中断控制器仲裁:GIC(Generic Interrupt Controller)或APIC等中断控制器对多个中断源进行优先级裁决,向CPU发送IRQ信号。
  3. CPU保存现场:CPU自动保存当前程序状态寄存器(CPSR)、返回地址(LR)到对应模式栈,并切换到中断模式。
  4. 向量表查表:CPU根据中断号从向量表中读取ISR入口地址,跳转执行。
  5. ISR执行:执行中断服务程序,完成必要的硬件操作(如读取数据、清除中断标志)。
  6. 恢复现场与返回:执行中断返回指令(如ARM的MOVS PC, LR),恢复CPU状态,继续执行被中断的任务。
中断处理完整流程图 ① 外设触发中断 ② 中断控制器仲裁 ③ CPU保存现场 ④ 向量表查表跳转 ⑤ ISR执行 关键寄存器变化 • LR 保存返回地址 • SPSR 保存CPSR • PC 跳转到ISR入口

1.5 Linux内核中断处理机制

Linux内核将中断处理分为上半部(Top Half)和下半部(Bottom Half)两部分,以平衡实时性与吞吐量:

特性 上半部(硬中断) 下半部(软中断 / Tasklet / Workqueue)
执行时机 中断触发后立即执行 硬中断结束后,在安全时机执行
中断使能 默认关闭本地中断 中断已使能,可被抢占
执行时间 必须极短(微秒级) 可稍长(毫秒级)
典型操作 清除中断标志、拷贝硬件寄存器 协议解析、数据分发、唤醒等待队列
API注册 request_irq() tasklet_init() / INIT_WORK()
驱动调优建议:对于高频中断(如网络收包、DMA完成),尽量将非紧急处理下沉到下半部,上半部只做最小必要操作。使用 IRQF_TIMER 标志可告知内核该中断为定时器类型,获得特殊调度优化。
Linux 中断上下半部处理模型 上半部(Top Half) • 关中断执行 • 仅做硬件ACK + 数据拷贝 • 触发下半部 调度 下半部(Bottom Half) • 开中断执行 • 协议处理 / 数据分发 • 可睡眠(Workqueue) 软中断(SoftIRQ) Tasklet Workqueue 注:软中断在 do_softirq() 中执行,Tasklet 基于软中断实现,Workqueue 运行在进程上下文

1.6 中断处理中的关键数据结构

Linux内核使用 irq_desc 结构体管理每个中断号的状态与回调函数,驱动开发者通过 request_irq() 注册中断处理函数:

// 注册中断处理函数原型
int request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long flags,
                const char *name,
                void *dev_id);

// 中断处理函数原型
irqreturn_t handler(int irq, void *dev_id);

// 返回值宏
#define IRQ_NONE      (0)  // 未处理
#define IRQ_HANDLED   (1)  // 已处理
#define IRQ_WAKE_THREAD (2) // 唤醒中断线程
参数调优要点:
  • flags 中的 IRQF_TRIGGER_RISING/FALLING/HIGH/LOW 必须与硬件电气特性匹配,否则导致中断丢失或误触发。
  • IRQF_SHARED 标志允许多个驱动共享同一中断线,但所有共享驱动必须支持该模式。
  • dev_id 在共享中断中用于区分设备,必须唯一且非NULL。

1.7 中断延迟与性能指标

中断延迟(Interrupt Latency)是衡量系统实时性的关键指标,直接影响驱动性能:

指标 定义 典型值(嵌入式Linux) 影响因素
中断响应延迟 从硬件触发到ISR第一条指令执行 1~10