Watchdog做过项目的同学应该不会陌生,主要是启动程序守护作用,程序跑飞后能够让MCU重新复位,让设备进入正常工作模式,通常所说的看门狗,普通的看门狗喂狗的周期是1.6S,只要在1.6S的时间内,让看门狗的喂狗电平进行反转一次,看门狗内部的计数器就会清0,如果超过1.6S周期没有反转喂狗信号,则会发出一个下降沿的电平给MCU的RST引脚,MCU从而复位。
普通单片机的操作是这样的,如果换成了ARM系统,1.6S周期对于Linux来说,启动时间是不够的,先从bootstrap->uboot->kernel->文件系统->应用程序;这个过程下来大概要10S时间,已经算是非常快了。
我接触的Linux系统方案有以下两种:
1、看门狗的Rst引脚和ARM的Rst脚之间加一个使能芯片,就像是一个开关一样,默认是关闭的,复位信号过不来,系统起来后,应用程序把开关打开,让复位信号导通;
缺点就是无法保证复位信号是不是导通的,也不能很清晰的知道硬件的开关是否正常。
2、ARM的外侧加一个单片机用来喂狗,ARM与单片机使用串口通讯,在系统启动之前喂狗权在单片机上面,系统启动后双机能够正常通讯喂狗权交给ARM。
缺点成本较高,通讯复杂。
3、基于以上两种呢,都不是很优的方案,后面找了一款超长时间的比较器,也能输出RST信号,用作看门狗比较好,并且还能输出提醒喂狗信号,ARM端可以做是否焊接看门狗芯片的逻辑;
下面主要介绍一下Linux下的字符驱动编写:
上期有小伙伴提了疑问,为什么IO的配置不放在设备树里面呢,你把IO配置还写在字符驱动的头文件当中是不是很Low,感觉不是很方便啊,工作和项目中难道是这么用的吗?
设备树里面放对应字符驱动IO配置当然没有问题,我现在目前的字符驱动都是模块驱动,就是不用更改内核的情况下可以随意更改驱动,就像是个应用程序一样,编译好的文件放入文件系统中,然后使用命令加载就可以了,如果IO的配置放在设备树里面,管脚有改动的话还要重新烧录设备树问题,根本做不到远程升级字符驱动,不利于应付工作中的突发需求。
关注微信公众号,回复“看门狗字符驱动”,下载源代码。
字符驱动的模型还是套用gpio系统;
1、模块的入口函数
module_init(at91_watdog_init);
module_exit(at91_watdog_cleanup);
MODULE_DESCRIPTION ("AT91 watdog detect DRIVER");
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR ("Jack");
MODULE_LICENSE ("GPL");
调用insmod和rmmod的时候会调用这两个函数;
2、创建init和cleanup函数
定义初始化信息,喂狗信号和捕捉提醒喂狗信号
struct watdog_pin
{
ulong wdgfree_pin; //
ulong wdgdete_pin; //
};
struct St_watdog
{
dev_t dev_major;
int sys_irq;
int hard_irq;
atomic_t open_count;
int detect_flag;// 断电检查标志
struct watdog_pin st_pin;
struct mutex watdog_mudex;//互斥锁
spinlock_t watdog_spinlock;
wait_queue_head_t watdog_poll_head;
struct cdev watdog_dev;//
struct class *watdog_class;
struct device *watdog_device;
};
3、注册及注销驱动流程
static int __init at91_watdog_init(void)
{
int retval = -1;
dev_t dev_id;
// 分配一个结构
pwdg = (struct St_watdog *)kzalloc(sizeof (struct St_watdog),GFP_KERNEL);
if(!pwdg)
{
printk("%s:kzalloc failded from:%s\n", __func__,WATCHDOG_NAME);
return -ENOMEM;
}
//需要减去偏移量
pwdg->st_pin.wdgfree_pin = WATCHDOG_PIN;
pwdg->st_pin.wdgdete_pin = WATDETECT_PIN;
mutex_init(&(pwdg->watdog_mudex));
spin_lock_init(&(pwdg->watdog_spinlock));
//init_timer
init_waitqueue_head(&pwdg->watdog_poll_head);
pwdg->detect_flag =0;
//分配主设备号
if (watdog_major) {
dev_id = MKDEV(watdog_major, 0);
retval = register_chrdev_region(dev_id, MAX_WATDOG_NB,
WATCHDOG_NAME);
} else {
retval = alloc_chrdev_region(&dev_id, 0, MAX_WATDOG_NB,
WATCHDOG_NAME);
watdog_major = MAJOR(dev_id);
}
if(retval<0)
{
printk("watdog: register error!\n");
goto error_malloc