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系统就重启一次.

如果在循环中加入:

ldr r0, =WTCNT     @喂狗
ldr r1, =Count
str r1, [r0]

那么,这又是一个标准的流水灯了.而且是有watchdog保护的流水灯了.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值