1、内核高精度定时器hrtimer:精度ns
测试代码: hrtimer_drv.c
/***********************************************************************
* 编译 : make
* 安装驱动 : insmod modName.ko
* 卸载驱动 : rmmod modName
* 查看驱动信息 : lsmod
* 查看内核打印 : dmesg
* *********************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/time.h>
#include <linux/ioport.h>//io端口头文件
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/ktime.h>
static int my_hrtimer_drv_release(struct inode *inode, struct file *file);
static int my_hrtimer_drv_open(struct inode *inode, struct file *file);
static int my_hrtimer_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos);
static struct file_operations hrtimer_drv_fops = {
.owner = THIS_MODULE,
.open = my_hrtimer_drv_open,
.read = my_hrtimer_drv_read,
.release = my_hrtimer_drv_release, //里面添加free_irq函数,来释放中断服务函数
};
typedef struct _hrtimer_event_s{
struct timespec timerValue;
}hrtimer_event_s;
#define MAX_BUF_LEN 100
typedef struct _timerInfo_s {
int count;
hrtimer_event_s info[MAX_BUF_LEN];
}timerInfo_s;
timerInfo_s timerInfo;
static int hrtimer_drv_major = 0;
static struct class *hrtimer_drv_cls;
uint32_t lastTimerValue = 0, currTimerValue = 0;
/*高精度定时器*/
static struct hrtimer hr_timer;
ktime_t ktime;
enum hrtimer_restart my_hrtimer_drv_callback(struct hrtimer *timer)
{
if(timerInfo.count < MAX_BUF_LEN)
{
timerInfo.info[timerInfo.count].timerValue = current_kernel_time();
timerInfo.count++;
}
hrtimer_start( timer, ktime, HRTIMER_MODE_REL ); // 一直运行下去
return HRTIMER_NORESTART;
}
static int __init my_hrtimer_drv_init(void)
{
printk(KERN_ALERT "HR Timer module installing\n");
// 动态申请主设备号
hrtimer_drv_major = register_chrdev(0, "hrtimer_drv_dev", &hrtimer_drv_fops);
// 创建设备节点
hrtimer_drv_cls = class_create(THIS_MODULE, "hrtimer_drv_cls");
device_create(hrtimer_drv_cls, NULL, MKDEV(hrtimer_drv_major, 0), NULL, "hrtimer_drv_cls");
//超时时间设为 1秒
ktime = ktime_set( 0, 100*1000*1000); // 100ms 触发一次
//设置为上电时间
hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
//设置回调函数
hr_timer.function = &my_hrtimer_drv_callback;
//启动定时器
hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL);
return 0;
}
static void __exit my_hrtimer_drv_exit(void)
{
int ret;
//从内核系统设备驱动程序模型中移除设备
device_destroy(hrtimer_drv_cls, MKDEV(hrtimer_drv_major, 0));
class_destroy(hrtimer_drv_cls);
// 取消定时器执行
ret = hrtimer_cancel(&hr_timer);
if(ret)
{
printk( KERN_ALERT "The timer was still in use...\n");
}
printk( KERN_ALERT "HR Timer module uninstalling\n");
return;
}
//关闭设备时调用
int my_hrtimer_drv_release(struct inode *inode, struct file *file) //卸载中断
{
printk("#### %s\n", __FUNCTION__);
return 0;
}
//打开设备时调用
static int my_hrtimer_drv_open(struct inode *inode, struct file *file)
{
printk("#### %s\n", __FUNCTION__);
return 0;
}
//读取设备时调用
static int my_hrtimer_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int ret;
printk("#### %s\n", __FUNCTION__);
ret = copy_to_user(buf, &timerInfo, count);
if(ret > 0)
{
printk("copy_to_user error\n");
return -EFAULT;
}
timerInfo.count = 0;
return 0;
}
module_init(my_hrtimer_drv_init);
module_exit(my_hrtimer_drv_exit);
MODULE_LICENSE("GPL");
Makefile文件:
PLATFORM := "am335x-evm"
MACHINE_NAME := "am335x"
# If CROSS_COMPILE is not set by Rules.make then set a sane default
CC = arm-linux-gnueabihf-gcc
export CC
#obj-m 表示编译成模块
obj-m := hrtimer_drv.o
gpio_drv-objs := hrtimer_drv.o
KERNEL_DIR := /mnt/AM335/linux-3.2.0-psp04.06.00.11
MAKE_ENV = ARCH=arm
PWD := $(shell pwd)
all:
$(MAKE) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" -C $(KERNEL_DIR) $(MAKE_ENV) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers
定时时间读取代码 hrtimer_read.c
/************************************************************
* 编译 : arm-linux-gnueabihf-gcc hrtimer_read.c -o hrtimer_read
*
**************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/input.h>
typedef struct _hrtimer_event_s{
struct timespec timerValue;
}hrtimer_event_s;
#define MAX_BUF_LEN 100
typedef struct _timerInfo_s {
int count;
hrtimer_event_s info[MAX_BUF_LEN];
}timerInfo_s;
int main(int argc, char *argv[])
{
int num, ret;
timerInfo_s data;
//直接将驱动模块当做文件来操作
int fd = open("/dev/hrtimer_drv_cls", O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
while(1)
{
ret = read(fd, &data, sizeof(timerInfo_s));
if(ret < 0)
{
perror("read");
exit(1);
}
//解析包
printf("count %d\n", data.count);
for(num = 0; num < data.count; num++)
{
printf("timerValue %u.%09u s\n",
data.info[num].timerValue.tv_sec, data.info[num].timerValue.tv_nsec);
}
sleep(1);
}
close(fd);
}
定时时间显示
遇到问题:
当hrtimer定时时间到10毫秒以内的时候,由于current_kernel_time()获取的时间就会不对,原因是该函数它返回的值不是基于实际的定时器,而是基于定时器中断更新的时间值.因此精度取决于定时器中断周期,但是该定时器中断周期在10ms左右。
因此在使用此函数获取时间的时候需要根据场景去考虑是否满足精度要求