【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第六十一章 Linux内核定时器

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、

【公众号】迅为电子

【粉丝群】258811263


六十一Linux内核定时器

本章导读

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

61.1章节讲解了Linux内核时间管理的基础知识

61.2章节讲解了内核定时器简介和相关函数介绍

61.3章节以实验的形式进行Linux内核定时器实验,实现内核定时器每隔一秒打印“This is timer_function \n”。

本章内容对应视频讲解链接(在线观看):

内核定时器  https://www.bilibili.com/video/BV1Vy4y1B7ta?p=40

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\018-Linux内核定时器”路径下。

61.1 Linux 内核时间管理

时间管理在内核中占有非常重要的地位。相对于事件驱动,内核中有大量的函数都是基于时间驱动的。

内核必须管理系统的运行时间以及当前的日期和时间。

周期产生的事件都是由系统定时器驱动的。系统定时器是一种可编程硬件芯片,它已固定频率产生中

断。该中断就是所谓的定时器中断,它所对应的中断处理程序负责更新系统时间,还负责执行需要周期性

运行的任务。系统定时器和时钟中断处理程序是 Linux 系统内核管理机制中的中枢。

61.1.1 内核中的时间概念

硬件为内核提供了一个系统定时器用以计算流逝的时间,系统定时器以某种频率自行触发时钟中断,该频率可以通过编程预定,称节拍率。当时钟中断发生时,内核就通过一种特殊中断处理程序对其进行处

理。内核知道连续两次时钟中断的间隔时间。这个间隔时间称为节拍(tick),内核就是靠这种已知的时钟

中断来计算墙上时间和系统运行时间。墙上时间即实际时间,内核提供了一组系统调用以获取实际日期和

实际时间。系统运行时间——自系统启动开始所经过的时间——对用户和内核都很有用,因为许多程序都必

须清楚流逝过的时间。

61.1.2 节拍率

系统定时器频率是通过静态预处理定义的,也就是 HZ,在系统启动时按照 Hz 对硬件进行设置。体系结构不同,HZ 的值也不同。内核在文件 <include/asm-generic/param.h> 中定义了 HZ 的实际值,节拍率就是 HZ,周期为 1/HZ。一般 ARM 体系结构的节拍率多数都等于 100,3399默认为1000。在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面:

-> Kernel Features

-> Timer frequency (<choice> [=y])

 选中“Timer frequency”,打开以后如下图所示:、

 从上图可以看出可选的系统节拍率为 100Hz、200Hz、250Hz、300Hz、500Hz 和 1000Hz,默认情况下

选择 1000Hz。设置好以后打开 Linux 内核源码根目录下的.config 文件,在此文件中有如下图所示定义:

上图中的 CONFIG_HZ 为 1000,Linux 内核会使用 CONFIG_HZ 来设置自己的系统时钟。打开文件

include/asm-generic/param.h,有如下内容:

# undef HZ

# define HZ CONFIG_HZ

# define USER_HZ 100

# define CLOCKS_PER_SEC (USER_HZ)

第 7 行定义了一个宏 HZ,宏 HZ 就是 CONFIG_HZ,因此 HZ=1000,我们后面编写 Linux 驱动的时候

会常常用到 HZ,因为 HZ 表示一秒的节拍数,也就是频率。

61.1.3 jiffies

全局变量 jiffies 用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为 0,此后,

每次时钟中断处理程序都会增加该变量的值。因为一秒内时钟中断的次数等于 Hz,所以 jiffes 一秒内增加的值也就为 Hz,系统运行时间以秒为单位计算,就等于 jiffes/Hz。jiffes=seconds*HZ。jiffies 定义在文件include/linux/jiffies.h 中,定义如下:

 extern u64 __jiffy_data jiffies_64;

extern unsigned long volatile __jiffy_data jiffies;

函数

作用

time_after(unkown, known)

unkown 通常为 jiffies,known 通常是需要对比的值。

time_before(unkown, known)

time_after_eq(unkown, known)

time_before_eq(unkown, 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)

将 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)

举例来说

<1>定时10ms

计算:jiffies +msecs_to_jiffies(10)

<2>定时10us

计算:jiffies +usecs_to_jiffies(10)

61.2 内核定时器简介

定时器,有时也称为动态定时器或内核定时器——是管理内核时间的基础。定时器的使用很简单。只需要执行一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以了。指定的函数将在定时器到期时自动执行。定时器并不周期运行,它在超时后就自行销毁,这也正是这种定时器被称为动态定时器的一个原因。

Linux 内核使用 timer_list 结构体表示内核定时器,timer_list 定义在文件 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;

};

要使用内核定时器首先要先定义一个 timer_list 变量,表示定时器,tiemr_list 结构体的 expires 成员变量表示超时时间,单位为节拍数。比如我们现在需要定义一个周期为 2 秒的定时器,那么这个定时器的超时时间就是 jiffies+(2*HZ),因此 expires=jiffies+(2*HZ)。function 就是定时器超时以后的定时处理函数,我们要做的工作就放到这个函数里面,需要我们编写这个定时处理函数。

