1. 程式人生 > >2440中使用看門狗定時器作為普通定時器

2440中使用看門狗定時器作為普通定時器

好吧,看s3c2440的看門狗看了好長時間,因為看門一般很少使用,所以我就想讓看門狗作為一般的定時器來觸發中斷,簡單一點,就做一個LED燈的定時閃爍。看了好多資料,百度、資料手冊中英文版、學習板光碟資料。。。。。。確實是一個糾結的過程,但是最後懂了收穫到的也是滿滿的快樂。

我要說的:

1、不能全相信手冊,手冊上說看門狗計時器作為一般定時器時,應使能中斷並且禁止看門狗定時器。然而實踐證明是不對的;應該使能中斷並且使能看門狗定時器,同時禁止看門狗的復位功能。主程式中的rWTCON |= (1<<5)|(1<<2);就是見證。2、清中斷簡單粗暴就行,不需要那麼多的函式。

       rSRCPND = 0x1<<9;
       rSUBSRCPND = 0x1<<13;
       rINTPND = 0x1<<9;
以下貼出程式碼:

2440init.s

GET option.inc
	GET memcfg.inc
	GET 2440addr.inc

BIT_SELFREFRESH EQU	(1<<22)

;Pre-defined constants
USERMODE    EQU 	0x10
FIQMODE     EQU 	0x11
IRQMODE     EQU 	0x12
SVCMODE     EQU 	0x13
ABORTMODE   EQU 	0x17
UNDEFMODE   EQU 	0x1b
MODEMASK    EQU 	0x1f
NOINT       EQU 	0xc0

;The location of stacks
UserStack	EQU	(_STACK_BASEADDRESS-0x3800)	;0x33ff4800 ~
SVCStack	EQU	(_STACK_BASEADDRESS-0x2800)	;0x33ff5800 ~
UndefStack	EQU	(_STACK_BASEADDRESS-0x2400)	;0x33ff5c00 ~
AbortStack	EQU	(_STACK_BASEADDRESS-0x2000)	;0x33ff6000 ~
IRQStack	EQU	(_STACK_BASEADDRESS-0x1000)	;0x33ff7000 ~
FIQStack	EQU	(_STACK_BASEADDRESS-0x0)	;0x33ff8000 ~

