学习笔记十:linux驱动之内核定时器

内核定时器

 定时器是我们最常用到的功能,一般用来完成定时功能,本章我们就来学习一下Linux内核提供的定时器API函数,通过这些定时器API函数我们可以完成很多要求定时的应用。Linux内核也提供了短延时函数,比如微秒、纳秒、毫秒延时函数,本章我们就来学习一下这些和时间有关的功能。

配置系统频率

 Linux 内核中有大量的函数需要时间管理,比如周期性的调度程序、延时程序、对于我们驱动编写者来说最常用的定时器。硬件定时器提供时钟源,时钟源的频率可以设置,设置好以后就周期性的产生定时中断,系统使用定时中断来计时。中断周期性产生的频率就是系统频率,也叫做节拍率(tick rate)(有的资料也叫系统频率),比如1000Hz,100Hz 等等说的就是系统节拍率。系统节拍率是可以设置的,单位是 Hz,我们在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面:
-> Kernel Features
  -> Timer frequency ( [=y])
在这里插入图片描述
设置好后配置内容会保存在.config中
在这里插入图片描述
CONFIG_HZ 为 100, Linux 内核会使用 CONFIG_HZ 来设置自己的系统时
钟。打开文件 include/asm-generic/param.h,有如下内容:

# define HZ CONFIG_HZ

高节拍率和低节拍率的优缺点:
①、高节拍率会提高系统时间精度,如果采用 100Hz 的节拍率,时间精度就是 10ms,采用
1000Hz 的话时间精度就是1ms,精度提高了10倍。高精度时钟的好处有很多,对于那些对时间要求严格的函数来说,能够以更高的精度运行,时间测量也更加准确。
②、高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担, 1000Hz和100Hz的系统节拍率相比,系统要花费10倍的“精力”去处理中断。中断服务函数占用处理器的时间增加,但是现在的处理器性能都很强大,所以采用 1000Hz 的系统节拍率并不会增加太大的负载压力。根据自己的实际情况,选择合适的系统节拍率。

jiffies

 Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数,系统启动的时候会将 jiffies 初始化为 0, jiffies 定义在文件 include/linux/jiffies.h 中,定义如下:

extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

 jiffies_64 和 jiffies 其实是同一个东西, jiffies_64 用于 64 位系统,而 jiffies 用于 32 位系统。为了兼容不同的硬件, jiffies 其实就是 jiffies_64 的低 32 位。当我们访问 jiffies 的时候其实访问的是 jiffies_64 的低 32 位,使用 get_jiffies_64 这个函数可以获取 jiffies_64 的值。在 32 位的系统上读取jiffies 的值,在 64 位的系统上 jiffes 和 jiffies_64表示同一个变量,因此也可以直接读取 jiffies 的值。所以不管是 32 位的系统还是 64 位系统,都可以使用 jiffies。
 前面说了 HZ 表示每秒的节拍数, jiffies 表示系统运行的 jiffies 节拍数,所以 jiffies/HZ 就是系统运行时间,单位为秒。不管是 32 位还是 64 位的 jiffies,都有溢出的风险,溢出以后会重新从 0 开始计数,相当于绕回来了,因此有些资料也将这个现象也叫做绕回。假如 HZ 为最大值 1000 的时候, 32 位的 jiffies只需要 49.7 天就发生了绕回,对于 64 位的 jiffies 来说大概需要5.8 亿年才能绕回,因此 jiffies_64 的绕回忽略不计。处理 32 位 jiffies 的绕回显得尤为重要,linux提供了如下几个API函数来处理绕回。

time_after(unknown,known);
time_befor(unknown,known);
time_after_eq(unknown,known);
time_before_eq(unknown,known);

 如果unkown超过known的话,time_after函数返回真,否则返回假。如果 unkown没有超过known的话time_before函数返回真,否则返回假time_after_eq函数和time_after函数类似,只是多了判断等于这个条件。同理,time_before_eq函数和time_before函数也类似。

 为了方便开发, Linux 内核提供了几个 jiffies 和 ms、 us、 ns 之间的转换函数

int jiffies_to_msecs(const unsigned long 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);
long usecs_to_jiffies(const unsigned int u) ;
unsigned long nsecs_to_jiffies(u64 n);
内核定时器
头文件

#include <linux/timer.h>

定义
struct timer_list {
	struct list_head entry;
	unsigned long expires; /* 定时器超时时间,单位是节拍数 */
	struct tvec_base *base;
	void (*function)(unsigned long); /* 定时处理函数 */
	unsigned long data; /* 要传递给 function 函数的参数 */
	int slack;
};
接口

初始化:
void init_timer(struct timer_list *timer);
启用定时器:
void add_timer(struct timer_list *timer);
删除定时器:
int del_timer(struct timer_list * timer);
参数:
  timer:要删除的定时器。
返回值: 0,定时器还没被激活; 1,定时器已经激活
// 等待其他处理器使用完定时器再删除
int del_timer_sync(struct timer_list *timer)
参数:
  timer:要删除的定时器。
返回值: 0,定时器还没被激活; 1,定时器已经激活。
激活并修改定时器定时值
int mod_timer(struct timer_list *timer, unsigned long expires);
参数:
  timer:需要操作的定时器
  expires:定时器终止时间
返回值:0,调用 mod_timer 函数前定时器未被激活; 1,调用 mod_timer 函数前定时器已被激活。

短延时

可能会有人问,系统节拍频率最高1000Hz,也就是一个节拍1ms,那我要进行更精确的定时或者延时怎么办呢?
可以使用如下函数进行短延时:

void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long mseces);

还可以使用hrtimer高精度定时器进行微秒纳秒级的定时。

!以上内容整理自正点原子的imx6ull驱动开发指南

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值