Linux 驱动开发基础---中断实现按键程序--查询方式
作者:
也许
,
2022-05-15 15:29:31
,
所有人可见
,
阅读 183
Linux中断相关知识
arm对异常(中断)处理过程:
1. 初始化:
设置中断源,让它可以产生中断
设置中断控制器(可以屏蔽某个中断,优先级)
设置CPU总开关(使能中断)
2. 执行其他程序:正常程序
3. 产生中断:比如按下按键--->中断控制器--->CPU
4. CPU 每执行完一条指令都会检查有无中断/异常产生
5. CPU发现有中断/异常产生,开始处理。对于不同的异常,跳去不同的地址执行程序。
这地址上,只是一条跳转指令,跳去执行某个函数(地址),这个就是异常向量。
3 4 5都是硬件做的。
6 中断服务程序函数做什么事情?
保存现场(各种寄存器)
处理异常(中断):分辨中断源,再调用不同的处理函数
恢复现场
Linux 对中断处理的演进
1. Linux系统把中断的意义扩展了,对于按键中断等硬件产生的中断,称之为“硬件中断”
相对的,还可以人为地制造中断:软件中断
2. 中断处理原则1:不能嵌套, 防止爆栈
3. 中断处理原则2:越快越好,太慢的话,影响进程调度(时间片轮转)
4. 中断上半部和下半部
当一个中断要耗费很多时间来处理时,它的坏处是:在这段时间内,其他中断无法被处理。换句话说,在这段时间
内,系统是关中断的。怎么办?=====》引入中断上半部和下半部
如果某个中断就是要做那么多事,我们能不能把它拆分成两部分:紧急的、不紧急的?
在handler函数里只做紧急的事,然后就重新开中断,让系统得以正常运行;那些不紧急的事,以后再处理,处理
时是开中断的。 中断下半部的实现有很多种方法:tasklet(小任务)、work queue(工作队列)
5. tasklet:下半部要做的事情耗时不是太长
当下半部比较耗时但是能忍受,并且它的处理比较简单时,可以用tasklet来处理下半部。tasklet是使用
软件中断来实现。工作在在中断上下文,没有进程/线程调度的概念
6. work queue:下半部要做的事情太多并且很复杂,创建一个内核线程调度工作队列
在中断下半部的执行过程中,虽然是开中断的,期间可以处理各类中断。但是毕竟整个中断的处理还
没走完,这期间APP是无法执行的。假设下半部要执行1、2分钟,在这1、2分钟里APP都是无法响应的。
所以,如果中断要做的事情实在太耗时,那就不能用软件中断来做,而应该用内核线程来做:在中断上半部唤醒内
核线程。内核线程和APP都一样竞争执行,APP有机会执行,系统不会卡顿。工作在在进程上下文。
内核线程要去“工作队列”(work queue)上取出一个一个“工作”(work),来执行它里面的函数。
7. 新技术:threaded irq:为每一个中断都创建一个内核线程
在设备树中指定中断
一个外设,它的中断信号接到哪个“中断控制器”的哪个“中断引脚”,这个中断的触发方式是怎样的?
这3个问题,在设备树里使用中断时,都要有所体现。
你要用哪一个中断控制器里的中断? interrupt-parent=<&XXXX>
你要用哪一个中断? interrupts
例如:interrupt-parent = <&gpio>;
interrupts = <160 1>;
代码获取中断
对于platform_device:
一个节点能被转换为platform_device,如果它的设备树里指定了中断属性,那么可以从platform_
device中获得“中断资源”
struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num);
对于I2C设备、SPI设备:
一个I2C设备会被转换为一个i2c_client结构体,中断号会保存在i2c_client的irq成员里
其他设备:
调用of_irq_get获得中断号
对于GPIO:
那么可以使用下面的函数获得引脚和flag:
button->gpio = of_get_gpio_flags(pp, 0, &flags);
bdata->gpiod = gpio_to_desc(button->gpio);
再去使用gpiod_to_irq获得中断号:irq = gpiod_to_irq(bdata->gpiod);