中断分为两个部分:中断顶部(top half)和中断底半部(bootom half)
一、中断顶部(top half)
中断上半部需要处理一下三种情况:
1,如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
2,如果一个任务和硬件相关,将其放在中断处理程序中执行。
3,如果一个人物要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中 执行。
4,其他所有任务,考虑放在中断底半部去执行。
一下代码都是基于s5p6818开发平台按键实验
头文件<linux/interrupt.h>
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, \
const char *name,void *dev);
功能:向内核请求注册中断
参数:
@irq 中断号
gpio_to_irq()
@handler 中断处理函数指针
typedef irqreturn_t (*irq_handler_t)(int , void *); 函数指针类型
irqreturn_t 返回值类型是枚举类型
IRQ_NONE 没有处理
IRQ_HANDLED 已经处理完成
irqreturn_t irq_handler(int irq,void*args)
{
}
@flags 中断标志
中断的触发方式(中断标志中的一种):
IRQF_TRIGGER_RISING 上升沿触发
IRQF_TRIGGER_FALLING 下降沿触发
IRQF_TRIGGER_HIGH 高电平触发
IRQF_TRIGGER_LOW 低电平触发
IRQF_DISABLED 屏蔽同级别中断
IRQF_SHARED 中断共享
@name 中断名字
@dev 私有数据
返回值:成功返回0,失败返回负数错误码
void free_irq(unsigned int, void *);
下方代码是在s5p6818开发平台上进行的按键中断
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#define GPIOA28 28
#define NAME "key_gpioa28"
int irqno = 0;
irqreturn_t irq_handler(int irqno, void *args)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
return IRQ_HANDLED;
}
int __init key_int_init(void)
{
int ret = 0;
irqno = gpio_to_irq(GPIOA28);
ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
NAME, NULL);
if(ret < 0){
printk(KERN_ERR "request_irq failed...\n");
return ret;
}
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
return 0;
}
void __exit key_int_exit(void)
{
free_irq(irqno,NULL);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");
二、中断底半部(top half)
【1】软中断
特点:可以被中断(顶半部)打断,不可以被中断底半部打断,不参与进程调度
要求:可以有耗时操作(相对来将) —>>> 可以使用for ,不可以使用延时和睡眠函数
void open_softirq(int nr, void (*action)(struct softirq_action *))
void raise_softirq(unsigned int nr)
【2】tasklet tasklet依赖软中断实现
特点:可以被中断(顶半部)打断,不可以被中断底半部打断,不参与进程调度
要求:可以有耗时操作(相对来将) —>>> 可以使用for ,不可以使用延时和睡眠函数
数据类型:
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long),unsigned long data);
功能:初始化tasklet
参数:
@t tasklet结构体指针
@func 中断底半部处理函数
@data 私有数据
void tasklet_schedule(struct tasklet_struct *t)
功能:调度tasklet底半部
参数:
@t tasklet结构体指针
实验代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#define GPIOA28 28
#define NAME "key_gpioa28"
int irqno = 0;
struct tasklet_struct task;
void task_func(unsigned long args)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
irqreturn_t irq_handler(int irqno, void *args)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
tasklet_schedule(&task);
return IRQ_HANDLED;
}
int __init key_int_init(void)
{
int ret = 0;
irqno = gpio_to_irq(GPIOA28);
ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
NAME, NULL);
if(ret < 0){
printk(KERN_ERR "request_irq failed...\n");
return ret;
}
tasklet_init(&task,task_func,0);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
return 0;
}
void __exit key_int_exit(void)
{
free_irq(irqno,NULL);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");
【3】工作队列
特点:可以被中断(顶半部)打断,也可以被中断底半部打断,也参与进程调度
要求:可以有耗时操作,也可以有涉及进程调度相关函数
<linux/workqueue.h>
INIT_WORK(_work, _func)
功能:初始化工作
参数:
@_work struct work_struct 指针
struct work_struct
{
atomic_long_t data;
work_func_t func;
};
@_func 工作队列底半部处理函数
typedef void (*work_func_t)(struct work_struct *work);
int schedule_work(struct work_struct *work);
功能:工作队列调度工作底半部处理函数
参数:
@work struct work_struct 指针
create_workqueue(name)
功能:创建工作队列
参数:
@name 名字
返回值:返回struct workqueue_struct结构体指针
int queue_work(struct workqueue_struct *wq, struct work_struct *work);
功能:将工作添加在工作队列里
参数:
@wq 工作队列结构体
@work 工作结构体
第一种方法
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#define GPIOA28 28
#define NAME "key_gpioa28"
int irqno = 0;
struct work_struct work;
struct workqueue_struct *work_queue;
void work_func(struct work_struct *work)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
irqreturn_t irq_handler(int irqno, void *args)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
queue_work(work_queue, &work);
return IRQ_HANDLED;
}
int __init key_int_init(void)
{
int ret = 0;
irqno = gpio_to_irq(GPIOA28);
ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
NAME, NULL);
if(ret < 0){
printk(KERN_ERR "request_irq failed...\n");
return ret;
}
work_queue = create_workqueue("key_work_queue");
INIT_WORK(&work,work_func);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
return 0;
}
void __exit key_int_exit(void)
{
free_irq(irqno,NULL);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");
第二种方法
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#define GPIOA28 28
#define NAME "key_gpioa28"
int irqno = 0;
struct work_struct work;
struct workqueue_struct *work_queue;
void work_func(struct work_struct *work)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
irqreturn_t irq_handler(int irqno, void *args)
{
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
queue_work(work_queue, &work);
return IRQ_HANDLED;
}
int __init key_int_init(void)
{
int ret = 0;
irqno = gpio_to_irq(GPIOA28);
ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
NAME, NULL);
if(ret < 0){
printk(KERN_ERR "request_irq failed...\n");
return ret;
}
work_queue = create_workqueue("key_work_queue");
INIT_WORK(&work,work_func);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
return 0;
}
void __exit key_int_exit(void)
{
free_irq(irqno,NULL);
printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");
内核提供的延时机制:
1.中断底半部
2.定时器
3.延时函数和睡眠函数(delay.h)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)