姓名:郑煜烁 学号:19029100010 学院:电子工程学院
转自:https://blog.csdn.net/u012142460/article/details/79272207
【嵌牛导读】介绍linux系统中如何对突发事件进行处理
【嵌牛鼻子】中断处理
【嵌牛提问】如何进行中断处理
【嵌牛正文】
一、中断介绍
所谓中断是指CPU在执行程序的过程中,出现了某些突发事件需要紧急处理,CPU必须暂时停止当前的工作,转去执行处理突发事件,处理完毕又返回原程序被中断的位置继续执行。
在ARM多核处理器中最常用的中断控制器是GIC,支持三类中断
1、SGI:Software Generated Interrupt,软件产生的中断,用于多核的核间通信
2、PPI:Private Peripheral Interrupt,某个CPU私有外设的中断,这类外设的中断只能发给绑定的那个CPU
3、SPI:Shared Peripheral Interrupt 共享外设中断,这类外设的中断可以路由到任何一个CPU
在proc/interrupts文件可以获得中断信息。
二 、中断API
看一下常用的中断相关的API函数
1、申请中断
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
功能:申请中断
参数:irq:中断号,这个中断号不是硬件手册上的中断号,而是linux的中断号。
handler:中断处理函数
flags:标志位 #define IRQF_TRIGGER_RISING0x00000001 上升沿触发
#define IRQF_TRIGGER_FALLING0x00000002 下降沿触发
#define IRQF_TRIGGER_HIGH0x00000004 高电平触发
#define IRQF_TRIGGER_LOW 0x00000008 低电平触发 IRQF_SHARED 共享标志,表示该中断可以被多个设备共享
name:中断的名称
dev:要传递给中断服务程序的私有数据,一般设置为这个设备的结构体或者为NULL
返回值:成功返回0,返回-EINVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经占用且不能共享。
2、释放中断
void free_irq(unsigned int irq, void *dev_id)
参数与申请中断中的参数一样。
三、中断上下部机制
中断会打断内核进程中的正常调度,系统对更高吞吐率的追求势必要求中断服务程序尽量短小精悍。但实际上,很多中断程序需要处理很多事务,可能进行大量的耗时操作。
Linux为了解决这个问题,找出一个平衡点,将中断程序分成了两个部分:顶半部和底半部。顶半部处理紧急事务,底半部处理耗时操作。顶半部和底半部最大不同在于,底半部是可以被其他中断打断的,这样就不会耽误其他中断的进行了。
顶半部处理紧急事务,一些中断必须的事务在此处理,比如读中断状态,清中断标志等等,这些都是必要但很简单的工作。在底半部主要处理一些不太紧要的工作,必要数据的处理等等。
尽管上述机制能够改善系统的响应能力,但不能僵化的把所有中断驱动分成两个半部,如果本身处理情况就比较简单,则是完全可以在顶半部来全部完成的。
我们使用tasklet和工作队列来完成顶半部底半部机制
1、tasklet
taskelet实际上是linux中软中断的一种,Linux提供了一系列宏和函数来完成tasklet
DECLARE_TASKLET(name, func, data)
功能:定义一个tasklet对象
参数:name:名称
func:底半部函数
data:传递给底半部函数的参数
DECLARE_TASKLET_DISABLED(name, func, data)
功能和上面类似,但还需要调用task_enable使能一下。
static inline void tasklet_schedule(struct tasklet_struct *tasklet)
功能:将指定的tasklet对象添加的加入到tasklet列表中,要执行底半部函数需要先执行这个函数,一般在顶半部函数执行。
2、工作队列
工作队列的方法也可以实现顶半部底半部机制
struct work_struct {
atomic_long_t data; //传递给工作函数的参数
struct list_head entry;
work_func_t func; //工作函数,可以理解就是底半部函数。
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
工作队列对象结构体。使用工作队列需要首先定义一个工作队列对象
INIT_WORK(_work, _func)
功能:将工作队列与底半部函数绑定。
参数: _work,定义的工作队列
_func,定义的底半部函数,可以简单的理解成将底半部函数赋值给定义的工作队列对象中func变量。
int schedule_work(struct work_struct *work)
功能:将工作队列节点加入到工作队列链表中,和tasklet中的tasklet_schedule函数功能类似,一般在顶半部函数中完成。
参数:work,工作队列对象
3、taskelet与工作队列的异同
两者有什么区别呢?taskelet是在中断上下文来完成的,而中断中是不能进行进程调度的,所以在tasklet的顶半部和底半部都能进行进程的调度。工作队列是处于进程上下文中的,所以底半部是工作队列时,是可以进程进程调度的
在使用时,步骤基本一致,绑定工作队列/tasklet和底半部函数,然后在顶半部中执行schedule函数,执行底半部函数。
实例,在迅为4412开发板上,实现按键中断
原理图如下
我们只拿一个来做例子,UART_RING,看他对应的GPIO口
它对应的是GPIOX1_1
得到中断号有一个API gpio_to_irq(gpio),三星定义了GPIOX1_1的gpio值为EXYNOS4_GPX1(1),这样就可以得到中断号了。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <mach/gpio-exynos4.h>
#define TASKLET;
int irq1;
#ifdef WORK_QUEUE
struct work_struct key_wq; //定义一个工作队列对象
#endif
void key_tasklet_func(unsigned long data);
#ifdef TASKLET
DECLARE_TASKLET(key_tasklet,key_tasklet_func,0); //绑定tasklet对象和函数
#endif
void key_tasklet_func(unsigned long data)
{
printk(KERN_INFO"key_tasklet_func enter...\n");
}
irqreturn_t key_handler(int irq, void *date)
{
printk(KERN_INFO"key1 enter...\n");
#ifdef TASKLET
tasklet_schedule(&key_tasklet); //执行tasklet底半部
#endif
#ifdef WORK_QUEUE
schedule_work(&key_wq); //执行工作队列底半部
#endif
return IRQ_HANDLED;
}
static int __init demo_key_init(void)
{
int ret = 0;
irq1 = gpio_to_irq(EXYNOS4_GPX1(1));
ret = request_irq(irq1,key_handler,IRQF_TRIGGER_FALLING,"KEY222",NULL);
if(ret < 0){
printk(KERN_INFO"request_irq fail...%s,%d,ret:%d\n",__func__,__LINE__,ret);
return -EINVAL;
printk(KERN_INFO"%s,%d\n",__func__,__LINE__);
#ifdef WORK_QUEUE
INIT_WORK(&key_wq,key_tasklet_func); //初始化一个工作队列
#endif
return 0;
}
static void __exit demo_key_exit(void)
{
free_irq(irq1,NULL);
printk(KERN_INFO"%s,%d\n",__func__,__LINE__);
}
module_init(demo_key_init);
module_exit(demo_key_exit);
MODULE_LICENSE("GPL");
————————————————
版权声明:本文为CSDN博主「念念有余」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012142460/article/details/79272207