IMX6ULL嵌入式Linux驱动学习笔记(八)

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


IMX6ULL嵌入式Linux驱动开发学习

以下内容是我在学习正点原子IMX6ULL开发板alpha中记录的笔记,部分摘录自正点原子IMX6ULL开发手册

Linux内核定时器和ioctl函数

  1. 内核时间管理

    1.1 对于Cortex-M内核来说,一般使用systick硬件定时器作为系统定时器,使用过FreeRTOS等操作系统的也知道,FreeRTOS一般就是使用systick来提供系统时钟,同样Linux也需要系统时钟。

    1.2 Linux内核频率可以配置,在图形化界面可以配置。在include/aasm-generic/param.h文件中可以看到内核配置的节拍率HZ(系统频率)。

    1.3 HZ表示每秒的节拍数。

  2. 节拍率高低的缺陷

    系统使用硬件定时中断来计时,中断周期性产生的频率就是系统频率,也叫作节拍率tick rate

    节拍率越高,时间精度越高,同样也会加剧系统的负担。

  3. jiffies

    Linux内核使用全局变量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
{
   
   
	/* 超时发生 */
}
  1. 内核定时器

    4.1 软件定时器不像硬件定时器一样是直接设置周期值的。软件定时器是设置期限满以后的时间点。

    4.2 需要编写定时器处理函数。

    4.3 内核定时器不是周期性的,一次定时时间到了以后就会关闭,除非重新打开。

  2. 定时器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);	// 修改定时值,同时启动定时器
  1. 内核短延时函数
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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值