linux中断及其底半部-s5p6818开发平台

中断分为两个部分:中断顶部(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() //将GPIO号转化成中断号
            @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);    //通过gpio号获取中断号
	/*向内核请求注册中断*/
	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;

/*由tasklet实现的中断底半部处理函数*/
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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值