打印

嵌入式系统中如何编写中断处理程序ISR

[复制链接]
321|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
前一篇博客解密了中断系统,下面我介绍一下如何编写中断服务程序。



中断处理系统结构

irqaction数据结构中包含了对应于此中断处理的相关信息,包括中断处理例程的地址,此中断所属的模块名称,以及是否允许共享的标志位,如果允许共享next成员将指向共巷此中断号的下一个irqaction的结构指针等。

中断发生时Linux首先读取系统可编程中断控制器中中断状态寄存器判断出中断源,将其转换成irq_action数组中偏移值。

根据中断号找到相应的irqaction后,内核是凭借 handler指针调入驱动程序的ISR,在此使用循环的意义是如果此中断号被多个ISR共享,可以依次遍历每一个注册的ISR,使它得到一次执行的机会。



注册中断处理函数

int request_irq(unsigned int irq, void (*handler)(int irq,void dev_id,struct pt_regs *regs), unsigned long flags, const char *device, void *dev_id)

参数irq表示所要申请的硬件中断号。Handler是向系统登记的中断处理子程序,中断产生时由系统来调用,调用时所带参数irq为中断号,dev_id为申请时告诉系统的设备标识,regs为中断发生时寄存器内容。device为设备名,将会出现在/proc/interrupts文件里。flag是申请时的选项,它决定中断处理程序的一些特性,其中最重要的是中断处理程序是快速处理程序(flag里设置了SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT),快速处理程序运行时,所有中断都被屏蔽,而慢速处理程序运行时,除了正在处理的中断外,其它中断都没有被屏蔽。

Linux内核中注销一个中断处理的函数:

void free_irq(unsigned int irq, void *dev_id)



中断标志flags

中断标志flags可以设置为:

SA_INTERRUPT。如果设置该位,就指示这是一个"快速"中断处理程序,如果清除这位,那么它就是一个"慢速"中断处理程序。

SA_SHIRQ 该位表明中断可以在设备间共享。共享的概念在稍后的"中断共享"一节中介绍。

SA_SAMPLE_RANDOM 该位表明产生的中断对/dev/random和/dev/urandom设备要使用的熵池(entropy pool)有贡献。读这些设备返回真正的随机数,它们用来帮助应用软件选取用于加密的安全钥匙。这些随机数是从一个熵池中取得的,各种随机事件都会对系统的熵池(无序度)有贡献。如果希望设备真正随机地产生中断,应该置上这个标志。而如果的中断是可预测的(例如,帧捕捉卡的垂直消隐),那就不值得设置这个标志位-它对系统的熵池没有任何贡献。



ISR上下文

当进程发出一个系统调用的请求时,由应用态切换到内核态。这样的内核控制路径被成为进程内核路径,也叫进程上下文。当CPU执行一个与中断有关的内核控制路径的时候,被成为中断上下文。中断的上半部和下半部都属于ISR上下文。



tasklet是一种特殊的软中断机制,它可以被多次调度运行。Linux内核使用tasklet机制实现底半部处理。软中断向量HI_SOFTIRQ和TASKLET_SOFTIRQ均是用tasklet机制来实现的。实际上,现在的底半处理程序本身就是用tasklet实现的。

tasklet机制是Linux内核对BH机制的一种扩展:

1. 与一般的软中断不同,某一段tasklet代码在某个时刻只能在一个CPU上运行,而不像一般的软中断服务函数(即softirq_action结构中的action函数指针)那样——在同一时刻可以被多个CPU并发地执行。

2. 与BH机制不同,不同的tasklet代码在同一时刻可以在多个CPU上并发地执行,而不像BH机制那样必须严格地串行化执行(也即在同一时刻系统中只能有一个CPU执行BH函数)。

tasklet_struct结构定义在<linux/interrupt.h>文件中

定义一个处理函数:void my_tasklet_func(unsigned long)

DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);

/*定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相关联,相当于DECLARE_TASK_QUEUE() */

tasklet_schedule(&my_tasklet);

/* 登记my_tasklet,允许系统在适当的时候进行调度运行,相当于queue_task(&my_task,&tq_immediate)和mark_bh(IMMEDIATE_BH) */

就写这么多吧,快放假了,大家假期快乐。









——————————————————————————————————————

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

437

主题

437

帖子

0

粉丝