嵌入式学习7--动态定时器和看门狗

1.在嵌入式系统中,定时器的使用时非常普遍的,看门狗、中断触发、防抖之类的功能和定时器有一定的关系,而linux中动态定时器的使用也是非常方便的,可以帮助我们完成很多的功能。动态定时器是依赖于内核时钟的,所以在使用的时候需要注意触发周期的设置。

下面简单介绍一下动态定时器的使用方法:

#include
#include
#include
#include

static struct timer_list dynamic_timer;        //定义一个动态定时器

static void dynamic_func(unsigned long data)  //定时器服务函数
{
    printk("<4>" "HZ = %d\n", HZ);
    printk("<4>" "jiffies = %lu\n", jiffies);
    printk("<4>" "data = %ld\n", data);
    printk("<4>" "dynamic_timer.expires = %lu\n", dynamic_timer.expires);

   /*此处修改动态定时器的触发时间,意思是定时器触发一次以后,在这里修改下一次的触发时间*/
    mod_timer(&dynamic_timer, dynamic_timer.expires+100);    
}

static int __init dynamic_timer_init(void)    
{
    init_timer(&dynamic_timer);    //初始化动态定时器
    
    dynamic_timer.function = &dynamic_func;   //定时器的服务函数
    dynamic_timer.expires = jiffies+100;            //定时器的触发时间
    dynamic_timer.data = 333;                           //传入服务函数的参数
    
    add_timer(&dynamic_timer);                        //将动态定时器加入内核
    
    printk("dynamic timer init\n");
    return 0;
}

static void __exit dynamic_timer_exit(void)
{
    del_timer(&dynamic_timer);                          //删除定义的动态定时器
    printk("dynamic timer exit\n");
}

module_init(dynamic_timer_init);
module_exit(dynamic_timer_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("dynamic timer demo");
MODULE_LICENSE("GPL");

2.看门狗是可以分为硬件和软件看门狗,是至关重要的功能,它可以起到保护系统的作用,在一些发生干扰或者程序发生异常的情况下,看门狗可以将系统进行复位,提高系统的可靠性。如果看门狗只是一个普通定时器实现的,那么就是一个软件看门狗,如果是依赖于硬件定时器的,那么就是硬件看门狗,这里主要介绍硬件看门狗。

硬件看门狗在使用的时候可以做一个普通定时器使用,也可以作为一个触发复位的定时器使用。

看门狗的原理就是计数值一直减,减到0就触发中断,所以需要判断,在没有减到0之前进行喂狗

我们在配置一个看门狗的时候主要注意以下几点:

1)定时器精度,本文描述的看门狗就是一个16bit的,这意味着看门狗的计数值为2^16,也就是0--65535

2)预分频,这个要看datasheet来确认,本文的预分频系数0--(8-1)

3)分频因子的设置

4)计数值的设置

5)reset操作的设置

嵌入式学习7--动态定时器和看门狗_第1张图片

上图就是一个看门狗的操作流程,需要按描述进行相应配置

这里一共有四个寄存器:

嵌入式学习7--动态定时器和看门狗_第2张图片

嵌入式学习7--动态定时器和看门狗_第3张图片

WTCON:设置预分频、分频因子、是否产生中断、是否reset以及开启或关闭看门狗

WTDAT:定时计数值

WTCNT:计数器,当寄存器中值减为0触发中断

WTCLRINT:写任意值清除中断

以下程序将看门狗作为一个混杂设备进行配置

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include
#include

#define WT_DEVICE "watch dog"        

/*静态映射看门狗寄存器的物理地址*/
#define WT_REGMAP_SIZE (0x1000)
#define WT_BASE (0xC0019000)
#define WT_IOREG(x) ((x)+IO_ADDRESS(WT_BASE))
#define WTCON WT_IOREG(0x00)
#define WTDAT WT_IOREG(0x04)
#define WTCNT WT_IOREG(0x08)
#define WTCLRINT WT_IOREG(0x0C)

#define WT_S_START _IO('w', 1)
#define WT_S_STOP  _IO('w', 2)
#define WT_S_KEEPALIVE _IO('w', 3)

static int data = 123;

irqreturn_t wt_isr(int irq, void *dev)
{
    int data = *(int *)dev;
    
    writel(0, WTCLRINT);
    writel(0xEE66, WTCNT);
    printk("<4>" "watch dog is running, data = %d\n", data);

    return IRQ_HANDLED;
}

int wt_open(struct inode *inode, struct file *filp)
{
    //writel((255<<8)|(3<<3)|(1<<2)|(1<<0), WTCON);  //设置预分频为256,分频因子为128,使能中断,开启reset

    /*不触发reset,需要将中断和reset寄存器关闭*/
    //writel((255<<8)|(3<<3), WTCON);
    //writel(readl(WTCON)&(~((1<<0)|(1<<2))), WTCON);

    printk("<4>" "watch dog timer open\n");
    
    return 0;
}

long wt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
    switch(cmd){
    case WT_S_START:   //开启看门狗
        writel(readl(WTCON)|(1<<5), WTCON);
        printk("<4>" "watch dog start\n");
        break;
        
    case WT_S_STOP:   //停止看门狗
        writel((readl(WTCON)&(~(1<<5)|(1<<0))), WTCON);
        writel(0, WTCLRINT);
        printk("<4>" "watch dog stop\n");
        break;
        
    case WT_S_KEEPALIVE:  //看门狗喂狗
        writel(0, WTCLRINT); 
        writel(0xEE66, WTCNT);
        printk("<4>" "watch dog keep alive\n");
        break;
    }
    
    return 0;
}

int wt_release(struct inode *inode, struct file *filp)
{
    writel((readl(WTCON)&(~(1<<5)|(1<<0))), WTCON);
    writel(0, WTCLRINT);
    printk("<4>" "watch dog timer close\n");
    
    return 0;
}

static struct file_operations fops= {
    .owner = THIS_MODULE,
    .open = wt_open,
    .read = wt_read,
    .write = wt_write,
    .release = wt_release,
    .unlocked_ioctl = wt_unlocked_ioctl,
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = WT_DEVICE,
    .fops = &fops,
};

static int __init watch_dog_init(void)
{
    int ret = 0;

    nxp_soc_peri_reset_set(RESET_ID_WDT);
    nxp_soc_peri_reset_set(RESET_ID_WDT_POR);
    
    ret = misc_register(&misc);
    if(ret != 0)
        return -EBUSY;
    

    /*初始化看门狗*/
    writel(0, WTCON);

   /*

0xEE66为10S的间隔,由于pclk为200MHz,所以计算公式为

61030(0xEE66H) = 200000000/256/128*10

*/
    writel(0xEE66, WTDAT);  
    writel(0xEE66, WTCNT);
    writel(0, WTCLRINT);
    
    printk("watch dog timer init\n");
    
    return ret;
}

static void __exit watch_dog_exit(void)
{
    misc_deregister(&misc);
    
    printk("watch dog timer exit\n");
}

module_init(watch_dog_init);
module_exit(watch_dog_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("watch dog timer demo");
MODULE_LICENSE("GPL");

 

 

你可能感兴趣的:(嵌入式)