从单片机起,watchdog就是必不可少的.在各种应用环境中,程序很可能跑飞或死掉,这时候就需要通过watchdog来保证整个系统重新恢复到正常状态.
照旧,给出s3c2440的datasheet说明:
概述:
watchdog timer用于由于噪声或者系统错误引起的程序跑飞了的情况下恢复处理器的正常操作.它可以被用作一个可以请求中断服务的普通16bit的内部定时器.watchdog timer产生128 PCLK的重启信号.
特点:
有中断请求的普通内部定时器模式
当定时器计数为0(超时)时,产生内部的长达128PCLK周期的重启信号
watchdog timer的操作:
F18-1显示watchdog timer的功能框图.watchdog timer只使用PCLK作为它的时钟源.PCLK先由一个8bit的prescaler进行分频,接下来还会再次分频.
Prescaler的值和分频因子由watchdog timer控制寄存器(WTCON)决定.有效的预分频值的范围是(0--2^8-1),因为是8bit的分频器.分频因子可选为16,32,64,128.
WTDAT&WTCNT
一旦watchdog timer启用了,watchdog timer数据寄存器(WTDAT)的值不会自动的重新加载到计数寄存器(WTCNT).所以,在watchdog timer启动前一定要向watchdog timer的计数寄存器(WTCNT)中写入一个初始值.
watchdog timer special registers
WTCON
WTCON允许user打开或关闭watchdog timer,从4个不同的源中选择时钟信号,开关中断以及开关watchdog timer的输出.watchdog timer用来s3c2440启动后的重启,如果不想处理器重启,watchdog timer要被禁用.在loader开始时,watchdog timer又没初始化的时候,应该将watchdog timer禁用.
如果user想使用watchdog timer提供的正常定时器功能,那就打开中断,关闭watchdog timer.
Register Address R/W Description Reset Value
WTCON 0x53000000 R/W Watchdog timer control register 0x8021
Bit Descrition Initial State
Prescaler value [15:8] 预分频的值(0--255) 0x80
Watchdog timer [5] watchdog timer的开关位 1(开)
Clock select [4:3] 时钟分频因子 00:16 01:32 00
10:64 11:128
Interrupt generation [2] 中断的开关位 0
Reset enable/diaable [0] 输出重启信号的开关 1
WTDAT
WTDAT用来指定超时的期限.在最开始的操作中WTDAT的值不会自动的加载到计数器中.使用初始值0x8000就可以驱动第一次超时.以后的话,WTDAT的值就会自动重加载到WTCNT中.
Register Address R/W Description Reset Value
WTDAT 0x53000004 R/W Watchdog timer data register 0x8000
Bit Description Initial State
Count reload value [15:0] 重加载的计数值 0x8000
WTCNT
WTCNT包含正常操作下watchdog timer的当前计数值.值得注意的是,在watchdog timer最初被启用的时候,WTDAT的内容不会自动的加载到WTCNT中,所以WTCNT一定要给一个初始值.
Register Address R/W Description Reset Value
WTCNT 0x53000008 R/W Watchdog timer count register 0x8000
Bit Description Initial State
Count value [15:0] 定时器的当前计数值 0x8000
我们先将watchdog的输出重启信号的开关关掉,将中断打开,把watchdog timer当一个普通的定时器来用.设计如下:
/* watchdog timer with disable reset copyleft@ [email protected] */ .equ NOINT, 0xc0 .equ GPBCON, 0x56000010 @led .equ GPBDAT, 0x56000014 @led .equ GPBUP, 0x56000018 @led .equ GPFCON, 0x56000050 @interrupt config .equ EINTMASK, 0x560000a4 .equ EXTINT0, 0x56000088 .equ EXTINT1, 0x5600008c .equ EXTINT2, 0x56000090 .equ INTMSK, 0x4A000008 .equ EINTPEND, 0x560000a8 .equ SUBSRCPND, 0x4a000018 .equ INTSUBMSK, 0x4a00001c .equ SRCPND, 0X4A000000 .equ INTPND, 0X4A000010 .equ GPB5_out, (1<<(5*2)) .equ GPB6_out, (1<<(6*2)) .equ GPB7_out, (1<<(7*2)) .equ GPB8_out, (1<<(8*2)) .equ GPBVALUE, (GPB5_out | GPB6_out | GPB7_out | GPB8_out) .equ LOCKTIME, 0x4c000000 .equ MPLLCON, 0x4c000004 .equ UPLLCON, 0x4c000008 .equ M_MDIV, 92 .equ M_PDIV, 1 .equ M_SDIV, 1 .equ U_MDIV, 56 .equ U_PDIV, 2 .equ U_SDIV, 2 .equ CLKDIVN, 0x4c000014 .equ DIVN_UPLL, 0 .equ HDIVN, 1 .equ PDIVN, 1 @FCLK : HCLK : PCLK = 1:2:4 .equ WTCON, 0x53000000 .equ Pre_scaler, 249 .equ wd_timer, 1 .equ clock_select, 00 @316 .equ int_gen, 1 @开中断 .equ reset_enable, 0 @关掉重启信号 .equ WTDAT,0x53000004 .equ Count_reload,50000 @定时器定为2S PCLK = 100M PCLK/(Pre_scaler+1)/clock_select = 100M/(249+1)/16=25k 50000/25k=2s .equ WTCNT,0x53000008 .equ Count,50000 .global _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used @b irq ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq .balignl 16,0xdeadbeef reset: ldr r3, =WTCON mov r4, #0x0 str r4, [r3] @ disable watchdog ldr r0, =GPBCON ldr r1, =0x15400 str r1, [r0] ldr r2, =GPBDAT ldr r1, =0x160 str r1, [r2] bl clock_setup bl delay msr cpsr_c, #0xd2 @进入中断模式 ldr sp, =3072 @中断模式的栈指针定义 msr cpsr_c, #0xd3 @进入系统模式 ldr sp, =4096 @设置系统模式的栈指针 @-------------------------------------------- ldr r0, =GPBUP ldr r1, =0x03f0 str r1, [r0] ldr r0, =GPFCON ldr r1, =0x2ea@0x2 str r1, [r0] ldr r0, =EXTINT0 @ldr r1, =0x8f888@0x0@0x8f888 @~(7|(7<<4)|(7<<8)|(7<<16)) //低电平触发中断 ldr r1, =0xafaaa@0x0@0x8f888 //下降沿触发中断 str r1, [r0] ldr r0, =EINTPEND ldr r1, =0xf0@0b10000 str r1, [r0] ldr r0, =EINTMASK ldr r1, =0x00@0b00000 str r1, [r0] ldr r0, =SRCPND ldr r1, =0x3ff@0x1@0b11111 str r1, [r0] ldr r0, =SUBSRCPND ldr r1, =0x1<<13 str r1, [r0] ldr r0, =INTPND ldr r1, =0x3ff@0x1@0b11111 str r1, [r0] ldr r0, =INTSUBMSK ldr r1, =0x0<<13 str r1, [r0] ldr r0, =INTMSK ldr r1, =0xfffff000@0b00000 str r1, [r0] MRS r1, cpsr BIC r1, r1, #0x80 MSR cpsr_c, r1 bl main irq: sub lr,lr,#4 stmfd sp!,{r0-r12,lr} bl irq_isr ldmfd sp!,{r0-r12,pc}^ irq_isr: ldr r2, =GPBDAT ldr r1, =0x0e0 str r1, [r2] ldr r0,=EINTPEND ldr r1,=0xf0 str r1,[r0] ldr r0, =SRCPND ldr r1, =0x3ff@0b11111 str r1, [r0] ldr r0, =SUBSRCPND ldr r1, =0x1<<13 str r1, [r0] ldr r0, =INTPND ldr r1, =0x3ff@0b11111 str r1, [r0] mov pc,lr delay: ldr r3,=0xffffff delay1: sub r3,r3,#1 cmp r3,#0x0 bne delay1 mov pc,lr clock_setup: ldr r0,=LOCKTIME ldr r1,=0xffffffff str r1, [r0] ldr r0,=CLKDIVN ldr r1,=(DIVN_UPLL<<3) | (HDIVN<<1) | (PDIVN<<0) str r1, [r0] ldr r0,=UPLLCON ldr r1,=(U_MDIV<<12) | (U_PDIV<<4) | (U_SDIV<<0) @Fin=12M UPLL=48M str r1, [r0] nop nop nop nop nop nop nop ldr r0,=MPLLCON ldr r1,=(M_MDIV<<12) | (M_PDIV<<4) | (M_SDIV<<0) @Fin=12M FCLK=400M str r1, [r0] mov pc,lr main: ldr r0, =WTDAT ldr r1, =Count_reload str r1, [r0] ldr r0, =WTCNT ldr r1, =Count str r1, [r0] ldr r0, =WTCON ldr r1, =(Pre_scaler<<8) | (wd_timer<<5) | (clock_select<<3) | (int_gen<<2) | (reset_enable) str r1, [r0] ledloop: ldr r1,=0x1c0 str r1,[r2] bl delay ldr r1,=0x1a0 str r1,[r2] bl delay ldr r1,=0x160 str r1,[r2] bl delay ldr r1,=0x0e0 str r1,[r2] bl delay b ledloop undefined_instruction: nop software_interrupt: nop prefetch_abort: nop data_abort: nop not_used: nop fiq: nop
稍微该一下上面的代码:
.equ int_gen, 0 @关中断
.equ reset_enable, 1 @打开重启信号
打开重启信号,则可以看到每隔2s系统就重启一次.
如果在循环中加入:
ldrr0, =WTCNT @喂狗
ldr r1, =Count
str r1, [r0]
那么,这又是一个标准的流水灯了.而且是有watchdog保护的流水灯了.