zoukankan      html  css  js  c++  java
  • Linux下的hrtimer高精度定时器【转】

    本文转载自:http://blog.csdn.net/waverider2012/article/details/38305785

    hrtimer高精度定时器的interval由ktime_set(const long secs, const unsigned long nsecs)决定,可做到ns级。此处的例子为5ms interval:

    [cpp] view plain copy
     
    1. #include <linux/kernel.h>  
    2. #include <linux/module.h>  
    3. #include <linux/hrtimer.h>  
    4. #include <linux/ktime.h>  
    5.   
    6. MODULE_LICENSE("GPL");  
    7.   
    8. static struct hrtimer hr_timer;  
    9. static struct work_struct wq_hrtimer;    
    10. static ktime_t ktime;  
    11. static unsigned int interval=5000; /* unit: us */  
    12. struct timespec uptimeLast;  
    13.   
    14. static unsigned int count=0;  
    15. #define COUNT_INTERVAL 4000  
    16. unsigned long long diff_tv(struct timespec start, struct timespec end) {  
    17.     return (end.tv_sec-start.tv_sec)*1000000000+(end.tv_nsec-start.tv_nsec);  
    18. }  
    19.   
    20. enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer )  
    21. {  
    22.     schedule_work(&wq_hrtimer);   
    23.     return HRTIMER_NORESTART;  
    24. }  
    25.   
    26. static void wq_func_hrtimer(struct work_struct *work)  
    27. {   
    28.     struct timespec uptime;  
    29.   
    30.     hr_timer.function = my_hrtimer_callback;   
    31.     ktime = ktime_set( interval/1000000, (interval%1000000)*1000 );  
    32.     hrtimer_start(&hr_timer, ktime, HRTIMER_MODE_REL );  
    33.   
    34.     /* print time every COUNT_INTERVAL*interval second*/  
    35.     if(count%COUNT_INTERVAL==0)   
    36.     {  
    37.         do_posix_clock_monotonic_gettime(&uptime);    
    38.         printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns, interval_delay=%lu ns ",   
    39.             (unsigned long) uptime.tv_sec, uptime.tv_nsec,  
    40.             (unsigned long)(diff_tv(uptimeLast, uptime)-interval*1000*COUNT_INTERVAL)   
    41.                 /COUNT_INTERVAL);   
    42.         uptimeLast=uptime;  
    43.     }  
    44.     count++;  
    45. }   
    46.   
    47. static int __init module_hrtimer_init( void )  
    48. {  
    49.     struct timespec uptime;   
    50.       
    51.     printk(KERN_INFO"HR Timer module installing ");  
    52.       
    53.     hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );  
    54.     
    55.     ktime = ktime_set( interval/1000000, (interval%1000000)*1000 );  
    56.     hr_timer.function = my_hrtimer_callback;  
    57.   
    58.     hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );  
    59.   
    60.     do_posix_clock_monotonic_gettime(&uptime);  
    61.     uptimeLast = uptime;  
    62.     printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns ", (unsigned long) uptime.tv_sec,    
    63.                                         uptime.tv_nsec );   
    64.   
    65.     INIT_WORK(&wq_hrtimer, wq_func_hrtimer);  
    66.     return 0;  
    67. }  
    68.   
    69. static void __exit module_hrtimer_exit( void )  
    70. {  
    71.     int ret;  
    72.   
    73.     ret = hrtimer_cancel( &hr_timer );  
    74.     if (ret)   
    75.         printk("The timer was still in use... ");  
    76.   
    77.     printk("HR Timer module uninstalling ");  
    78.     return;  
    79. }  
    80.   
    81. module_init(module_hrtimer_init);  
    82. 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误差)。

    [plain] view plain copy
     
      1. root@zynq:~/nfs/hrtimer# insmod hrtimer.ko  
      2. HR Timer module installing  
      3. hrtimer:    2900 sec, 993366078 ns  
      4. hrtimer:    2900 sec, 998395278 ns, interval_delay=369966 ns  
      5. hrtimer:    2921 sec,  69525447 ns, interval_delay=17782 ns  
      6. hrtimer:    2941 sec, 139764655 ns, interval_delay=17559 ns  
      7. hrtimer:    2961 sec, 210029519 ns, interval_delay=17566 ns  
      8. hrtimer:    2981 sec, 280465631 ns, interval_delay=17609 ns  
      9. hrtimer:    3001 sec, 350677038 ns, interval_delay=17552 ns  
      10. hrtimer:    3021 sec, 420625114 ns, interval_delay=17487 ns  
      11. hrtimer:    3041 sec, 490744847 ns, interval_delay=17529 ns 
  • 相关阅读:
    angularjs的$on、$emit、$broadcast
    angularjs中的路由介绍详解 ui-route(转)
    ionic入门教程-ionic路由详解(state、route、resolve)(转)
    Cocos Creator 加载使用protobuf第三方库,因为加载顺序报错
    Cocos Creator 计时器错误 cc.Scheduler: Illegal target which doesn't have uuid or instanceId.
    Cocos Creator 构造函数传参警告 Can not instantiate CCClass 'Test' with arguments.
    Cocos Creator 对象池NodePool
    Cocos Creator 坐标系 (convertToWorldSpaceAR、convertToNodeSpaceAR)
    Cocos Creator 常驻节点addPersistRootNode
    Cocos Creator 配合Tiled地图的使用
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7098243.html
Copyright © 2011-2022 走看看