Linux驱动设计—— 中断与时钟

中断和时钟技术可以提升驱动程序的效率

中断

中断在Linux中的实现

通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的。所以程序员只要保证申请了正确的中断号及编写了正确的中断处理函数即可。

中断的宏观分类

1.硬中断

  由系统硬件产生的中断。系统硬件通常引起外部事件。外部事件事件具有随机性和突发性,因此硬件中断也具有随机性和突发性。

2.软中断

  软中断是执行中断指令时产生的。软中断不用外设施加中断请求信号,因此软中断的发生不是随机的是程序安排好的。汇编程序中软中断指令int n,n必须是中断向量。

  处理器接收软中断有两个来源:(1)处理器执行到错误的指令代码;(2)软件产生中断,如进程的调度就是使用的软中断。

中断产生的位置分类

1.外部中断

  外部中断一般是由计算机外设发出的中断请求,如键盘中断、定时器中断等。外部中断是可以通过编程方式给予屏蔽的。

2.内部中断

  内部中断指因硬件出错(如突然断电、奇偶校验错等)或运算出错(除数为0、运算溢出、单步中断等)所引起的中断。内部中断是不可屏蔽的中断。通常情况下,大多数内部中断由Linux内核进行了处理,所以驱动程序员不需要关心这些问题。

同步和异步中断

1.同步中断

  同步中断是指令执行的过程中由CPU控制的,CPU在执行完一条指令后才发出中断。也就是说,在指令执行的过程中,即时有中断的到来,只要指令还没执行完,CPU就不会去执行该中断。同步中断一般是因为程序错误所引起的,例如内存管理中的缺页中断,被0除出错等。当CPU决定处理同步中断时,会调用异常处理函数,使系统从错误的状态恢复过来。当错误不可恢复时,就会死机会蓝屏。

2.异步中断

  异步中断是由硬件设备随机产生的,产生中断时并不考虑与处理器时钟同步问题,该类型的中断时可以随时产生。例如在网卡驱动程序中,当网卡接收到数据包后,会向CPU发送一个异步中断事件,表示数据到来,CPU并不知道何时将接收该事件。异步中断的中断处理函数与内核的执行顺序是异步执行的,两者没有必然的联系,也不会互相影响。

中断的实现过程

中断的实现过程较为复杂,涉及中断信号线、中断控制器等概念。

1.中断信号线(IRQ)

 中断信号线是对中断输入线和中断输出线的统称。中断输入线是指接收中断信息的引脚。中断输出线是指发送中断信息的引脚。每一个能够产生中断的外设都有一条或者多条中断输出线(简称IRQ),用来通知处理器产生中断。

2.中断控制器

 中断控制器位于ARM处理器核心和中断源之间。外部中断源将中断发送到中断控制器。中断控制器根据优先级进行判断,然后通过引脚将中断请求发送给ARM处理器核心。

 

  当外部中断同时产生中断时,中断优先级产生逻辑会判断哪一个中断将被执行。中断屏蔽寄存器:当 屏蔽位为0表示对应的中断可以正常执行,否则对应的中断被禁止。

中断处理过程

  

中断的安装与释放

当设备需要中断功能时,应该安装中断。如果驱动程序员没有通过安装中断的方式通知Linux内核需要使用中断,那么内核只会简单的应答并且忽略该中断。

1.申请中断线

 申请中断线可以使内核指导外设应该使用哪一个中断号,哪一个中断处理函数。

 函数实现:kernel/irq/Manage.c

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.释放中断线 kernel/irq/Manage.c

void free_irq(unsigned int irq, void *dev_id)
{
	kfree(__free_irq(irq, dev_id));
}

按键中断实例

时钟机制

Linux驱动程序中经常会使用一些时钟机制,主要是用来延时一段时间。在这段时间内硬件设备可以完成相应的工作。

时间度量

一个与时钟中断相关的全局变量HZ。时钟中断是由系统定时硬件以周期性的间隔产生,这个周期性的值由HZ来表示。

HZ一般被定义为1000,表示一秒钟时钟中断发生1000次。每当时钟中断发生时,内核内部计数器的值就会加上1。内部计数器由jiffies变量表示,当系统初始化时,这个变量被设置为0。

时间延时

C语言中,经常使用sleep()函数将程序延时一段时间,这个函数能够实现毫秒级的延时。在设备驱动程序中,很多对设备的操作也需要延时一段时间,使设备完成某些特定的任务。

Linux内核中,两种常见的延时技术

1.短时延时

当设备驱动程序需要等待硬件处理的完成时,会主动地延时一段时间。这个时间一般是几十毫秒,甚至更短的时间。例如,驱动程序向设备的某个寄存器写入数据时,由于寄存器的写入速度较慢,所以需要驱动程序等待一定的时间,然后继续执行下面的工作。

static inline void ndelay(unsigned long x);
static inline void udelay(unsigned long usecs);
static inline void msleep(unsigned int msecs);

2.长时延时

长时延时实现一般是比较当前jiffies和目标jiffies的值。长时延时可以使用忙等待来实现。

延时3秒钟的实例:

