Linux系统中中断控制与实现

本文详细介绍了Linux系统中的中断控制,包括中断的基本概念、中断顶半部和底半部机制,重点讲解了中断顶半部的API函数如request_irq()、disable_irq()等,以及中断底半部的tasklet和工作队列的使用,包括tasklet_schedule()、create_workqueue()等。此外,还讨论了系统定时器和内核定时器timer的实现和应用。
摘要由CSDN通过智能技术生成

目录

一、基本概念

1.中断

2.IRQ---interrupt request

3.ISR---interrupt service routine(中断服务函数)

4.中断工作机制

5.共享中断和重用中断服务函数的区别

6.中断顶半部和中断底半部

二、Linux中断顶半部相关的API函数和宏

1.request_irq()

2.gpio_to_irq()

3.free_irq()

4.disable_irq()

5.disable_irq_nosync()

6.enable_irq()

三、系统定时器

1.msecs_to_jiffies()

2.usecs_to_jiffies()

四、内核定时器timer 

1.核心数据结构

2.相关的函数或对应的宏

2.1 DEFINE_TIMER

2.2 add_timer()

3.使用流程

3.1 静态定义内核时钟

3.2 循环定时触发中断

4.按键中断实现

五、中断底半部----tasklet

1.核心结构体

2.相关函数或宏

2.1 DECLARE_TASKLET

2.2 tasklet_init()

2.3 tasklet_schedule()

2.4 tasklet_disable()

2.5 tasklet_kill()

3.使用流程

六、中断底半部---工作队列

1.共享工作队列

2.私有工作队列

3.私有队列相关API

3.1 create_workqueue()

3.2 destory_workqueue()

4.work

4.1 不指定延时时间的work

4.2 指定延时  delayed_work

5.work相关API

5.1 DECLARE_WORK()

5.2 schedule_work()

5.3 cancel_work_sync()

5.4 普通按键中断+workqueue工作队列+硬件操作

6.delayed_work相关API

6.1 DECLARE_DELAYED_WORK()

6.2 schedule_delayed_work()

6.3 cancel_delayed_work_sync()

6.4 普通按键中断+延时工作队列+硬件操作


一、基本概念

1.中断

        由于I/O操作的不确定因素以及处理器和I/O设备之间的速度不匹配(异常事件),I/O设备可以通过某种硬件信号异步唤醒对应的处理器的响应,这些硬件信号叫做中断。 

2.IRQ---interrupt request

        Linux内核为每个中断线分配一个唯一的中断编号(IRQ)(可以使用gpio_to_irq函数,获取到对应的中断编号),也称为中断请求号。不同的计算机系统分配方式不同的。

3.ISR---interrupt service routine中断服务函数

        系统响应外设的中断处理是通过外设所在的中断线上绑定的中断服务例程(ISR)实现的,也成为中断处理函数、中断服务函数等。

        注意:一个中断线可以绑定一个或多个中断服务例程。多个中断线可以绑定同一个中断服务例程。 

        关键点注意:一个外设只能对应一个中断服务例程。

4.中断工作机制

        当外设发出中断请求时(按键),会通过所在的中断线传递给linux系统,处理器会停止当前的工作,保存断点,然后跳到该中断线所绑定的中断服务函数(ISR),执行相应的中断服务函数。中断服务处理完毕后,处理器再返回到断点继续执行原来的工作。

5.共享中断和重用中断服务函数的区别

        (1)挂载不同中断线上的不同外设,通常使用不同的中断服务例程,无需通过设备参数进行区分。(各个外设中断不同)

        如果这些外设中断服务处理的框架是相同(例如:key1 key2),则可以使用同一个中断服务例程,通过设备参数来区分不同的外设。这个情况不是共享中断,是重用中断服务例程。

        (2)挂载同一个中断线上的不同外设,使用同一个中断服务例程,必须参数来区分不同的外设。此时称为共享中断。(很灵活)

6.中断顶半部和中断底半部

         Linux内核将中断分为顶半部和低半部机制,中断服务例程属于顶半部(核心的事情,不耗费时间),在中断服务例程(顶半部)结束之前可以启动中断底半部机制,将耗时的事务交给中断低半部处理。

        作用:  顶半部通常会立即执行--不允许被打断,时效性更高。

                    而底半部是尽快执行,不能保证立即执行,而是内核择机调度,有机会就执行。

        总结:常用的底半部机制包括:softirq、tasklet、工作队列workqueue

        特点:softirq、tasklet都运行于中断上下文   工作队列运行于进程上下文(tasklet比softirq更好用一些)。

        内核定时器timer作为定时机制,可以用于中断低半部,实现精准的延时功能。(类似:M4端的定时器)

二、Linux中断顶半部相关的API函数和宏

1.request_irq()

