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  阅读(20)  评论(0编辑  收藏  举报

导航