在嵌入式系统领域,中断管理是保障系统实时性与稳定性的核心机制,AT91系列处理器作为Microchip(原Atmel)公司推出的基于ARM架构的微控制器,凭借其丰富的外设接口和灵活的中断控制器设计,在工业控制、物联网设备、消费电子等领域得到广泛应用,本文将围绕AT91Linux中断机制,从硬件架构、软件实现、驱动开发及优化实践等维度展开分析,帮助读者深入理解其工作原理与应用要点。

AT91架构中的中断控制器:AIC的核心作用
AT91处理器的中断管理由高级中断控制器(Advanced Interrupt Controller, AIC)负责,该控制器是连接硬件中断源与CPU中断请求的核心桥梁,AIC支持多达32个可配置的中断源(具体数量因型号而异,如AT91SAM9系列支持32个,AT91RM9200支持64个),每个中断源均可独立配置优先级、触发方式(边沿触发/电平触发)及中断向量。
AIC内部关键寄存器包括:
- 中断向量寄存器(AIC_IVR):存储当前响应中断的服务程序入口地址;
- 中断服务寄存器(AIC_ISR):标识已发生且未处理的中断;
- 中断屏蔽寄存器(AIC_IECR):使能或禁用特定中断源;
- 中断优先级寄存器(AIC_IPR):配置每个中断源的优先级(0-7,0为最高优先级)。
在硬件层面,AIC通过“优先级判决逻辑”实现中断的嵌套处理:当高优先级中断发生时,即使CPU正在处理低优先级中断,也会立即响应高优先级中断,确保关键任务的实时性,AIC支持“中断向量自动跳转”,无需CPU逐个查询中断源,有效降低了中断响应延迟。
Linux内核中的中断处理机制:从硬件到软件的映射
Linux内核通过统一的中断描述符表(Interrupt Descriptor Table, IDT)管理硬件中断,而AT91架构的中断控制器(AIC)作为“中断控制器驱动”的核心,负责将硬件中断信号转换为内核可识别的中断号,其处理流程可分为三个阶段:
中断初始化与注册
系统启动时,AT91中断控制器驱动(如drivers/irq/irq-at91.c)会完成AIC的初始化,包括:
- 配置AIC的基地址、时钟及中断源数量;
- 注册中断控制器到内核,建立硬件中断号与Linux虚拟中断号的映射关系;
- 设置默认中断处理函数(如
handle_level_irq或handle_edge_irq),根据触发方式选择不同的中断处理逻辑。
对于设备驱动开发者而言,需通过request_irq()函数注册中断处理函数,该函数会完成中断号的映射、中断使能及处理函数挂载等操作。

中断响应与上半部处理
当硬件中断发生时,CPU会暂停当前任务,转而执行中断服务例程(ISR),Linux将ISR分为“上半部”和“下半部”:
- 上半部:执行快速、关键的中断处理,如读取中断状态、清除中断标志、发送信号等,要求执行时间尽可能短(通常在几十微秒内),避免阻塞其他中断。
- 下半部:处理耗时较长的非关键任务,如数据拷贝、设备状态更新等,Linux提供多种下半部机制,如软中断(softirq)、任务队列(tasklet)和工作队列(workqueue),开发者可根据实时性需求选择。
以AT91的按键中断为例,上半部仅需读取按键状态并清除AIC的中断标志,而按键事件的具体处理(如输入事件的生成)则通过工作队列(workqueue)在下文执行。
中断释放与资源清理
设备卸载时,需调用free_irq()释放中断资源,包括:
- 禁用对应中断源(清除AIC_IECR中的使能位);
- 从内核中断描述符表中移除处理函数;
- 释放相关的中断处理数据结构。
中断驱动开发实践:以AT91按键中断为例
以下以AT91SAM9G25处理器的按键中断驱动为例,说明中断驱动的开发要点:
硬件初始化
首先在设备树(Device Tree)中配置按键引脚的中断属性,
keys {
compatible = "gpio-keys";
key1 {
gpios = <&pioA 10 GPIO_ACTIVE_LOW>;
linux,code = <KEY_1>;
interrupt-parent = <&aic>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
};
};
interrupts属性指定了中断号(10)和触发方式(下降沿触发),interrupt-parent指向AIC中断控制器。

中断处理函数编写
驱动程序需实现中断处理函数,并在request_irq()中注册:
static irqreturn_t key1_handler(int irq, void *dev_id) {
struct key_device *dev = dev_id;
int state = gpio_get_value(dev->gpio);
input_report_key(dev->input_dev, KEY_1, !state);
input_sync(dev->input_dev);
return IRQ_HANDLED; // 表示中断已处理完成
}
static int key_probe(struct platform_device *pdev) {
// ... 其他初始化代码 ...
ret = request_irq(dev->irq, key1_handler, 0, "key1", dev);
if (ret) {
dev_err(&pdev->dev, "failed to request irqn");
return ret;
}
return 0;
}
关键点:
- 中断处理函数需快速返回,避免耗时操作;
- 通过
input_report_key上报按键事件后,调用input_sync同步事件; - 返回值
IRQ_HANDLED表示中断已处理,IRQ_NONE表示中断源非本驱动。
中断共享与去抖处理
若多个设备共享同一中断(如多个按键共用一个中断线),需在request_irq()中设置IRQF_SHARED标志,并在处理函数中通过dev_id区分设备,机械按键的抖动可能导致中断误触发,可通过两种方式去抖:
- 硬件去抖:在按键电路中添加RC滤波电路;
- 软件去抖:在中断处理函数中启动定时器,延迟10-20ms后再次检测按键状态,确认稳定后再触发事件。
中断优化与常见问题
中断优化策略
- 优先级配置:通过AIC_IPR合理配置中断优先级,确保高实时性任务(如通信接口)优先响应;
- 中断负载均衡:在多核系统中,通过
irqbalance工具或手动将中断绑定到特定CPU核心,避免单一核心过载; - 延迟降低:禁用非必要的中断(如调试串口中断)、使用“中断合并”(如DMA批量处理数据)减少中断次数。
常见问题及解决方案
- 中断丢失:可能因中断处理函数耗时过长导致后续中断被丢弃,需优化中断处理逻辑,将耗时操作移至下半部;
- 中断不响应:检查AIC_IECR是否使能对应中断、中断触发方式是否与硬件匹配(如边沿触发 vs 电平触发)、设备树配置是否正确;
- 中断风暴:硬件故障(如信号线抖动)或驱动逻辑错误(如未清除中断标志)可能导致大量中断,可通过中断计数器定位问题,并在驱动中添加中断限流机制。
FAQs
Q1:AT91Linux中如何配置中断优先级?
A:通过AIC的优先级寄存器(AIC_IPR)配置,每个中断源对应一个32位寄存器(低8位为优先级,0为最高),在Linux驱动中,可通过irq_set_irq_priority()函数设置,例如irq_set_irq_priority(irq_num, 1)将中断优先级设为1(低于0但高于2-7),需注意,内核要求高优先级中断号数值更小,且优先级配置需在request_irq()之前完成。
Q2:中断处理函数中为什么不能调用睡眠函数(如msleep)?
A:中断处理函数运行于中断上下文(interrupt context),此时内核不允许调度进程切换(睡眠函数会导致进程阻塞,触发调度),若需执行耗时操作,应使用下半部机制(如工作队列schedule_work())或定时器,将任务延迟到进程上下文中执行,在中断处理函数中创建工作队列,由内核线程在安全环境下执行耗时逻辑。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/54564.html