GNU ARM汇编--(八)s3c2440的watchdog
从单片机起,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@ dndxhej@gmail.com
- */
- .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
程序实现的是:一个正常的流水灯,定时器每隔2s触发一次中断,中断处理中点亮第四个LED.
稍微该一下上面的代码:
.equ int_gen, 0 @关中断
.equ reset_enable, 1 @打开重启信号
打开重启信号,则可以看到每隔2s系统就重启一次.
如果在循环中加入:
ldrr0, =WTCNT @喂狗
ldrr1, =Count
strr1, [r0]
那么,这又是一个标准的流水灯了.而且是有watchdog保护的流水灯了.
转载于:blog.csdn.net/dndxhej