中断机制

裸板中的中断处理
1.硬件处理
(1)cpu强制进入中断模式
(2)cpsr ->spsr
(3)lr = pc -4
(4)cpu强制跳转到中断向量表 
2.软件处理
初始化中断
(1)设置中断管脚
(2)设置触发方式(电平、边沿 EINT0/1/2)
(3)设置中断模式 (IRQ/FIQ)INTMOD
(4)使能中断,开屏蔽位 INTMSK,EINTMASK,CPSR
(5)设置优先级
中断处理
(1)计算返回地址 lr = lr -4
(2)保存现场
(3)执行中断处理函数
(4)恢复现场

linux的中断机制

1. 中断号的申请和中断处理函数的注册
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);
}

irq: 中断号 定义在 arch/arm/mach-s5pv210/include/mach/irqs.h
                    arch/arm/plat-samsung/include/plat/irqs.h
中断号 : 表示中断的类型,对中断源的分类

handler : 中断处理函数
typedef irqreturn_t (*irq_handler_t)(int, void *);
中断处理函数是函数指针类型
IRQF_DISABLED : 如果进入中断处理函数后,会禁止其他中断使能
IRQF_SHARED - allow sharing the irq among several devices
             : 共享中断,几个设备公用一个中断号
如果是gpio引发的中断源 ,要使用一下的宏
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
     IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE 0x00000010
name : 中断号的名称

dev_id : 在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。 

2. 中断函数的实现:
typedef irqreturn_t (*irq_handler_t)(int, void *);

3.中断的释放:  
void free_irq(unsigned int irq, void *dev_id) 
irq : 要释放的中断号
dev_id : 要释放中断的名称,一般设置为NULL

中断处理函数中:
1. 不能执行有可能睡眠的操作
2. 不能使用慢速的函数进行处理,比如printk(),copy_to_user
3. 实现中断处理有一个原则,就是尽可能快地处理并返回

中断处理分成2个部分,一个快速处理部分,一个是慢速处理部分
中断的顶半部 : 用来做快速处理的,处理完成后调用底半部后,退出中断
中断的底半部 : 一段安全时间后,系统空闲了,调用底半部部分进行处理

底半部的机制:tasklet
1.依赖的头文件
<linux/interrupt.h>

2. 定义一个tasklet结构体
struct tasklet_struct
{
     struct tasklet_struct *next;
     unsigned long state;
     atomic_t count;
     void (*func)(unsigned long);
     unsigned long data;
};

struct tasklet_struct mytasklet;

3. 初始化这个结构体 并注册处理函数
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data) 
参数:
t : struct tasklet_struc 结构体指针
func : 函数指针类型的变量,底半部的处理函数
data : 是给函数指针传参的

tasklet_init(&hello_device.tlet, jit_tasklet_fn, (unsigned long)&hello_device);


jit_tasklet_fn: 这个函数就是底半部的调用函数,这个函数会在中断处理后的一段安全时间后执行


4. 调用tasklet底半部的处理函数
tasklet_schedule()
static inline void tasklet_schedule(struct tasklet_struct *t)
t : 是要进行调度的tasklet
 
tasklet_schedule(&dev->tlet);


工作队列 :
1. 依赖头文件<linux/workqueue.h>
还可以是这个头文件: #include <linux/interrupt.h>,因为在这个头文件内已经包含了<linux/workqueue.h> 
2. 定义一个结构体
struct work_struct my_wq;

3. 初始化工作队列并将其与处理函数绑定
INIT_WORK(&my_wq, (void *) my_wq_func);
my_wq : 结构体的地址
my_wq_func : 工作队列的处理函数

4. 调用工作队列的底半部处理函数
schedule_work(&dev->my_wq);

tasklet与工作队列

1. 工作队列的使用方法和tasklet非常相似
2. tasklet运行于中断上下文 (中断上下文是由硬件触发的处理函数)
   工作队列运行与进程的上下文(是应用程序调用内核的处理机制)
3. tasklet处理函数中不能睡眠,而工作队列处理函数中允许睡眠
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值