linux的定时器和中断

一、定时器

Linux的时钟节拍率可以在配置的时候设置,默认为100,单位是HZ。系统里面定义了HZ的宏为100,即一个时钟节拍为10ms。同时系统定义了jiffies来记录系统启动以来的系统节拍数。系统初始化的时候会初始化为0。即jiffies/HZ就是运行时间,单位为S。

    jiffies和ms、us、ns之间的转换函数:

函数

描述

int jiffies_to_msecs(const unsigned long j)

jiffies类型的参数j分别转换为对应的毫秒、微秒、纳秒。

int jiffies_to_usecs(const unsigned long j)

u64 jiffies_to_nsecs(const unsigned long j)

long msecs_to_jiffies(const unsigned int m)

将毫秒、微秒、纳秒转换为jiffies类型。

long usecs_to_jiffies(const unsigned int u)

unsigned long nsecs_to_jiffies(u64 n)

延时函数:

函数

描述

oid ndelay(unsigned long nsecs)

纳秒、微秒和毫秒延时函数。

 

oid udelay(unsigned long usecs)

oid mdelay(unsigned long mseces)

内核定时器:

函数

 

void init_timer(struct timer_list *timer)

init_timer函数负责初始化timer_list类型变量

void add_timer(struct timer_list *timer)

add_timer函数用于向Linux内核注册定时器

int del_timer(struct timer_list * timer)

del_timer函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除

int del_timer_sync(struct timer_list *timer)

del_timer_sync函数是del_timer函数的同步版,会等待其他处理器使用完定时器再删除,del_timer_sync不能使用在中断上下文中

int mod_timer(struct timer_list *timer, unsigned long expires)

mod_timer函数用于修改定时值,如果定时器还没有激活的话,mod_timer函数会激活定时器

 

 

struct timer_list timer; /* 定义定时器 */ 
 
/* 定时器回调函数 */ 
void function(unsigned long arg)
{ 
/* 
 * 定时器处理代码 
*/ 

* 如果需要定时器周期性运行的话就使用mod_timer 
* 函数重新设置超时值并且启动定时器。 
*/ 
mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2000)); 
} 

/* 初始化函数 */ 
void init(void) 
{ 
init_timer(&timer); /* 初始化定时器 */ 
 
timer.function = function; /* 设置定时处理函数 */ 
timer.expires=jffies + msecs_to_jiffies(2000);/* 超时时间2秒 */ 
timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */ 
 
add_timer(&timer); /* 启动定时器 */ 
} 
 
/* 退出函数 */ 
void exit(void) 
{ 
del_timer(&timer); /* 删除定时器 */ 
/* 或者使用 */ 
del_timer_sync(&timer); 
} 

二、中断

我们知道单片机中中断是用来处理突发事件的,中断处理函数处理得越快越好,同时不能嵌套。在linux中,中断分为上下部,并有一套中断的机制高效的处理。下面是linux下中断的处理机制和应用说明。

机制

应用情景

类似简单单片机,一个中断处理函数完成中断处理

处理事情很少,紧急,耗时不太长

中断函数分为上半部和下半部(上半部关中断,下半部开中断)

 

上半部(紧急)

下半部(不紧急)

 

用来处理紧急的事情

中断处理函数里面,应用程序没有在跑

软中断

处理得事情很多,耗时不太长

Tasklet(小任务,基于软中断)

处理得事情很多,耗时不太长

创建内核线程在中断外处理剩下的工作,可以跟APP一样竞争执行

工作队列

处理得事情很多,耗时很长

thread irq (跟工作队列原理一样,多考虑了多核处理器的处理,更优)

处理得事情很多,耗时很长

中断相关函数说明

函数

说明

int request_irq(unsigned int irq,

irq_handler_t handler,

unsigned long flags,

const char *name,

void *dev)

irq:要申请中断的中断号

handler:中断处理函数

flags:中断标志,可以在文件include/linux/interrupt.h里面查看所有的中断标志,这里我们

name:中断名字,设置以后可以在/proc/interrupts文件中看到对应的中断名字