unsigned long timeout = jiffies + 3*HZ;
while(time_before(jiffies, timeout));

time_before宏简单的比较两个时间值得大小。如果参数1<参数2,返回true。

To be continue...

时间: 2024-11-05 16:34:21

Linux驱动设计—— 中断与时钟的相关文章

linux驱动之中断方式获取键值

linux驱动之中断方式获取键值 ------------------------------------------------------------------------------------------------------------------------------------------------------ 回想在单片机下的中断处理 分辨是哪个中断 调用处理函数 清中断 --------------------------------------------------

Linux驱动设计——内存与IO访问

名词解释 内存空间与IO空间 内存空间是计算机系统里面非系统内存区域的地址空间,现在的通用X86体系提供32位地址,寻址4G字节的内存空间,但一般的计算机只安装256M字节或者更少的内存,剩下的高位内存就被用于PCI或者AGP及系统桥设备的使用上面,主机可以像访问系统内存一样访问这些高端内存,这样对于扩展的设备有更大的空间. Linux用户空间与内核空间 IO空间是X86系统上面的专用空间,现在的IO空间大小是64K字节,从0x0000到0xffff,可以供设备使用,比如南桥很多的设备就是挂在I

Linux驱动设计——并发控制

四种并发控制机制:原子操作.自旋锁.信号量和完成量. 原子变量操作 原子变量操作绝对不会再执行完毕前被任何其他任务或事件打断.原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树中的include/asm/atomic.h文件中,它们都是使用汇编语言实现的. 常用于多个应用程序对同一个共享的值进行操作的情况. 自旋锁 自旋锁是实现信号量和完成量的基础.对资源有很好的保护作用. Linux系统中提供了一些锁机制来避免竞争条件,最简单的一种就是自旋锁.引入锁的机制是因

Linux驱动设计—— 驱动调试技术

参考博客与书籍: <Linux设备驱动开发详解> <Linux设备驱动程序> http://blog.chinaunix.net/uid-24219701-id-2884942.html 对于驱动程序设计来说,核心问题之一就是如何完成调试.当前常用的驱动调试技术可分为: 1. 打印调试 printk 重定向控制台消息 消息记录 开启和关闭消息速度限制 打印设备编号 2. 调试器调试 gdb kdb内核调试器 kgdb补丁 3. 查询调试 使用/proc文件系统 ioctl方法 4.

Linux驱动设计编译错误信息集锦

1.warning: passing argument 2 of 'request_irq' from incompatible pointer type http://blog.sina.com.cn/s/blog_7321be1101012gek.html 今天在些key的driver的时候...写完了编译出现一个warmming如下:warning: passing argument 2 of 'request_irq' from incompatible pointer type 我的r

Linux驱动设计——阻塞和同步

阻塞和非阻塞是设备访问的两种基本方式,阻塞和非阻塞驱动程序使用时,经常会用到等待队列. 阻塞和非阻塞 阻塞调用是指调用结果返回之前,当前线程会被挂起.函数只有得到结果之后才会返回.而对于同步调用来说,许多时候当前线程还是激活的,只是逻辑上当前函数没有返回而已. 非阻塞指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回. 完整实例程序分析 等待队列 等待队列机制使等待的进程暂时睡眠,当等待的信号到来时,便唤醒等待队列中进程继续执行. 等待队列的基本数据结构是一个双向链表,这个链表可以存

linux驱动之i2c子系统device注册driver注册简单分析

Linux 驱动设计主要是根据分层分离思想,i2c子系统分为i2cocre.adapter.及device_driver层,其实adapter也是个device,只不过是我们主控芯片的I2C控制接口而已,我们的主控芯片有几个I2C接口就有几个adapter; i2ccore这一层linux已经帮我们实现,主要的工做是类似platform总线的作用,负责drvier及设备的注册,相比platform多了个adapter的注册管理工作,以及i2c的数据发送接收等等算法,说算法有点夸大,其实就是按照i

《Linux内核设计与实现》读书笔记(八)- 中断下半部的处理

在前一章也提到过,之所以中断会分成上下两部分,是由于中断对时限的要求非常高,需要尽快的响应硬件. 主要内容: 中断下半部处理 实现中断下半部的机制 总结中断下半部的实现 中断实现示例 1. 中断下半部处理 那么对于一个中断,如何划分上下两部分呢?哪些处理放在上半部,哪些处理放在下半部? 这里有一些经验可供借鉴: 如果一个任务对时间十分敏感,将其放在上半部 如果一个任务和硬件有关,将其放在上半部 如果一个任务要保证不被其他中断打断,将其放在上半部 其他所有任务,考虑放在下半部 2. 实现中断下半部

Linux kernel中断子系统之(五):驱动申请中断API

一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的驱动的时候,如何向Linux Kernel中的中断子系统注册中断处理函数?为了理解注册中断的接口,必须了解一些中断线程化(threaded interrupt handler)的基础知识,这些在第二章描述.第三章主要描述了驱动申请 interrupt line接口API request_threaded_irq的规格.第四章是进入request_threaded_irq的实现细节,分析整个代码的执行过程. 二.和中断相关的lin