Linux下的hrtimer高精度定时器

本文详细介绍了如何在Linux系统中使用HRTimer实现高精度定时,包括定时器的初始化、回调函数的实现及工作队列的使用。通过实测分析了引入Linux系统调度延迟导致的定时误差,并提供了误差计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hrtimer高精度定时器的interval由ktime_set(const long secs, const unsigned long nsecs)决定,可做到ns级。此处的例子为5ms interval:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>

MODULE_LICENSE("GPL");

static struct hrtimer hr_timer;
static struct work_struct wq_hrtimer;  
static ktime_t ktime;
static unsigned int interval=5000; /* unit: us */
struct timespec uptimeLast;

static unsigned int count=0;
#define COUNT_INTERVAL 4000
unsigned long long diff_tv(struct timespec start, struct timespec end) {
    return (end.tv_sec-start.tv_sec)*1000000000+(end.tv_nsec-start.tv_nsec);
}

enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer )
{
    schedule_work(&wq_hrtimer); 
    return HRTIMER_NORESTART;
}

static void wq_func_hrtimer(struct work_struct *work)
{ 
    struct timespec uptime;

    hr_timer.function = my_hrtimer_callback; 
    ktime = ktime_set( interval/1000000, (interval%1000000)*1000 );
    hrtimer_start(&hr_timer, ktime, HRTIMER_MODE_REL );

    /* print time every COUNT_INTERVAL*interval second*/
    if(count%COUNT_INTERVAL==0) 
    {
        do_posix_clock_monotonic_gettime(&uptime);  
        printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns, interval_delay=%lu ns\n", 
            (unsigned long) uptime.tv_sec, uptime.tv_nsec,
            (unsigned long)(diff_tv(uptimeLast, uptime)-interval*1000*COUNT_INTERVAL) \
                /COUNT_INTERVAL); 
        uptimeLast=uptime;
    }
    count++;
} 

static int __init module_hrtimer_init( void )
{
    struct timespec uptime; 
    
    printk(KERN_INFO"HR Timer module installing\n");
    
    hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
  
    ktime = ktime_set( interval/1000000, (interval%1000000)*1000 );
    hr_timer.function = my_hrtimer_callback;

    hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );

    do_posix_clock_monotonic_gettime(&uptime);
    uptimeLast = uptime;
    printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns\n", (unsigned long) uptime.tv_sec,  
                                        uptime.tv_nsec ); 

    INIT_WORK(&wq_hrtimer, wq_func_hrtimer);
    return 0;
}

static void __exit module_hrtimer_exit( void )
{
    int ret;

    ret = hrtimer_cancel( &hr_timer );
    if (ret) 
        printk("The timer was still in use...\n");

    printk("HR Timer module uninstalling\n");
    return;
}

module_init(module_hrtimer_init);
module_exit(module_hrtimer_exit);

如果在my_hrtimer_callback()里面直接返回HRTIMER_RESTART会导致立即重新进入my_hrtimer_callback()。这时shell对输入没有任何响应。

所以为了解决这个问题,创建了一个work queue,由my_hrtimer_callback() enqueue这个工作队列。在work queue的处理函数里面重启hrtimer。

但是这样带来的负面影响是进入hrtimer_callback和wq_func被调用之间有Linux系统调度引入的延迟,导致interval出现误差。经过实测,在ZC706缺省配置下,这个延迟大约是17.5us (hrtimer interval为5ms,每20秒计算一次interval误差)。

root@zynq:~/nfs/hrtimer# insmod hrtimer.ko
HR Timer module installing
hrtimer:    2900 sec, 993366078 ns
hrtimer:    2900 sec, 998395278 ns, interval_delay=369966 ns
hrtimer:    2921 sec,  69525447 ns, interval_delay=17782 ns
hrtimer:    2941 sec, 139764655 ns, interval_delay=17559 ns
hrtimer:    2961 sec, 210029519 ns, interval_delay=17566 ns
hrtimer:    2981 sec, 280465631 ns, interval_delay=17609 ns
hrtimer:    3001 sec, 350677038 ns, interval_delay=17552 ns
hrtimer:    3021 sec, 420625114 ns, interval_delay=17487 ns
hrtimer:    3041 sec, 490744847 ns, interval_delay=17529 ns


hrtimerLinux内核中的一个重要功能,可提供高精度定时器功能。它可以在纳秒级别的精度下进行定时,主要用于实时任务或需要高精度定时的应用。 使用hrtimer高精度的方法如下: 1. 定义hrtimer: 使用hrtimer之前,首先需要定义一个hrtimer对象。可以通过声明struct hrtimer类型的变量来完成,例如: struct hrtimer my_hrtimer; 2. 初始化hrtimer: 初始化hrtimer对象可以使用hrtimer_init函数,该函数有三个参数:hrtimer对象,时钟源和是相对还是绝对时间。根据具体需要,可以选择不同的时钟源,如CLOCK_MONOTONIC或CLOCK_REALTIME。 3. 设置并启动hrtimer: 设置hrtimer对象的定时器周期和回调函数,然后使用hrtimer_start函数启动hrtimer。设置定时器周期可以使用hrtimer_set_periodic或hrtimer_set_expires函数。回调函数会在定时器到期时被调用。 4. 处理hrtimer到期: 当hrtimer到期时,会触发之前设置的回调函数,我们可以在回调函数中执行相应的操作。 5. 停止hrtimer: 如果需要停止hrtimer,可以使用hrtimer_cancel函数。 综上所述,通过使用Linux内核的hrtimer模块,我们可以实现高精度的定时功能。这对于实时任务或需要高精度定时的应用至关重要。通过定义、初始化、设置和启动hrtimer对象,可以实现定时器的定期触发和相应的操作。同时,可以根据需要选择不同的时钟源来满足特定的应用需求。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值