Chinaunix首页 | 论坛 | 博客
  • 博客访问: 844638
  • 博文数量: 321
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 936
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-23 11:25
文章分类

全部博文(321)

文章存档

2017年(1)

2016年(10)

2015年(61)

2014年(187)

2013年(62)

分类: 嵌入式

2013-03-07 22:42:12

中断指CPU在执行程序的过程中,出现了某些突发事件时CPU必须暂停执行当前的程序,转去处理突发事件,处理完毕后CPU又返回原程序被中断的位置并继续执行。

二、中断分类:

a) 外部中断(手册E开头的,或引出一个引脚) VS 内部中断(CPU内部的一个控制模块

b) 可屏蔽中断 (一般都有maskVS 不可屏蔽中断

c) 向量中断(中断向量表) VS 非向量中断  =P190 向量:不同的中断号,非向量:同一个入口地址,再由软件判断是具体哪个中断。

三、中断上半部和下半部

上半部:紧急操作。

A.实际响应中断例行

B.用request_irq注册的中断例程

C.它在很短的时间内完成

下半部:非紧急

被顶半部调用,并在稍后更安全的时间内执行。

四、为设备实现一个中断包含两个步骤:

   1.向内核注册中断

    2.实现中断处理函数

  五、

Q: 什么是中断处理程序,有何特别之处?

A: 中断处理程序就是普通的C代码。唯一特别的地方是中断处理程序是在中断时间内 运行的,它的行为要受某些限制:

1处理程序不能向用户空间发送或接受数据,因为它不属于任何进程的上下文。

2不能使用可能引起阻塞的函数。

六、软中断和硬中断:

硬中断:外部设备对CPU的中断;

软中断:通常是硬中断服务程序对内核的中断,而信号则是由内核(或其他进程)对某 个进程的中断。

中断底半部机制:

一、Tasklet

二、工作队列

三、软中断

中断共享:

在中断到来时,所有共享此中断的处理函数都会被执行,在中断处理程序顶半部中,应迅速得根据硬件寄存器中的信息比照传入的dev_id参数判断是否是本设备的中断,若不是,应迅速返回。

代码:

1、定义:struct work_struct my_key;

2、申请中断:

if((result=request_irq(keyIrqArray[0], (void  *)key1_interrupt,IRQ_TYPE_EDGE_FALLING,  "KEY1", NULL)) !=0)

工作队列:INIT_WORK(&(globalmem_devp->my_key),(void *)key2_do_tasklet);// 始化等待队列

3中断处理函数

A.无上下半部机制

irqreturn_t key1_interrupt(int irq,void *dev_id,struct pt_regs *regs)

{

printk("The KEY1 is pressed...!\n");

//tasklet_schedule(&key1_tasklet);

keyvalue = 1;

keyflag = 1;

globalmem_devp->current_len = 4;

return 0;

}

B.工作队列schedule_work(&globalmem_devp->my_key);

C.tasklet==tasklet_schedule(&key3_tasklet);

4声明绑定==》对tasklet

DECLARE_TASKLET(key3_tasklet,key3_do_tasklet,0);

5执行函数: void key2_do_tasklet(unsigned long data)

6释放中断free_irq(keyIrqArray[0], NULL);

 

 

软中断和tasklet仍然运行于中断上下文,而工作队列则运行于进程上下文。因此,软中断和tasklet处理函数中不能睡眠(中断函数里面不能阻塞,或者睡眠),但是工作队列函数可以允许睡眠。

总结:顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操作。Tasklet和工作队列都是调度中断底半部的良好机制,tasklet基于软中断实现。内核定时器也是依靠软中断来实现的。

定时器:通过修改expires的值来改变定时器到来的时间值globalmem_devp->s_timer,mod_timer(&globalmem_devp->s_timer,jiffies+HZ);

一、linux通过时钟中断来确定时间间隔。时钟中断的发生频率为HZ=100,不同的体系 即每秒产生的定时中断次数。

jiffies值就是自linux启动后的时钟滴答的次数.即记录了自最近一次LINUX启动后到当前的时间间隔===中断发生的次数。

二、S3C2410RTC可产生两种中断:周期节拍(tick)中断和报警(alarm)中断。前者相当于一个周期性的定时器,后者相当于一个闹钟,它在预先设定的时间到来时产生中断。

三、定时器用于控制某函数(定时器处理函数)在未来某个特定时间执行。内核定时器注册的处理函数只执行一次--不是循环执行的

四、由于我们在第一次中断处理函数中,修改了(不断的设置)定时器到来的时间的值,即mod_timer(&globalmem_devp->s_timer(定时器),jiffies+HZ(expires));,即通过新的被-传入的expires到来后,才会执行定时器函数。

五、为了防止因jiffies溢出导致的问题,最好使用宏比较

#include ===========忙等待函数

a) void udelay(unsigned long usecs);

b)  void ndelay(unsigned long nsecs); 

c)  void mdelay(unsigned long msecs); 

d) time_before(jiffies,delay)

在定时器处理函数中,在做完响应的工作后,往往会延后expires并将定时器再次添加到内核定时器链表,仪表定时器能再次触发。

五、代码:

1、定义: struct timer_list s_timer;//设备要使用的定时器

atomic_t counter;//一共经历了多少秒

2、初始化定时器:

a)  init_timer(&globalmem_devp->s_timer);

b)  globalmem_devp->s_timer.function = &second_timer_handle;

c)  globalmem_devp->s_timer.expires = jiffies+HZ;

3、添加到内核:

a) add_timer(&globalmem_devp->s_timer);

b) atomic_set(&globalmem_devp->counter,0);//计数器清零

4、实现中断处理函数:

a)  mod_timer(&globalmem_devp->s_timer,jiffies+HZ);

b)  atomic_inc(&globalmem_devp->counter);

5、释放函数

del_timer(&globalmem_devp->s_timer);

总结:内核中的延时是忙等待或者睡眠等待,为了充分利用CPU资源,使系统有更好的吞吐性能,在对延迟时间的要求并不是很精确的情况下,睡眠等待同城是值得推荐的。。

忙等待延时:长延时---time_beforetime_after()====类似于while(n--);

睡着延时:睡着延时在等待的时间到来之间出去睡眠状态,CPU资源被其他进程使用。

内核定时器与tasklet比较

相同点:

1、在中断期间运行;

2、始终会在调度的同一CPU上运行;

3、软件中断上下文,院子模式运行。

不同点:

1、不能要求tasklet在给定时间执行;

2、软件中断是打开硬件中断的同时执行某些异步任务的一种内核机制。

阅读(1125) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~