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操作的设置
上图就是一个看门狗的操作流程,需要按描述进行相应配置
这里一共有四个寄存器:
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");