Linux在驱动里做定时循环
1. 使用内核定时器 实现
思路是,在驱动里使用一个内核定时器,定时一个时间后,执行回调函数,再在回调函数里重新设置一次定时时间,以此往复,在回调函数里里执行自己的业务
Linux4.4内核
定时器内核源码位置:linux-4.1.15/kernel/time/timer.c
/* 一些变量 */
#define POLL_PERIOD (HZ/1) /* (HZ/100): Polling period .01 seconds (10ms) */ static void thcvxxx_detect_do_poll(unsigned long dummy); static DEFINE_TIMER(thcvxxx_detect_timer, thcv241_detect_do_poll, 0, 0);
/* 开始定时器 */ mod_timer(&thcvxxx_detect_timer, jiffies + POLL_PERIOD);
/* 回调函数 */ static void thcvxxx_detect_do_poll(unsigned long dummy) {
/* 自定义业务 */
......
/* 重新开始定时器 */
mod_timer(&thcv241_detect_timer, jiffies + POLL_PERIOD);
/* 自定义业务 */
...... }
或者
/* 一些变量 */
#define POLL_PERIOD (HZ/1) /* (HZ/100): Polling period .01 seconds (10ms) */
static struct timer_list timer; static void thcvxxx_detect_do_poll(unsigned long dummy);
/* 开始定时器 */ init_timer(&timer); timer.function= thcvxxx_detect_do_poll; timer.expires = jiffies + 1*HZ; add_timer(&timer);
static void thcvxxx_detect_do_poll(unsigned long dummy) { ...... timer.expires = jiffies + 1*HZ; add_timer(&timer); // 重新开始计时 ...... }
以上两种方式,都可以实现定时循环。
存在问题:
当在回调函数里执行iic读写时,会报错如下
------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at /home/ex/os/kernel/kernel/locking/rtmutex.c:1536 rt_mutex_trylock+0x6c/0xc4() Modules linked in: sensor_ov9x7x3x4_thcvxxx(O) ak_isp(O) ak_mci(O) mmc_block mmc_core ak_fb(O) ak_gui(O) ak_uio(O) ak_leds(O) ak_ion(O) ak_gpio_keys(O) ak_pcm(O) ak_i2c(O) ak_rtc(O) CPU: 0 PID: 0 Comm: swapper Tainted: G W O 4.4.192V2.2 #5 Hardware name: A*K*3*7*D Backtrace: [<c000d4e8>] (dump_backtrace) from [<c000d6e0>] (show_stack+0x18/0x1c) r6:c030facc r5:00000009 r4:00000000 r3:00000000 [<c000d6c8>] (show_stack) from [<c01681a0>] (dump_stack+0x20/0x28) [<c0168180>] (dump_stack) from [<c00175bc>] (warn_slowpath_common+0x80/0xb8) [<c001753c>] (warn_slowpath_common) from [<c0017698>] (warn_slowpath_null+0x24/0x2c) r8:c0438c40 r7:c0439460 r6:c042dd74 r5:c78c7420 r4:c78c7410 [<c0017674>] (warn_slowpath_null) from [<c030facc>] (rt_mutex_trylock+0x6c/0xc4) [<c030fa60>] (rt_mutex_trylock) from [<c01eacb4>] (i2c_trylock_adapter+0x30/0x4c) r5:00000001 r4:c78c7410 [<c01eac84>] (i2c_trylock_adapter) from [<c01eb510>] (i2c_transfer+0x54/0xc8) [<c01eb4bc>] (i2c_transfer) from [<c01eb5c8>] (i2c_master_send+0x44/0x54) r6:00000200 r5:bf0b7f14 r4:00000002 r3:00000000 [<c01eb584>] (i2c_master_send) from [<bf0b7d3c>] (i2c_read_reg2_value1+0x2c/0x54 [sensor_ov9x7x3x4_thcvxxx]) r4:c78c7600 [<bf0b7d10>] (i2c_read_reg2_value1 [sensor_ov9x7x3x4_thcvxxx]) from [<bf0b7e58>] (i2c_read+0x50/0x70 [sensor_ov9x7x3x4_thcvxxx]) r4:c78c7600 [<bf0b7e08>] (i2c_read [sensor_ov9x7x3x4_thcvxxx]) from [<bf0b54f8>] (ov9734_sensor_get_parameter_func+0x164/0x178 [sensor_ov9x7x3x4_thcvxxx]) [<bf0b5494>] (ov9734_sensor_get_parameter_func [sensor_ov9x7x3x4_thcvxxx]) from [<bf0b5528>] (ov9734_sensor_probe_id_func+0x1c/0x84 [sensor_ov9x7x3x4_thcvxxx]) r5:c78c7600 r4:bf0b9700 [<bf0b550c>] (ov9734_sensor_probe_id_func [sensor_ov9x7x3x4_thcvxxx]) from [<bf0b5620>] (thcv241_detect_do_poll+0x90/0xb0 [sensor_ov9x7x3x4_thcvxxx]) r5:bf0b5590 r4:bf0b9700 [<bf0b5590>] (thcv241_detect_do_poll [sensor_ov9x7x3x4_thcvxxx]) from [<c00482a4>] (call_timer_fn+0x2c/0xa4) r4:00000100 r3:c042de28 [<c0048278>] (call_timer_fn) from [<c00488b8>] (run_timer_softirq+0x118/0x1e8) r6:00000200 r5:00000000 r4:c0438c40 [<c00487a0>] (run_timer_softirq) from [<c001a0a4>] (__do_softirq+0xf4/0x238) r8:c042c000 r7:40000001 r6:00000100 r5:00000002 r4:00000001 [<c0019fb0>] (__do_softirq) from [<c001a48c>] (irq_exit+0xa8/0xf4) r10:80425a70 r9:c7fff460 r8:00000000 r7:00000000 r6:00000000 r5:c043d05c r4:00000000 [<c001a3e4>] (irq_exit) from [<c0040594>] (__handle_domain_irq+0x74/0xd0) r4:00000000 r3:00000000 [<c0040520>] (__handle_domain_irq) from [<c0009024>] (asm_do_IRQ+0x24/0x28) r8:c04464e2 r7:c042df54 r6:1380952e r5:60000013 r4:c000ab18 r3:c042df20 [<c0009000>] (asm_do_IRQ) from [<c000e000>] (__irq_svc+0x40/0x270) Exception stack(0xc042df20 to 0xc042df68) df20: 00000000 0005317f 0005217f 60000013 c042c000 c042e06c c042e06c c04464e2 df40: c04464e2 c7fff460 80425a70 c042df7c 600000d3 c042df70 c000ab20 c000ab18 df60: 60000013 ffffffff [<c000aaec>] (arch_cpu_idle) from [<c003a8fc>] (default_idle_call+0x28/0x3c) [<c003a8d4>] (default_idle_call) from [<c003a9d4>] (cpu_startup_entry+0xc4/0x120) [<c003a910>] (cpu_startup_entry) from [<c030ccb4>] (rest_init+0x64/0x7c) r7:c042e000 r3:c0311ac0 [<c030cc50>] (rest_init) from [<c040ac3c>] (start_kernel+0x2dc/0x33c) [<c040a960>] (start_kernel) from [<80008044>] (0x80008044) ---[ end trace cab02c313e6f2366 ]---
2. 使用内核定时器 + 工作队列 实现
针对以上报错,加入工作队列实现:
/* 一些变量 */
#define POLL_PERIOD (HZ/1) /* (HZ/100): Polling period .01 seconds (10ms) */
static struct timer_list timer;
static void thcv241_detect_do_poll(unsigned long dummy);
static struct work_struct my_work;
static void my_work_poll(struct work_struct *unused);
/* 开始定时器 */ init_timer(&timer); timer.function= thcv241_detect_do_poll; timer.expires = jiffies + 1*HZ; add_timer(&timer); INIT_WORK(&my_work, my_work_poll);
/* 定时器回调函数 */ static void thcv241_detect_do_poll(unsigned long dummy) { timer.expires = jiffies + 1*HZ; add_timer(&timer); // 重新开始计时
schedule_work(&my_work); }
/* 工作队列回调函数 */ static void my_work_poll(struct work_struct *unused) { /* 自定义业务,如iic读写 */
...... }
使用以上方法,在工作队列里 定时读写iic,不会报错了。
posted on 2024-09-06 09:12 f1engmin11 阅读(12) 评论(0) 编辑 收藏 举报