任务:板子上增加了独立的复位芯片SP706S,为了在设备死机的时候重启系统。
资源:芯片使能管脚 PH13 喂狗管脚 PI16
1. 为了省事,直接在drivers/sunxi_gpio/gpio_sw.c这个文件里加了,这里有现成的操作GPIO管脚的函数例子,而且还有
获取GPIO号的函数例子。
2. 这个驱动实际就是A20的GPIO驱动,也是一个平台总线驱动,他为每一个sys_config.fex里配置的GPIO调用probe函数创建驱动。
3. 我们先在probe函数的最后面增加这一句,以获得GPIO的号码
printk(KERN_ERR "------gpio %s = %d\n", pdata->name, item.gpio.gpio);
4. 然后接着增加看门狗使能和喂狗定时器
if(!strcmp("gpio_pin_10", pdata->name))
{
__gpio_set_value(item.gpio.gpio,1);
printk(KERN_ERR "-------enable watchdog-------");
init_timer(&mytimer);
mytimer.expires = jiffies;
mytimer.data = 0;
mytimer.function = watchdog_timer;
add_timer(&mytimer);
}
gpio_pin_10是我使用的看门狗使能的gpio名字,另外,probe函数会被执行多次,有几个gpio会执行几次,所以
关于定时器的这几个函数一定要放到这个括号里,否则会多次初始化定时器,会出现意想不到的效果。
其中一块板子,我在定时函数里做的打印,现象就是打印频率比我设置的时间要快的多。最后发现是因为多个定时器一起在跑。
另一块板子,直接就内存泄露了。报这个错,Unable to handle kernel NULL pointer dereference。
耽误了我整整3个小时时间就查这个问题。
5. 增加喂狗定时器函数
#include <linux/sched.h>
#include <linux/timer.h>
struct timer_list mytimer;
static dog = 0;
void watchdog_timer(unsigned long arg)
{
printk(KERN_ERR "feed watchdog %d\n", dog);
dog = ! dog;
__gpio_set_value(217,dog); //217为gpio编号
mytimer.expires = jiffies+ 50; // 500ms
mytimer.data = 0;
mytimer.function = watchdog_timer;
add_timer(&mytimer);
}
6. 下面是定时器喂狗函数的打印,可以看出,linux内核定时器的精度是相当高的。我设置的是500ms的定时器,
通过下图的计算可以看出,误差基本在10us以内。