定义好定时器以后还需要通过一系列的 API 函数来初始化此定时器,这些函数如下:

函数

作用

void init_timer(struct timer_list *timer)

初始化定时器

#define DEFINE_TIMER(_name, _function, _expires, _data)

该宏会静态创建一个名叫 timer_name 内核定时器,并初始化其 function, expires, name 和 base 字段。

void add_timer(struct timer_list *timer)

向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后,定时器就会开始运行

int del_timer(struct timer_list * timer)

删除一个定时器

int del_timer_sync(struct timer_list *timer)

等待其他处理器使用完定时器再删除

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

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

#define DEFINE_TIMER(_name, _function, _expires, _data)

_name

变量名

_function

超时处理函数

_data

传递给超时处理函数的参数

_expires

到点时间,一般在启动定时前需要重新初始化。

功能

静态定义结构体变量并且初始化初始化function, expires, data 成员。

内核定时器一般的使用流程如下所示:

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 内核提供了毫秒、微秒和纳秒

延时函数,这三个函数如下所示:

函数

作用

void ndelay(unsigned long nsecs)

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

void udelay(unsigned long usecs)

void mdelay(unsigned long mseces)

61.3 实验测试

我们拷贝最简单的驱动文件helloworld.c和Makefile到Ubuntu的/home/topeet/imx8mm/18目录下,我们在此基础上进行修改,编写驱动代码如下所示:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
// 声明时间处理函数
static void timer_function(unsigned long data);
// 该宏会静态创建一个名叫 timer_name 内核定时器,
// 并初始化其 function, expires, name 和 base 字段。
DEFINE_TIMER(test_timer, timer_function, 0, 0);/*** @description:超时处理函数 * @param {*}* @return {*}*/
static void timer_function(unsigned long data)
{printk(" This is timer_function \n");/*** @description: 修改定时值,如果定时器还没有激活的话,mod_timer 函数会激活定时器* @param {1} ** @return {*}*/mod_timer(&test_timer, jiffies + 1 * HZ);
}
static int hello_init(void)
{printk("hello world! \n");//初始化test_timer.expires意为超时时间test_timer.expires = jiffies + 1 * HZ;//定时器注册到内核里面,启动定时器add_timer(&test_timer);return 0;
}static void hello_exit(void)
{printk("gooodbye! \n");// 删除一个定时器del_timer(&test_timer);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

编译完加载驱动模块,如下图所示:

如上图所示,内核定时器每隔一秒打印“This is timer_function \n”。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/50905.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第四十二章 LED驱动实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

【python014】Python爬取并解析潮汐天气简报-潮历数据

1.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 【python014】Python爬取并解析潮汐天气简报-潮历数据&#xff0c;源代码下载【python014】Python爬取并解析潮汐天气简报-潮历数据&#xff0c;源代码下载【python014】Python爬取并解…

EtherNet/IP转Profinet协议转化网关(功能与配置)

如何将EtherNet/IP和Profinet网络连接通讯起来呢?近来几天有几个朋友问到这个问题&#xff0c;那么作者在这里统一说明一下。其实有一个不错的设备产品可以很轻易地解决这个问题&#xff0c;名为捷米特JM-PN-EIP。接下来作者就从该设备的功能及配置详细说明一下。 一&#xf…

Leetcode283. 移动零(java实现)

今天分享的题目是leetcode283移动0&#xff08;成都人狂喜&#xff09; 先来看下题目描述 这道题目我也看了官方的题解感觉有点冗余了。 那么我们就不用官方的题解了&#xff0c;分享下我们自己的解体方式。 解题步骤&#xff1a;1.找到非0元素&#xff0c;如果是非0进行记录2…

CentOS6.0安装telnet-server启用telnet服务

CentOS6.0安装telnet-server启用telnet服务 一步到位 fp"/etc/yum.repos.d" ; cp -a ${fp} ${fp}.$(date %0y%0m%0d%0H%0M%0S).bkup echo [base] nameCentOS-$releasever - Base baseurlhttp://mirrors.163.com/centos-vault/6.0/os/$basearch/http://mirrors.a…

永劫无间游戏辅助攻略:2024阵容搭配攻略大全!云手机辅助!

《永劫无间》是一款备受玩家喜爱的动作类游戏&#xff0c;其丰富的角色选择和多样的技能搭配让玩家在战斗中体验到了极大的乐趣。然而&#xff0c;要在竞争激烈的战场上脱颖而出&#xff0c;仅仅依靠基础的游戏理解是远远不够的。为了帮助广大玩家提升战斗力&#xff0c;本文将…

Ruby、Python、Java 开发者必备:Codigger之软件项目体检

在编程的广阔天地里&#xff0c;Ruby、Python 和 Java 开发者们各自凭借着独特的语言特性&#xff0c;构建着精彩纷呈的应用世界。然而&#xff0c;无论使用哪种语言&#xff0c;确保项目的高质量始终是至关重要的目标。而 Codigger 项目体检则成为了实现这一目标的得力助手&am…

python机器学习8--网络

1.超文本传输协议HTTP GET 在实际开发应用程序时&#xff0c;一定都会利用WiFi网络进行连接&#xff0c;再通过HTTP的方式读入后台的数据&#xff0c;并下载和显示在用户的PC上。这靠的是网络服务的技术&#xff0c;也就是大家提到的Web Service。而与HTTP服务器交换数据有两种…

【React】详解“最新”和“最热”切换与排序

文章目录 一、基本概念和初始化二、切换与排序功能的实现1. 函数定义和参数2. 设置活动 Tab3. 定义新列表变量4. 根据排序类型处理列表4.1 按时间降序排序4.2 按点赞数降序排序 5. 更新评论列表 三、渲染导航 Tab 和评论列表1. map 方法2. key 属性3. className 动态赋值4. onC…

数据结构(二叉树)

树 树的概念与结构 树是⼀种⾮线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;⽽叶朝下的。 • 有⼀个特殊的结点&#xff0c;…

linux 桌面版安装原生微信的方式列举

linux 桌面版安装原生微信的方式列举 方法1&#xff1a;下载deb安装包安装 下载地址&#xff1a;https://github.com/lovechoudoufu/wechat_for_linux/releases 安装示例&#xff1a; sudo dpkg -i linuxqq_3.2.10-25765_amd64.deb方法2&#xff1a;Flatpak安装 安装flatp…

docker dotnet-dump离线部署

1.下载指定dotnet版本的dotnet-dump 示例地址&#xff1a; https://www.nuget.org/packages/dotnet-dump/3.1.141901#dependencies-body-tab 我本地测试的是netcore 3.1 2. 在本地解压 将文件解压出来。看到any目录,能看到我们要用的dotnet-dump文件 3. 将tools/netcoreapp2.…

qt实现智能家居(语言控制+服务器监听)

目录 介绍页面展示环境搭建开发工具开发环境百度token 连接服务器 介绍 qt智能家居&#xff08;语音控制&#xff09; 视频演示地址&#xff1a;进入哔哩哔哩 仓库地址&#xff1a;Gitee 源代码&#xff1a;百度网盘 默认密码是123456 页面展示 登录页面演示图 控制中心页…

SpringBoot运行流程源码分析

run方法核心流程 我们在启动SpringBoot的时候调用的是SpringApplication类的静态run方法。其核心流程如下图所示&#xff1a; 在run方法内完成了SpringApplication的声明周期。&#xff0c;这个过程涉及的几个核心类如下&#xff1a; SpringApplicationRunListeners&#xff…

一起学Java(1)-新建一个Gradle管理的Java项目

一时兴起&#xff0c;也为了便于跟大家同步学习进展和分享样例代码&#xff0c;遂决定创建一个全新的Java项目&#xff0c;并通过Github与大家分享。本文就是记录该项目的创建过程以及其中的一些知识要点&#xff08;如Gradle等&#xff09;。为了紧跟技术潮流和提高操作效率&a…

鱼哥好书分享活动第28期:看完这篇《终端安全运营》终端安全企业基石,为你的终端安全保驾护航!

鱼哥好书分享活动第28期&#xff1a;看完这篇《终端安全运营》终端安全企业基石&#xff0c;为你的终端安全保驾护航&#xff01; 读者对象&#xff1a;主要内容&#xff1a;本书目录&#xff1a;了解更多&#xff1a;赠书抽奖规则: 在当前网络威胁日益复杂化的背景下&#xff…

linux nginx 命令记录,和转发

nginx: 查看配置文件&#xff1a;sudo find / -name nginx.conf 配置文件&#xff1a;/etc/nginx/nginx.conf 检查nginx.conf文件正确性 nginx -t -c /path/to/nginx.conf 或者 有nginx命令执行 nginx -t 查找nginx 可执行文件&#xff1a;which nginx /usr/sbin/nginx 安装Ng…

游戏UI设计大师课:3款游戏 UI 设计模板

很多时候&#xff0c;做设计需要找素材。假如是普通的 UI 界面或者 Banner 等等&#xff0c;在Dribbble、Pinterest、即时设计、Behance 翻看这样的网站&#xff0c;至少可以梳理出一些想法和思路。如果你需要一个更规范的指南&#xff0c;此时&#xff0c;在各种设计规范、官方…

.Net 检验信息采集及管理系统LIS,成熟的医院实验室管理系统源码

检验管理系统LIS实现了检验信息电子化、检验信息管理自动化&#xff0c;具备与医嘱双向沟通、采用条码管理手段、财务自动计费、仪器双向控制等重要功能特点。其工作流程为通过门诊医生和住院工作站提出检验申请&#xff0c;生成相应患者的化验条码标签&#xff0c;在生成化验单…

根据题意写出完整的css,html和js代码【购物车模块页面及功能实现】

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 问题描述 根据题意写出完…