一、看门狗定时器概述
看门狗(WatchDog Timer) 定时器和PWM的定时功能目的不一样。它的特点是,需要不同的接收信号(一些外置看门狗芯片)或重新设置计数器,保持计数值不为0。一旦一些时间接收不到信号,或计数值为0,看门狗将发出复位信号复位系统或产生中断。
看门狗的作用是微处理器收到干扰进入错误状态后,使系统在一定时间间隔内复位。因此看门狗是保证系统长期、可靠和稳定运行的有效措施。目前大部分的嵌入式芯片内部都集成了看门狗定时器来提高系统运行的可靠性。
4412处理器的看门狗是当系统被故障干扰时,用于处理器的复位操作,也可以作为一个通用的16位定时器来请求中断操作。看门狗定时器产生128个PCLK周期的复位信号。主要特性有如下两个。
1)通用的中断方式的16位定时器。
2)当计数器减到0(发生溢出)时,产生128个PCLK周期的复位信号。
看门狗定时器功能框图如下:
看门狗模块包括一个预比例因子放大器,一个四分频的分频器,一个16位计数器。看门狗的时钟信号源来自PCLK,为了得到宽范围的看么狗信号,PCLK先被预分频,然后再进过分频器分频。预分频比例因子和分频器的分频值,都可以由看门狗控制寄存器(WTCON)决定,预分频比例因子的范围是0~255,分频器的分频比可以是16、32、64或128。看门狗定时器时钟周期的计算如下:
式中Prescaler value 为预分频比例放大器的值;Divison_factor是四分频的分频比,可以是16、32、64或128.
一旦看门狗定时器被允许,看门狗定时器数据寄存器(WTDAT)的值就不能被自动地装在到看门狗定时器(WTCNT)中。因此,看门狗启动前要将一个初始值写入看门狗计数器(WTCNT)中。当4412用嵌入式ICE调试时,看门狗定时器的复位功能就不被启动,看门狗定时器能从CPU内核信号判断出当前CPU是否处于调试状态。如果看门狗定时器确定当前模式是调试模式,尽管看门狗产生溢出信号,但是仍然不会产生复位信号。
二、看门狗定时器相关定时器
1、看门狗定时器控制寄存器(WTCON)
WTCON寄存器的内容包括:用户是否启动看门狗定时器、4个分频比的选择、是否允许中断产生、是否允许复位操作等。
如果用户想把看门狗定时当做一般定时器使用,应该中断使能,禁止看门狗定时器复位。
WTCON描述如下:
2、看门狗定时器数据寄存器(WTDAT)
WTDAT用于指定超时时间,在看门狗把复位功能禁止并打开中断使能后,此时看门狗定时器就是一个普通的定时器,使用方法和普通定时器一样。当使用复位功能后,由于WTCNT的值减到0时,系统就会复位,所以WTCNT的值装不进看门狗计数寄存器(WTCNT)中。复位后初始值为0x8000。WTDAT描述如下:
3、看门狗计数寄存器(WTCNT)
WTCNT包含看门狗定时器工作的时候,计数器的当前计数值。WTCNT描述如下:
三、看门狗定时器的程序编写
1、看门狗软件程序设计流程
以为看门狗是对系统地复位或中断的操作,所以不需要外围的硬件电路。要实现看门狗的功能,只需要对看门够的寄存器组进行操作,即对看门狗的控制寄存器(WTCON)、看门狗数据寄存器(WTDAT)、看门狗计数寄存器(WTCNT)的操作。
其一般流程如下:
1)设置看门狗中断操作,包括全局中断和看门狗中断使能及看门狗中断向量的定义,如果只是进行复位操作,这一步不用设置。
2)对看门狗控制寄存器(WTCON)的设置,包括设置预分频比例因子、分频器的分频值,中断使能和复位使能等。
3)对看门狗数据寄存器(WTDAT)和看门狗计数寄存器(WTCNT)的设置。
4)启动看门狗定时器。
2、具体代码如下:
#include "exynos_4412.h" #include "led.h" #include "pwm.h" void mydelay_ms(int time) { int i, j; while(time--) { for (i = 0; i < 5; i++) for (j = 0; j < 514; j++); } } //*(volatile unsigned int *)(0x11000c20) = 0; /* * 裸机代码,不同于LINUX 应用层, 一定加循环控制 */ void do_irq(void) { static int a = 1; int irq_num; irq_num = CPU0.ICCIAR&0x3ff; //获取中断号 switch(irq_num) { case 57: printf("in the irq_handler\n"); EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); //清GPIO中断标志位 ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); //清GIC中断标志位 break; case 75: printf("in the WDT interrupt!\n"); WDT.WTCLRINT = 0; ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 11); //清GIC中断标志位 break; } CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num; //清cpu中断标志位 } void wdt_init(void) { WDT.WTCON = (249 << 8) | (1 << 5) | (1 << 2)|(1 << 0); WDT.WTDAT = 25000; ICDDCR = 1; //使能分配器 ICDISER.ICDISER2 = ICDISER.ICDISER2 | (0x1 << 11); //使能相应中断到分配器 ICDIPTR.ICDIPTR18 = ICDIPTR.ICDIPTR18 & (~(0xff << 24))|(0x1 << 24); //选择CPU接口 CPU0.ICCPMR = 255; //中断屏蔽优先级 CPU0.ICCICR = 1; //使能中断到CPU } int main (void) { wdt_init(); printf("hello reset!\n"); while(1) { WDT.WTCNT = 25000; mydelay_ms(100); } return 0; }