目录
一、中断简介
二、中断API函数
1.获取中断号相关函数
2.申请中断函数
3.中断释放函数
4.中断处理函数
5.中断使能和禁止函数
三、中断上文与中断下文
1.软中断
2.tasklet
3.工作队列
四、设备树中的中断节点
一、中断简介中断是指 CPU 在执行程序的过程中, 出现了某些突发事件急待处理, CPU 必须暂停当前程序的执行,转去处理突发事件, 处理完毕后又返回原程序被中断的位置继续执行。
由于中断的存在极大的提高了 CPU的运行效率, 但是设备的中断会打断内核进程中的正常调度和运行, 系统对更高吞吐率的追求势必要求中断服务程序尽量短小精悍。
二、中断API函数 1.获取中断号相关函数每个中断都有一个中断号,通过中断号即可区分不同的中断。在 Linux 内核中使用一个 int 变量表示中断号,用到中断号, 中断信息一般写到了设备树里面, 可以通过 irq_of_parse_and_map 函数从 interupts 属性中提取到对应的设备号。
unsigned int irq_of_parse_and_map(struct device_node *dev,int index)
dev: 设备节点
index:索引号, interrupts 属性可能包含多条中断信息,通过 index 指定要获取的信息。返回值:中断号
如果使用 GPIO 的话,可以使用 gpio_to_irq 函数来获取 gpio 对应的中断号
int gpio_to_irq(unsigned int gpio)
gpio: 要获取的 GPIO 编号 返回值: GPIO 对应的中断号
2.申请中断函数在 Linux 内核中要想使用某个中断是需要申请的, request_irq 函数用于申请中断, request_irq 函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。 request_irq 函数会激活(使能)中断,所以不需要手动去使能中断。
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char *name,
void *dev)
irq:要申请中断的中断号 handler:中断处理函数,当中断发生会执行此中断处理函数 flags:中断标志,可以在文件 include/linux/interrupt.h 里面查看所有的中断标志 name:中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字
dev: 如果将 flags 设置为 IRQF_SHARED, dev 用来区分不同的中断,一般情况下将dev 设置为设备结构体, dev 会传递给中断处理函数 irq_handler_t 的第二个参数。 返回值: 0 中断申请成功,负值 中断申请失败,如果返回-EBUSY 表示中断已经被申请了
常用的中断标志:
中断使用完成以后就要通过 free_irq 函数释放掉相应的中断。 如果中断不是共享的,free_irq 会删除中断处理函数并且禁止中断。
void free_irq(unsigned int irq,void *dev)
irq: 要释放的中断号 dev:如果中断设置为共享(IRQF_SHARED),此参数用来区分具体的中断。共享中断只有在释放最后中断处理函数的时候才会被禁止掉
4.中断处理函数使用 request_irq 函数申请中断的时候需要设置中断处理函数
irqreturn_t (*irq_handler_t) (int, void *)
第一个参数:要中断处理函数要相应的中断号
第二个参数:一个指向 void 的指针,是个通用指针,需要与 request_irq 函数的 dev 参数保持一致。用于区分共享中断的不同设备,dev 也可以指向设备数据结构
返回值:irqreturn_t 类型
irqreturn_t 类型定义如下所示:
enum irqreturn {
IRQ_NONE = (0 ;
compatible = "key"; //和驱动进行匹配的
pinctrl - names = "default";
pinctrl - 0 = ; //把引脚的复用关系设置为 GPIO
key - gpio = ; /* KEY0 */
interrupt - parent = ;
interrupts = ; /* 双边沿触发 */
status = "okay";
}
首先使用 pinctrl 和 gpio 子系统把这个引脚设置为了 gpio 功能, 因为在使用中断的时候需要把引脚设置成输入
然后使用 interrupt-parent 和 interrupts 属性来描述中断。 interrupt-parent 的属性值是 gpio1, 要使用 gpio1 这个中断控制器。
interrupts 属性设置的是中断源,里面包含两个cells,这是因为在 gpio1中断控制器里面#interrupt-cells 的值为 2。
第一个 cells:指定中断号,18 表示 GPIO1 组的 18 号 IO。
第一个 cells:中断触发方式, IRQ_TYPE_EDGE_BOTH 表示上升沿和下降沿同时有效, 它定义在文件include/linux/irq.h
所以在设备树里面配置中断的时候只需要俩个步骤即可
①把管脚设置为 gpio 功能 ②使用 interrupt-parent 和 interrupts 属性来描述中断
interrupts指定中断号和触发方式
与中断有关的设备树属性信息:
①#interrupt-cells,指定中断源的信息 cells 个数 ②interrupt-controller,表示当前节点为中断控制器③interrupts,指定中断号,触发方式 ④interrupt-parent,指定父中断,也就是中断控制器