ILD

Watchdog timer
作者:Herbert Yuan 邮箱:yuanjp89@163.com
发布时间:2017-11-6 站点:Inside Linux Development

1 介绍

看门狗定时器用来当系统由于噪声或者系统错误而malfunction时将系统恢复过来。它可以用作一个普通的16位内部定时器,来产生中断请求。看门狗定时器产生128个PCLK周期的复位信号。


看门狗定时器使用PCLK作为时钟源,首先经过一个8位预分频器,然后再分频一次,再分频系数可为16, 32, 64或128,这样就产生看门狗定时器时钟,频率为:

f = PCLK / (1 + prescaler value) / division_factor


一旦看门狗定时器开启,定时器数据的值不会自动改变,所以需要在看门狗定时器启动前写入初始值。


当CPU处于调试模式时,看门狗不会输出复位信号。一旦DBGACK信号asserted。


2 相关寄存器

Watchdog timer control (WTCON) register

用来开启/关闭看门狗、选择时钟源,开启/关闭中断,开启/关闭定时器输出。

RegisterAddressR/WDescReset value
WTCON0x53000000R/WWatchdog timer control register0x8021


WTCONbitdescinital state
Prescaler value[15:8]

Prescaler value

0-255

0x80
Reserved[7:6]must be 0000
watchdog timer[5]

enable or disable bit of watchdog timer

0 = disable

1 = enable

1
clock select[4:3]

determine the clock division factor

00: 16 01:32

10:64 11:128

00
interrupt generation[2]

enable or disable bit of the interrupt

0 = disable

1 = enable

0
reserved[1]must be 000
reset enable/disable[0]

enable or disable bit of watchdog timer output for reset signal

1: assert reset signal, at watchdog time-out

0: disable the reset function of the watchdog timer

1


Watchdog timer data  (WTDAT) register

确定超时的长度,第一次启动看门狗不会自动加载到WTCNT,只有在超时时才会自动加载到WTCNT。

RegisterAddressR/WDescReset value
WTDAT0x53000004R/WWatchdog timer data register0x8000

[15:0] count reload value


Watchdog timer data (WTCNT) register

首次启动时,不会从WTCNT加载,所以需要手动设置,WTCNT可以在到达0之前随时手动设置,这叫喂狗。到达0后,根据WTCON的配置,可产生中断,也可产生reset,不reset的话,它会自动从WTDAT拿数据,重新开始一次定时。

RegisterAddressR/WDescReset value
WTCNT0x53000008R/WWatchdog timer COUNT register0x8000

[15:0] the current count value of the watchdog timer


3 实战

要求:开机时,3个灯灭,按任何一个键,开启看门狗,3个等轮流亮,5s内需要再次按键喂狗,不喂狗超时发生reset。


init.c的本实战相关的代码如下,有个变量pollmod表示是否有按键按下,按下之后就变成了1,main函数一开始关闭所有灯,然后进入循环,如果pollmod不为0,则跑马亮灯。中断里面,如果pollmod为0,表示第一次按下键,初始化看门狗,并将pollmod置为1,再次按键后,只执行喂狗的操作。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
static int count = 0;
 
void start_watchdog()
{
#define PCLK_HZ         (67*1000*1000)
#define WATCHDOG_TIMER  5
#define prescaler       255
#define division_factor 128
 
    count = PCLK_HZ / prescaler / division_factor * 
                WATCHDOG_TIMER;
 
    WTCNT = count;
     
    // 15:8 prescaler value
    // 5:   watchdog timer enable
    // 4:3  clock division factor, 11:128
    // 0    reset enable / disable
    WTCON = (255 << 8) | (1 << 5) | (3 << 3) | 1;
}
 
void feed_watchdog()
{
    WTCNT = count;
}
 
static int pollmod = 0;
 
void main()
{
     register int i = 0;
    register int led = 4;
 
    GPFDAT = -1;
 
    while (1)
    {
        i++;
        if (i == 300000) {
            if (pollmod)
                GPFDAT = ~(1 << led);
            led++;
            if (led == 7)
                led = 4;
            i = 0;
        }
    
}
 
void irq_handler()
{
    unsigned long off = intcont->INTOFFSET;
 
    if (pollmod == 0) {
        pollmod = 1;
        start_watchdog();
    }
    else
        feed_watchdog();
 
    if (off == 5) {
        EINTPND = 1 << 11;
    }
    intcont->SRCPND = 1 << off;
    intcont->INTPND = 1 << off;
}


因为要在main和中断处理函数中共享,使用全局变量pollmod,由于其初始值为0,编译器缺省将其放入.bss section,链接时.bss section的大小为0,所以编出的bin是没有pollmod的内容的。而编出的固件小于4K nand页大小,没有数据的内容在nand flash中默认擦除为0xff,这其实看烧录程序是怎么做的。所以这里通过-fno-zero-initialized-in-bss选项将初始化为0的变量放入.data section,这样板子起来后,pollmod为正确的值。

1
$(CC) -c -o init.o init.c -O0 -g -fno-zero-initialized-in-bss

当然也在可以代码里面加一个pollmod = 0。


参考

https://os.mbed.com/cookbook/WatchDog-Timer


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.