dev:如果将flags设置为IRQF_SHARED的话,dev用来区分不同的中断,一般情况下将dev设置为设备结构体,dev会传递给中断处理函数irq_handler_t的第二个参数

返回值:0 中断申请成功,其他负值中断申请失败,如果返回-EBUSY的话表示中断已经被申请了

void free_irq(unsigned int irq,

void *dev)

irq:要释放的中断。

dev:一般情况下将dev设置为设备结构体

irqreturn_t (*irq_handler_t) (int, void *)

第一个参数是要中断处理函数要相应的中断号。第二个参数是一个指向void的指针,也就是个通用指针,需要与request_irq函数的dev参数保持一致。用于区分共享中断的不同设备,dev也可以指向设备数据结构。

中断使用示例代码:

/* 中断处理函数 */ 
irqreturn_t test_handler(int irq, void *dev_id) 
{ 
...... 
...... 
} 
/* 驱动入口函数 */ 
static int __init xxxx_init(void) 
{ 
...... 
/* 注册中断处理函数 */ 
request_irq(xxx_irq, test_handler, 0, "xxx", &xxx_dev); 
...... 
} 
/* 驱动出口函数 */ 
static void __exit xxxx_exit(void) 
{ 
...... 
/* 释放中断 */ 
free_irq(xxx_irq, &xxx_dev); 
......
} 

tasklet函数说明

函数

说明

void tasklet_init(struct tasklet_struct *t,

void (*func)(unsigned long),

unsigned long data);

t:要初始化的tasklet

functasklet的处理函数。

data:要传递给func函数的参数

void tasklet_schedule(struct tasklet_struct *t)

t:要调度的tasklet

 

 

tasklet示例代码
/* 定义taselet */ 
struct tasklet_struct testtasklet; 
/* tasklet处理函数 */ 
void testtasklet_func(unsigned long data) 
{ 
/* tasklet具体处理内容 */ 
} 
/* 中断处理函数 */ 
irqreturn_t test_handler(int irq, void *dev_id) 
{ 
...... 
/* 调度tasklet */ 
tasklet_schedule(&testtasklet); 
...... 
} 
/* 驱动入口函数 */ 
static int __init xxxx_init(void) 
{ 
...... 
/* 初始化tasklet */ 
tasklet_init(&testtasklet, testtasklet_func, data); 
/* 注册中断处理函数 */ 
request_irq(xxx_irq, test_handler, 0, "xxx", &xxx_dev); 
...... 
}

工作队列相关函数说明

函数

说明

#define INIT_WORK(_work, _func)

_work表示要初始化的工作,_func是工作对应的处理函数。

bool schedule_work(struct work_struct *work)

work:要调度的工作。

/* 定义工作(work) */ 
struct work_struct testwork; 
/* work处理函数 */ 
void testwork_func_t(struct work_struct *work); 
{ 
/* work具体处理内容 */ 
} 
/* 中断处理函数 */ 
irqreturn_t test_handler(int irq, void *dev_id) 
{ 
...... 
/* 调度work */ 
schedule_work(&testwork); 
...... 
} 
/* 驱动入口函数 */ 
static int __init xxxx_init(void) 
{ 
...... 
/* 初始化work */ 
INIT_WORK(&testwork, testwork_func_t); 
/* 注册中断处理函数 */ 
request_irq(xxx_irq, test_handler, 0, "xxx", &xxx_dev); 
...... 
} 

三、设备树中断节点信息

①、#interrupt-cells,指定中断源的信息cells个数。

②、interrupt-controller,表示当前节点为中断控制器。

③、interrupts,指定中断号,触发方式等。

④、interrupt-parent,指定父中断,也就是中断控制器。

获取中断号

函数

说明

unsigned int irq_of_parse_and_map(struct device_node *dev,

int index)

dev:设备节点。

index:索引号,interrupts属性可能包含多条中断信息,通过index指定要获取的信息。

返回值:中断号。

int gpio_to_irq(unsigned int gpio)

gpio:要获取的GPIO编号。

返回值:GPIO对应的中断号。

 

 

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值