Transferred from: http://blog.csdn.net/waverider2012/article/details/38305785
The interval of the Hrtimer high-precision timer is determined by the Ktime_set (const long secs, const unsigned long nsecs) and can be NS-level. The example here is 5ms interval:
[CPP]View PlainCopy
- #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 is still in use...\n");
- PRINTK ("HR Timer module uninstalling\n");
- return;
- }
- Module_init (Module_hrtimer_init);
- Module_exit (Module_hrtimer_exit);
If you return directly to Hrtimer_restart in My_hrtimer_callback () it will cause immediate re-entry into My_hrtimer_callback (). At this point the shell does not respond to the input.
So in order to solve this problem, a work queue was created, My_hrtimer_callback () enqueue This Task Force column. Restart Hrtimer in the work queue's handler function.
However, the negative effect is that the delay introduced by Linux system scheduling between Hrtimer_callback and Wq_func is called, resulting in interval errors. After measurement, in the ZC706 default configuration, this delay is approximately 17.5us (Hrtimer interval is 5ms, the interval error is calculated every 20 seconds).
[Plain]View PlainCopy
- [Email protected]:~/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
Hrtimer High-precision timer "turn" under Linux