头文件:

        #include <linux/interrupt.h>

原型:

        int  request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev_id)

功能:

        注册中断,绑定对应的中断服务函数,并指明中断的中断编号,中断属性,设备参数

参数:

        Irq:指定的中断编号。

        handler:中断服务函数  

        flags:中断属性  指的是触发条件  上升沿或则下降沿  

        name:自定义的属于该中断的设备名 作用:内核会根据这个名字创建/proc/irq/中断编号/name/ 目录spurious这个文件会记录中断发生的次数。

        dev_id:挂在该中断线上的设备的标识符。  共享中断的时候是不能省的。

返回值:

        成功 0   

        失败:负数错误码   -EBUSY表示中断编号已经被占用

源码的基本形式:
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev)
{
	return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

2.gpio_to_irq()

头文件:

        #include  <linux/gpio.h>

原型:

        Int gpio_to_irq(unsigned  gpio)

功能:

        获取指定的GPIO引脚编号的中断编号

参数:

        GPIO:GPIO引脚编号

返回值:

        成功>0  表示对应的中断编号  

        失败 <0

3.free_irq()

头文件

        #include  <linux/interrupt.h>

原型

        void free_irq(unsigned int irq,void *dev_id)  //一般在退出函数里面会使用

功能

        注销指定中断线的指定的设备,取消该设备触发中断

参数

        Irq:代表指定中断线上的中断编号  

        dev_id:挂在该中断线上的设备的标识信息,必须与request_irq保持一致

返回值

        无

4.disable_irq()

头文件

        #include <linux/interrupt.h>

原型

        void disable_irq(unsigned int irq)

功能

        禁止指定的中断线  注意:禁用处理器上的中断线,会阻塞等待该中断线上的中断服务例程,所以不能用于中断上下文。

参数

        Irq: 表示中断线上的中断编号

返回值

        无

内核里面的API函数的原型:
/**
 *	disable_irq - disable an irq and wait for completion
 *	@irq: Interrupt to disable
 *
 *	Disable the selected interrupt line.  Enables and Disables are
 *	nested.
 *	This function waits for any pending IRQ handlers for this interrupt
 *	to complete before returning. If you use this function while
 *	holding a resource the IRQ handler may need you will deadlock.
 *
 *	This function may be called - with care - from IRQ context.
 */
void disable_irq(unsigned int irq)
{
	if (!__disable_irq_nosync(irq))
		synchronize_irq(irq);
}

5.disable_irq_nosync()

头文件

        #include <linux/interrupt.h>

原型

        void disable_irq_nosync(unsigned int irq) --退出函数里面

功能

        禁用一次中断线,不会等待该中断线上的中断服务例程,可以用于中断上下文

参数

        Irq:表示中断线上的中断编号

返回值

        无

内核源码的基本形式
/**
 *	disable_irq_nosync - disable an irq without waiting
 *	@irq: Interrupt to disable
 *
 *	Disable the selected interrupt line.  Disables and Enables are
 *	nested.
 *	Unlike disable_irq(), this function does not ensure existing
 *	instances of the IRQ handler have completed before returning.
 *
 *	This function may be called from IRQ context.
 */
void disable_irq_nosync(unsigned int irq)
{
	__disable_irq_nosync(irq);
}

6.enable_irq()

头文件

        #include <linux/interrupt.h>

原型

        void  enable_irq(unsigned int irq)

功能

        使能处理器上的中断线

参数

        Irq:表示中断线上的中断编号

返回值

        无

三、系统定时器

        Linux系统定时器有硬件定时器,可以设置的频率,频率:1秒内系统定时触发中断的次数,HZ表示。

        如果频率越高,定时时间间隔越小,导致开销和电源的消耗越高。(如果要省电的话,需要降低频率)

        注意:linux系统定时器的计时单位jiffy,  可以理解为:触发中断的周期时长,1s=1jiffy+ 1*HZ,每个滴答之后,jiffy就会加1

1.msecs_to_jiffies()

头文件:

        #include <linux/jiffies.h>

原型:

        unsigned long msecs_to_jiffies(const unsigned int m)

功能:

        将以毫秒为单位的时长转换为以jiffy为单位的时长

参数:

        m:毫秒数

返回值:

        相同时长的jiffy的个数

内核源码的基本形式:
static __always_inline unsigned long msecs_to_jiffies(const unsigned int m)
{
	if (__builtin_constant_p(m)) {
		if ((int)m < 0)
			return MAX_JIFFY_OFFSET;
		return _msecs_to_jiffies(m);
	} else {
		return __msecs_to_jiffies(m);
	}
}

2.usecs_to_jiffies()

头文件

        #include <linux/jiffies.h>

原型

        unsigned long usecs_to_jiffies(const unsigned int m)

功能

        将微

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值