;Check if tasm.exe(armasm -16 
[email protected]
1.0) is used. GBLL THUMBCODE [ {CONFIG} = 16 THUMBCODE SETL {TRUE} CODE32 | THUMBCODE SETL {FALSE} ] MACRO MOV_PC_LR [ THUMBCODE bx lr | mov pc,lr ] MEND MACRO MOVEQ_PC_LR [ THUMBCODE bxeq lr | moveq pc,lr ] MEND MACRO $HandlerLabel HANDLER $HandleLabel $HandlerLabel sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address) ldr r0,=$HandleLabel;load the address of HandleXXX to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) MEND IMPORT Main ; The main entry of mon program AREA Init,CODE,READONLY ENTRY EXPORT __ENTRY __ENTRY ResetEntry ;1)The code, which converts to Big-endian, should be in little endian code. ;2)The following little endian code will be compiled in Big-Endian mode. ; The code byte order should be changed as the memory bus width. ;3)The pseudo instruction,DCD can not be used here because the linker generates error. ASSERT :DEF:ENDIAN_CHANGE [ ENDIAN_CHANGE ASSERT :DEF:ENTRY_BUS_WIDTH [ ENTRY_BUS_WIDTH=16 andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00 ] [ ENTRY_BUS_WIDTH=8 streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea ] | b ResetHandler ] b HandlerUndef ;handler for Undefined mode b HandlerSWI ;handler for SWI interrupt b HandlerPabort ;handler for PAbort b HandlerDabort ;handler for DAbort b . ;reserved b HandlerIRQ ;handler for IRQ interrupt b HandlerFIQ ;handler for FIQ interrupt ;@0x20 ; b EnterPWDN ; Must be @0x20. HandlerFIQ HANDLER HandleFIQ HandlerIRQ HANDLER HandleIRQ HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabort IsrIRQ sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ldr r8,[r8] str r8,[sp,#8] ldmfd sp!,{r8-r9,pc} LTORG ;======= ; ENTRY ;======= ResetHandler ldr r0,=WTCON ;watch dog disable ldr r1,=0x0 str r1,[r0] ldr r0,=INTMSK ldr r1,=0xffffffff ;all interrupt disable str r1,[r0] ldr r0,=INTSUBMSK ldr r1,=0x7fff ;all sub interrupt disable str r1,[r0] ;To reduce PLL lock time, adjust the LOCKTIME register. ldr r0,=LOCKTIME ldr r1,=0xffffff str r1,[r0] [ PLL_ON_START ; Added for confirm clock divide. for 2440. ; Setting value Fclk:Hclk:Pclk ldr r0,=CLKDIVN ldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6. str r1,[r0] ;program has not been copied, so use these directly, [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1. mrc p15,0,r0,c1,c0,0 orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA mcr p15,0,r0,c1,c0,0 | mrc p15,0,r0,c1,c0,0 bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF mcr p15,0,r0,c1,c0,0 ] ;Configure UPLL ldr r0,=UPLLCON ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) str r1,[r0] nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed. nop nop nop nop nop nop ;Configure MPLL ldr r0,=MPLLCON ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=16.9344MHz str r1,[r0] ] ;Check if the boot is caused by the wake-up from SLEEP mode. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; check if EIN0 button is pressed 1 bl InitStacks ;=========================================================== ; Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0] [ :LNOT:THUMBCODE bl Main ;Do not use main() because ...... b . ] [ THUMBCODE ;for start-up code for Thumb mode orr lr,pc,#1 bx lr CODE16 bl Main ;Do not use main() because ...... b . CODE32 ] ;function initializing stacks InitStacks ;Do not use DRAM,such as stmfd,ldmfd...... ;SVCstack is initialized before ;Under toolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1' mrs r0,cpsr bic r0,r0,#MODEMASK orr r1,r0,#UNDEFMODE|NOINT msr cpsr_cxsf,r1 ;UndefMode ldr sp,=UndefStack ; UndefStack=0x33FF_5C00 orr r1,r0,#ABORTMODE|NOINT msr cpsr_cxsf,r1 ;AbortMode ldr sp,=AbortStack ; AbortStack=0x33FF_6000 orr r1,r0,#IRQMODE|NOINT msr cpsr_cxsf,r1 ;IRQMode ldr sp,=IRQStack ; IRQStack=0x33FF_7000 orr r1,r0,#FIQMODE|NOINT msr cpsr_cxsf,r1 ;FIQMode ldr sp,=FIQStack ; FIQStack=0x33FF_8000 bic r0,r0,#MODEMASK|NOINT orr r1,r0,#SVCMODE msr cpsr_cxsf,r1 ;SVCMode ldr sp,=SVCStack ; SVCStack=0x33FF_5800 ;USER mode has not be initialized. mov pc,lr ;The LR register will not be valid if the current mode is not SVC mode. ;=========================================================== ;===================================================================== ; Clock division test ; Assemble code, because VSYNC time is very short ;===================================================================== ALIGN AREA RamData, DATA, READWRITE ^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00 HandleReset # 4 HandleUndef # 4 HandleSWI # 4 HandlePabort # 4 HandleDabort # 4 HandleReserved # 4 HandleIRQ # 4 HandleFIQ # 4 ;Do not use the label 'IntVectorTable', ;The value of IntVectorTable is different with the address you think it may be. ;IntVectorTable ;@0x33FF_FF20 HandleEINT0 # 4 HandleEINT1 # 4 HandleEINT2 # 4 HandleEINT3 # 4 HandleEINT4_7 # 4 HandleEINT8_23 # 4 HandleCAM # 4 ; Added for 2440. HandleBATFLT # 4 HandleTICK # 4 HandleWDT # 4 HandleTIMER0 # 4 HandleTIMER1 # 4 HandleTIMER2 # 4 HandleTIMER3 # 4 HandleTIMER4 # 4 HandleUART2 # 4 ;@0x33FF_FF60 HandleLCD # 4 HandleDMA0 # 4 HandleDMA1 # 4 HandleDMA2 # 4 HandleDMA3 # 4 HandleMMC # 4 HandleSPI0 # 4 HandleUART1 # 4 HandleNFCON # 4 ; Added for 2440. HandleUSBD # 4 HandleUSBH # 4 HandleIIC # 4 HandleUART0 # 4 HandleSPI1 # 4 HandleRTC # 4 HandleADC # 4 ;@0x33FF_FFA0 END
2440addr.h
#define _IRQ_BASEADDRESS 	0x33ffff00  
/*#define pISR_RESET	(*(unsigned *)(_IRQ_BASEADDRESS+0x0))
#define pISR_UNDEF		(*(unsigned *)(_IRQ_BASEADDRESS+0x4))
#define pISR_SWI		(*(unsigned *)(_IRQ_BASEADDRESS+0x8))
#define pISR_PABORT		(*(unsigned *)(_IRQ_BASEADDRESS+0xc))
#define pISR_DABORT		(*(unsigned *)(_IRQ_BASEADDRESS+0x10))
#define pISR_RESERVED	(*(unsigned *)(_IRQ_BASEADDRESS+0x14))
#define pISR_IRQ		(*(unsigned *)(_IRQ_BASEADDRESS+0x18))
#define pISR_FIQ		(*(unsigned *)(_IRQ_BASEADDRESS+0x1c))*/
#define pISR_WDT  (*(unsigned *)(_IRQ_BASEADDRESS+0x44))
#define U32 unsigned int
//GPBIO(使用GPB5)
#define rGPBCON    (*(unsigned *) 0x56000010) 
#define rGPBDAT   ( *(unsigned *) 0x56000014)
#define rGPBUP    ( *(unsigned *) 0x56000018)



//UART0
#define rUTRSTAT0   (*(volatile unsigned *)0x50000010)	//UART 0 Tx/Rx status
#define rULCON0     (*(volatile unsigned *)0x50000000)	//UART 0 Line control
#define rUCON0      (*(volatile unsigned *)0x50000004)	//UART 0 Control
#define rUFCON0     (*(volatile unsigned *)0x50000008)	//UART 0 FIFO control
#define rUBRDIV0    (*(volatile unsigned *)0x50000028)	//UART 0 Baud rate divisor
#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)


//WDT
#define rWTCON  (*(volatile unsigned *)0x53000000)
#define rWTDAT  (*(volatile unsigned *)0x53000004)
#define rWTCNT  (*(volatile unsigned *)0x53000008)



//INTRRUPT
#define rSRCPND     (*(volatile unsigned *)0x4A000000)
#define rINTMOD     (*(volatile unsigned *)0x4A000004)
#define rINTMSK    (*(volatile unsigned *)0x4A000008)
#define rPRIORITY   (*(volatile unsigned *)0x4A00000c)
#define rINTPND     (*(volatile unsigned *)0x4A000010)
#define rINTOFFSET  (*(volatile unsigned *)0x4A000014)
#define rSUBSRCPND     (*(volatile unsigned *)0x4A000018)
#define rINTSUBMSK     (*(volatile unsigned *)0x4A00001C)



#define prescaler_value  127
#define clock_select     3
#define  BIT_WDT_AC97 (1<<9)
#define  BIT_WDT (1<<13)
#define  BIT_AC97 (1<<14)


#define	EnableIrq(bit)		rINTMSK &= ~(bit)
#define	DisableIrq(bit)		rINTMSK |= (bit)
#define	EnableSubIrq(bit)	rINTSUBMSK &= ~(bit)
#define	DisableSubIrq(bit)	rINTSUBMSK |= (bit)

main.c
#include "2440addr.h"
void delay(int a)
{
       int k;
       for(k=0;k<a;k++)
              ;
}

void __irq watchdog(void);
 
void Main(void)
{
    
	//GPB5設定為輸出
	rGPBCON |= 0x400;
	rGPBCON &= 0xFFFFF7FF; 
	//GPB5設為滅狀態
	rGPBDAT |= 0x20;
	//輸出上拉
	rGPBUP  &=0xFDF;

    rWTCON = 0xf9<<8;                  //Prescaler = 249,Division = 16,時鐘頻率為12.5kHz
    
    rWTDAT = 40000;               //設定看門狗定時器超時時間為4秒(50÷12.5)
    rWTCNT = 40000;
    rWTCON |= (1<<5)|(1<<2);         //開啟看門狗定時器中斷
    rSRCPND = 0x1<<9;
    rSUBSRCPND = 0x1<<13;
    rINTPND = 0x1<<9;
    rINTSUBMSK = ~(0x1<<13);      //開啟中斷子遮蔽
    rINTMSK = ~(0x1<<9);                     //開啟中斷遮蔽
 
    pISR_WDT= (U32)watchdog;

    while(1) ;
       
}
void __irq watchdog(void)
{
      	rGPBDAT &=0xfdf;
		delay(6400000);
		 rGPBDAT |= 0x20;
       rSRCPND = 0x1<<9;
       rSUBSRCPND = 0x1<<13;
       rINTPND = 0x1<<9;
 
}