记录工作成长中的点滴
2012-12-12
在最近公司的一个项目中,突然发现ep阶段的代码能正常复位3G模块,发现并创建设备节点,但PP阶段的板子出来后,同样的代码复位3G模块失败。
分析原理图发现在PP阶段3G模块的供电新增了延时电路,示波器测量也验证了开机6S后,3G模块才上电。而EP阶段的代码执行3G模块复位的时间大概
是在开机5s左右,而此时PP阶段的3G模块都还没有供电,自然也就无法复位成功。
也就是说要延时1~2s左右,才能给3G模块复位,实现如下:
首先排除简单的在复位代码前加ssleep(1);来实现延时,因为这样为直接导致kernel启动速度延时s。
想想可以通过内核线程中ssleep(1)的方式或timer来实现延时。
分别使用内核线程和timer的方式实现并验证了延时复位3G的功能,最终采用了timer的方式。
timer的方式的实现:1. 创建一个tiemr,
2. 调用init_timer()将其初始化;
3. 为timer成员赋值,通常只要将其中的expires和function成员赋值。
expires表示过多久之后启动;function: 超时处理函数
4. 调用add_timer()将timer添加到定时器等待队列
5. 实现超过处理函数。
代码如下:
static void pw_on_3g(unsigned long data)
{
// 注意在此处不可以调用可休眠的函数,如msleep()之类的,
// 否则会报错:BUG: scheduling while atomic
3G模块复位gpio操作 // step: 5
}
static struct timer_list pw_3g_timer; // step: 1
static int __init setup_pw_3g(void)
{
init_timer(&pw_3g_timer); // step: 2
pw_3g_timer.expires = jiffies + HZ; // step: 3
pw_3g_timer.function = pw_on_3g;
add_timer(&pw_3g_timer); // step: 4
return 0;
}
late_initcall(setup_pw_3g);
内核线程的方式实现:1. 创建1个内核线程,
2. 实现内核线程函数;
static void pw_on_3g(unsigned long data)
{
3G模块复位gpio操作 // step: 2
}
static int __init setup_pw_3g(void)
{
static struct task_struct *tstask;
tstask = kthread_run(pw_3g_thread, NULL, "mxc_3g"); // step: 1
if (IS_ERR(tstask)) {
tstask = NULL;
return -1;
}
return 0;
}
late_initcall(setup_pw_3g);