Linux内核定时器和ioctl函数
IMX6ULL嵌入式Linux驱动开发学习
以下内容是我在学习正点原子IMX6ULL开发板alpha中记录的笔记,部分摘录自正点原子IMX6ULL开发手册。
Linux内核定时器和ioctl函数
-
内核时间管理
1.1 对于
Cortex-M内核来说,一般使用systick硬件定时器作为系统定时器,使用过FreeRTOS等操作系统的也知道,FreeRTOS一般就是使用systick来提供系统时钟,同样Linux也需要系统时钟。1.2
Linux内核频率可以配置,在图形化界面可以配置。在include/aasm-generic/param.h文件中可以看到内核配置的节拍率HZ(系统频率)。1.3
HZ表示每秒的节拍数。 -
节拍率高低的缺陷
系统使用硬件定时中断来计时,中断周期性产生的频率就是系统频率,也叫作节拍率
tick rate。节拍率越高,时间精度越高,同样也会加剧系统的负担。
-
jiffiesLinux内核使用全局变量jiffies来记录系统从启动以来的系统节拍数,系统启动的时候会将其初始化为0,jiffies定义在文件include/linux/jiffies.h中。jiffies/HZ就是系统运行时间,单位为秒。
/************** 判断是否超时的api函数 ***************/
/* unkown 通常为 jiffies, known 通常是需要对比的值。 */
time_after(unkown, known)
time_before(unkown, known)
time_after_eq(unkown, known)
time_before_eq(unkown, known)
/************** jiffies 和 ms、us、ns的转化函数 ***************/
/* 将 jiffies 类型的参数 j 分别转换为对应的毫秒、微秒、纳秒。 */
int jiffies_to_msecs(const unsigned long j)
int jiffies_to_usecs(const unsigned long j)
u64 jiffies_to_nsecs(const unsigned long j)
/* 将毫秒、微秒、纳秒转换为 jiffies 类型。 */
long msecs_to_jiffies(const unsigned int m)
long usecs_to_jiffies(const unsigned int u)
unsigned long nsecs_to_jiffies(u64 n)
/***************** 使用 jiffies 判断超时 ****************/
unsigned long timeout;
timeout = jiffies + (2 * HZ); /* 超时的时间点 */
/* 判断有没有超时 */
if(time_before(jiffies, timeout))
{
/* 超时未发生 */
}
else
{
/* 超时发生 */
}
-
内核定时器
4.1 软件定时器不像硬件定时器一样是直接设置周期值的。软件定时器是设置期限满以后的时间点。
4.2 需要编写定时器处理函数。
4.3 内核定时器不是周期性的,一次定时时间到了以后就会关闭,除非重新打开。
-
定时器
API函数
/******** timer_list 结构体 **********/
struct timer_list {
struct list_head entry;
unsigned long expires; /* 定时器超时时间,单位是节拍数 */
struct tvec_base* base;
void (*function)(unsigned long); /* 定时处理函数 */
unsigned long data; /* 要传递给 function 函数的参数 */
int slack;
};
/************ api函数 ************/
void init_timer(struct timer_list* timer); // 初始化定时器
void add_timer(struct timer_list* timer); // 向Linux内核注册定时器,同时启动定时器
int del_timer(struct timer_list* timer); // 删除一个定时器
int del_timer_sync(struct timer_list* timer); // del_timer 函数的同步版,会等待其他处理器使用完定时器再删除,del_timer_sync 不能使用在中断上下文中
int mod_timer(struct timer_list* timer, unsigned long expires); // 修改定时值,同时启动定时器
- 内核短延时函数
void ndelay(unsigned long nsecs); // 纳秒延时
void udelay(unsigned long usecs); // 微秒延时
void mdelay(unsigned long mseces); // 毫秒延时
定时器使用练手
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define TIMER_CNT 1
#define TIMER_NAME "timer"
#define LEDOFF 0
#define LEDON 1
/* 定义设备驱动结构体 */
struct timer_dev
{
dev_t devid;
int major;
int minor;
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *nd;
int led_gpio; /* led 所使用的 GPIO 编号 */
struct timer_list timer; /* 定义一个定时器 */
};
struct timer_dev timerdev; /* 定义一个设备 */
static int led_open(struct inode *inode, struct file *filp)
{
filp->private_data = &timerdev;
return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
struct timer_dev *dev = filp->private_data;
return 0;
}
ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
struct timer_dev *dev = filp

本文是学习正点原子开发板的笔记,介绍了Linux内核定时器和ioctl函数。涵盖内核时间管理,包括硬件定时器、节拍率配置及高低缺陷;阐述内核定时器特点,如设置期限、需处理函数且非周期性;还说明了ioctl函数命令拆分、构建及驱动和测试APP程序。
最低0.47元/天 解锁文章
383

被折叠的 条评论
为什么被折叠?



