WINCE6.0+S3C2443睡眠和唤醒(sleep and wake up)的实现
1. 系統(tǒng)進(jìn)入睡眠狀態(tài)的過程
1.1 硬件相關(guān)電路
我們的產(chǎn)品使用GPF0/EINT0作為系統(tǒng)進(jìn)入睡眠和從睡眠中喚醒的喚醒源,如下圖所示:
?
EINT0作為喚醒源,而EINT0在S3C2443的datasheet中相關(guān)描述如下:
?
那么我們就需要知道觸發(fā)這個(gè)中斷(EINT0)的電平變化情況,是低電平觸發(fā)?或是高電平觸發(fā)?或是下降沿觸發(fā)?或是上升沿觸發(fā)?或是上升沿和下降沿觸發(fā)?上面的設(shè)計(jì)是:在未按下按鍵(S5)時(shí),EINT0是低電平,當(dāng)按下按鍵時(shí),EINT0是高電平,我們以松開按鍵時(shí)作為觸發(fā)條件,也即下降沿時(shí)觸發(fā),初始化代碼如下所示
?
1.2 系統(tǒng)進(jìn)入睡眠的方式
WINCE6.0有三種方式讓系統(tǒng)進(jìn)入睡眠的狀態(tài),如下所示:
?
我們系統(tǒng)是采用第三種方式使系統(tǒng)進(jìn)入睡眠狀態(tài)的,
?
1.3 系統(tǒng)進(jìn)入睡眠狀態(tài)的調(diào)用流程
1.3.1 SetSystemPowerState()
在power按鍵驅(qū)動(dòng)的IST中,當(dāng)我們按下power鍵,在松開按鍵時(shí),會(huì)調(diào)用SetSystemPowerState()函數(shù),如下:
SetSystemPowerState( NULL, POWER_STATE_ON, POWER_FORCE );
下圖是這個(gè)函數(shù)的定義
?
1.3.2 Power manager的相關(guān)調(diào)用
當(dāng)OEM調(diào)用了SetSystemPowerState()函數(shù),就轉(zhuǎn)入power manager的工作流,執(zhí)行下面的動(dòng)作:
?
⑴ FileSystemPowerFunction():
?
⑵ PowerOffSystem()
?
⑶ Sleep()
?
1.3.3 內(nèi)核的相關(guān)調(diào)用
Power manager的以上調(diào)用之后,接下來轉(zhuǎn)入內(nèi)核的調(diào)用流程,執(zhí)行以下操作
?
其中power off GWES和文件系統(tǒng)進(jìn)程是內(nèi)核的工作,下面重點(diǎn)介紹OEMPowerOff()函數(shù),這個(gè)函數(shù)在/Src/Common/Power/off.c下定義,這個(gè)函數(shù)體所實(shí)現(xiàn)的內(nèi)容就對應(yīng)到S3C2243 CPU的相關(guān)部分了,下圖是系統(tǒng)進(jìn)入睡眠狀態(tài)之前的工作:
?
?
1.3.4 OEMPowerOff()函數(shù)
根據(jù)OEMPowerOff函數(shù)的流程圖來說明這個(gè)函數(shù)體的功能。
?
?
下面分別介紹這個(gè)函數(shù)體主體部分:
⑴BSPPowerOff()函數(shù)
à pRTCPort->RTCCON=0x0;
這句主要目的就是在系統(tǒng)進(jìn)入睡眠之前,禁止RTC控制使能,預(yù)防在系統(tǒng)進(jìn)入睡眠狀態(tài)后意外修改RTC寄存器的值,CPU的相關(guān)描述如下
?
à pADCPort->ADCCON|=(1<<2);
設(shè)置ADC的工作模式為standby mode,在睡眠狀態(tài)下,觸摸屏不需要工作,所以設(shè)置為standy mode,見下圖:
?
à pIOPort->MISCCR|=(1<<12); //USB port = suspend
設(shè)置USB port為掛起模式,降低在睡眠時(shí)的功耗。
à pCLKPWR->USB_PHYPWR |= (0xf<<0);
見下圖:
?
à pCLKPWR->PWRCFG &= ~(1<<4);
關(guān)閉對usb物理端口的供電。
?
à pCLKPWR->USB_CLKCON &= ~(1<<31);
見下圖
?
à pCLKPWR->INFORM0 = 0x2BED;
?
?
?
這個(gè)寄存器可用于在進(jìn)入睡眠前保留一些重要或者特別目的的數(shù)據(jù),以便喚醒過程或喚醒后可以使用。
à 關(guān)閉背光燈和LCD
?
⑵ save system registers
…………………………………..
saveArea[5]? = INPORT32(&pIOPort->GPCCON);
saveArea[6]? = INPORT32(&pIOPort->GPCDAT);
saveArea[7]? = INPORT32(&pIOPort->GPCUDP);
…………………………………
把GPIO寄存器的值保存在saveArea[]數(shù)組中,以便喚醒后恢復(fù)寄存器保存的數(shù)值。
?
⑶ ConfigStopGPIO函數(shù)
在這個(gè)函數(shù)可以設(shè)置好作為喚醒睡眠的GPIO口,比如GPF0/EINT0作為喚醒的GPIO口,就要在這里設(shè)置好,也可在OALCPUPowerOff函數(shù)中設(shè)置好,其他GPIO口一般設(shè)置為輸入,已減少系統(tǒng)在睡眠時(shí)的功耗。
?
⑷ OALCPUPowerOff函數(shù)
這個(gè)函數(shù)在/Src/Oal/Oallib/startup.s中定義,如下所示
LEAF_ENTRY OALCPUPowerOff
;?????? 1. Push SVC state onto our stack
stmdb?? sp!, {r4-r12}??????????????????
stmdb?? sp!, {lr}
/***************************************************************/
我們知道R13常用作堆棧指針(sp),用于保存當(dāng)前堆棧地址。SVC:表示處理器模式為管理模式。Stm指令是多寄存器存儲指令,在此表示把r4到r12這9個(gè)寄存器中的值存儲到基址寄存器(sp)所指示的一片連續(xù)存儲器中,stm后面的db表示每次傳送前地址值減;!表示數(shù)據(jù)加載與存儲完畢之后,將最后的地址寫入基址寄存器,如不使用!,則基址寄存器的內(nèi)容不改變。假設(shè)sp=0x90020,stmdb?? sp!, {r4-r12}的操作如下:
第一步:在存儲前,0x90050的值減4(對于ARM指令是4,對Thumb指令是2),也即為0x9004c。
第二步:把寄存器r12的值存儲到0x9004c指向的存儲區(qū)域。
第三步:0x9004c-4=0x90048。
第四步:把寄存器r11的值存儲到0x90048指向的存儲區(qū)域。
……………………………………
最后一步:就是sp=0x90030
?
lr:R14寄存器也稱為子程序連接器(Subroutine Link Register)或連接寄存器LR。
/***************************************************************/
?
;?????? 2. Save MMU & CPU Register to RAM
??? ldr???? r3, =SLEEPDATA_BASE_VIRTUAL???? ; base of Sleep mode storage
?
ldr???? r2, =Awake_address????????????? ; store Virtual return address
str???? r2, [r3], #4
?
mrc???? p15, 0, r2, c1, c0, 0?????????? ; load r2 with MMU Control
ldr???? r0, =MMU_CTL_MASK?????????????? ; mask off the undefined bits
bic???? r2, r2, r0
str???? r2, [r3], #4??????????????????? ; store MMU Control data
?
mrc???? p15, 0, r2, c2, c0, 0?????????? ; load r2 with TTB address.
ldr???? r0, =MMU_TTB_MASK?????????????? ; mask off the undefined bits
bic???? r2, r2, r0
str???? r2, [r3], #4??????????????????? ; store TTB address
?
mrc???? p15, 0, r2, c3, c0, 0?????????? ; load r2 with domain access control.
str???? r2, [r3], #4??????????????????? ; store domain access control
?
str???? sp, [r3], #4??????????????????? ; store SVC stack pointer
?
mrs???? r2, spsr
str???? r2, [r3], #4??????????????????? ; store SVC status register
?
mov???? r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts
msr???? cpsr, r1
mrs???? r2, spsr
stmia?? r3!, {r2, r8-r12, sp, lr}?????? ; store the FIQ mode registers
?
mov???? r1, #Mode_ABT:OR:I_Bit:OR:F_Bit ; Enter ABT mode, no interrupts
msr???? cpsr, r1
mrs r0, spsr
stmia?? r3!, {r0, sp, lr}?????????????? ; store the ABT mode Registers
?
mov???? r1, #Mode_IRQ:OR:I_Bit:OR:F_Bit ; Enter IRQ mode, no interrupts
msr???? cpsr, r1
mrs???? r0, spsr
stmia?? r3!, {r0, sp, lr}?????????????? ; store the IRQ Mode Registers
?
mov???? r1, #Mode_UND:OR:I_Bit:OR:F_Bit ; Enter UND mode, no interrupts
msr???? cpsr, r1
mrs???? r0, spsr
stmia?? r3!, {r0, sp, lr}?????????????? ; store the UND mode Registers
?
mov???? r1, #Mode_SYS:OR:I_Bit:OR:F_Bit ; Enter SYS mode, no interrupts
msr???? cpsr, r1
stmia?? r3!, {sp, lr}?????????????????? ; store the SYS mode Registers
?
mov???? r1, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Back to SVC mode, no interrupts
msr???? cpsr, r1
?
;?????? 3. do Checksum on the Sleepdata
ldr???? r3, =SLEEPDATA_BASE_VIRTUAL ; get pointer to SLEEPDATA
mov???? r2, #0
ldr???? r0, =SLEEPDATA_SIZE ; get size of data structure (in words)
30
ldr???? r1, [r3], #4
and???? r1, r1, #0x1
mov???? r1, r1, LSL #31
orr???? r1, r1, r1, LSR #1
add???? r2, r2, r1
subs??? r0, r0, #1
bne???? %b30
/****************************************************************/
計(jì)算睡眠數(shù)據(jù)的checksum,保存在r2寄存器中
/****************************************************************/
ldr???? r0, =vINFORM3
str???? r2, [r0] ; Store in Power Manager Scratch pad register
/****************************************************************/
把保存在r2寄存器中的睡眠數(shù)據(jù)的checksum保存到INFORM3寄存器中,以便喚醒過程計(jì)算checksum時(shí)比較。
/****************************************************************/
?
?
;?????? 4. Interrupt Disable
ldr???? r0, =vINTBASE
mvn???? r2, #0
str???? r2, [r0, #oINTMSK]
str???? r2, [r0, #oSRCPND]
str???? r2, [r0, #oINTPND]
?
;;?????? 5. Cache Flush
[ {TRUE}
bl????? OALClearUTLB
bl????? OALFlushICache
ldr???? r0, = (DCACHE_LINES_PER_SET - 1)???
ldr???? r1, = (DCACHE_NUM_SETS - 1)???
ldr???? r2, = DCACHE_SET_INDEX_BIT???
ldr???? r3, = DCACHE_LINE_SIZE????
bl????? OALFlushDCache
]
?
;?????? 6. Setting Wakeup External Interrupt(EINT0) Mode
ldr???? r0, =vGPIOBASE
?
ldr???? r1, =0x5502
str???? r1, [r0, #oGPFCON]
/****************************************************************/
設(shè)置GPF0為EINT0,并且設(shè)置為下降沿觸發(fā),只要這里的設(shè)置準(zhǔn)確才能正常從睡眠狀態(tài)喚醒系統(tǒng)。
/****************************************************************/
?
ldr???? r4, =vRSTCON
ldr???? r5, =0x0ff80???????????
str???? r5, [r4]
/****************************************************************/
?
/****************************************************************/
?
ldr???? r4, =vOSCSET
ldr???? r5, =0x8000???????????
str???? r5, [r4]
/****************************************************************/
?
/****************************************************************/
?
ldr???? r4, =vPWRCFG
ldr???? r5, =0x8201??????????
str???? r5, [r4]
/****************************************************************/
?
?
/****************************************************************/
?
ldr???? r4, =vPWRMODE
ldr r5, [r4]
bic r5, r5, #0xff00
bic r5, r5, #0x00ff
ldr r6, =0x2BED
orr???? r5, r5, r6??????????? ; Power Off Mode
?
str???? r5, [r4] ; Power Off !!
??? b .
/****************************************************************/
?
/****************************************************************/
?
1.4 系統(tǒng)進(jìn)入休眠前必須的動(dòng)作
?
在系統(tǒng)進(jìn)入休眠前,正確設(shè)置外部喚醒中斷,才能夠喚醒CPU.一般來說,正確設(shè)置喚醒中斷源,有三個(gè)要點(diǎn)。
⑴ 把對應(yīng)的GPIO設(shè)置為中斷功能
?
⑵明確外部中斷觸發(fā)條件,比如我們把這個(gè)喚醒用的中斷源所對應(yīng)的IO接到一個(gè)按鍵上,希望通過按下按鍵來實(shí)現(xiàn)喚醒。那么就得明確,當(dāng)按下這個(gè)按鍵時(shí),IO口上的電平會(huì)發(fā)生什么樣的變化。
?
⑶ 設(shè)置EXTINTn寄存器,按照按鍵按下時(shí)IO電平的變化條件來設(shè)置。比如當(dāng)按下按鍵時(shí),IO口上的電平會(huì)發(fā)生從高到低的變化,那么我們就設(shè)置對應(yīng)的EXTINTn,使得中斷觸發(fā)條件為Falling edge trigeerde,即下降沿觸發(fā)。
?
?
2. 系統(tǒng)從睡眠狀態(tài)喚醒的過程
2.1 喚醒
當(dāng)按下power鍵(GPF0/EINT0端口產(chǎn)生下降沿),程序就從nboot開始執(zhí)行,也即從/Src/Bootloader/Stepldr/statup.s文件的入口ResetHandler開始
?
Stepldr的入口函數(shù)startup.s是由stepldr目錄下的sources文件下“EXEENTRY=StartUp”來指定的,startup.s函數(shù)的主要功能如下所示:
1)startup.s函數(shù)的入口處
STARTUPTEXT
LEAF_ENTRY StartUp ;用于指定Startup.s函數(shù)的入口點(diǎn)
b ResetHandler ;無條件跳轉(zhuǎn)到ResetHandler函數(shù)
b .
……………………….
b .
;-----------------------------------
; Steppingstone loader entry point.
;-----------------------------------
ResetHandler
ldr r0, =WTCON ; disable the watchdog timer.
mov r1,#0
str r1, [r0]
……………………
2) 禁止看門狗,屏蔽所有的中斷及設(shè)置中斷模式
ResetHandler
ldr r0, =WTCON ; disable the watchdog timer.
mov r1,#0
str r1, [r0]
?
ldr r0, = GPACDH
ldr r1, = 0x1AA8A
str r1, [r0]
/**********************************************************************/
GPACON和GPADAT在S3C2443中已不存在,被GPACDL和GPACDH代替,其作用如下:
GPACDL:Configuration and data register for port A low
GPACDH:Configuration and data register for port A high
配置為功能端,但不甚清楚如此配置的原因。
/**********************************************************************/
ldr r0, = GPFCON
ldr r1, = 0x5500
?
2
str r1, [r0]
ldr r0, =INTMSK ; mask all first-level interrupts.
ldr r1, =0xffffffff
str r1, [r0]
ldr r0, =INTSUBMSK ; mask all second-level interrupts.
ldr r1, =0x1fffffff
str r1, [r0]
/**********************************************************************/
屏蔽子中斷和中斷,從而在stepldr階段不能使用中斷服務(wù)功能。
/**********************************************************************/
?
ldr r0, = INTMOD
mov r1, #0x0 ; set all interrupt as IRQ
str r1, [r0]
/**********************************************************************/
設(shè)置所有的中斷為IRQ中斷。
/**********************************************************************/
3)設(shè)置時(shí)鐘頻率
ldr r0,=CLKDIV0 ; Set Clock Divider
ldr r1,[r0]
bic r1,r1,#0x37 ; clear HCLKDIV, PREDIV, PCLKDIV
bic r1,r1,#(0xf<<9) ; clear ARMCLKDIV
ldr r2,=((Startup_ARMCLKdiv<<9)+(Startup_PREdiv<<4)+(Startup_PCLKdiv<<2)+(Startup_HCLKdiv))
orr r1,r1,r2
str r1,[r0]
/**********************************************************************/
先清除PREDIV、PCLKDIV、HCLKDIV和ARMCLKDIV,在重新根據(jù)系統(tǒng)的需要來設(shè)置這幾個(gè)參數(shù),Startup_ARMCLKdiv等這幾個(gè)參數(shù)在stepldr目錄下的option.inc下定義。
ldr r0,=LOCKCON0 ; Set lock time of MPLL. added by junon
mov r1,#0xe10 ; Fin = 12MHz - 0x800, 16.9844MHz - 0xA00
str r1,[r0]
LOCKCON0是MPLL鎖存時(shí)間的統(tǒng)計(jì)寄存器,啟用PLL之后,由這個(gè)寄存器的值來決定為ARMCLK,HCLK和PCLK服務(wù)的MPLL鎖存時(shí)間的計(jì)數(shù)值,典型情況下,這個(gè)值必須大于300us。
/**********************************************************************/
ldr r0,=LOCKCON1 ; Set lock time of EPLL. added by junon
mov r1,#0x800 ; Fin = 12MHz - 0x800, 16.9844MHz - 0xA00
str r1,[r0]
/**********************************************************************/
LOCKCON1是EPLL鎖存時(shí)間的統(tǒng)計(jì)寄存器,啟用PLL之后,由這個(gè)寄存器的值來決定為ARMCLK,HCLK和PCLK服務(wù)的MPLL鎖存時(shí)間的計(jì)數(shù)值,典型情況下,這個(gè)值必須大于150。
/**********************************************************************/
?
ldr r0,=MPLLCON ; Set MPLL
ldr r1,=((0<<24)+(Startup_Mdiv<<16)+(Startup_Pdiv<<8)+(Startup_Sdiv))
str r1,[r0]
?
?? ldr r0,=EPLLCON ; Set EPLL
ldr r1,=((0<<24)+(Startup_EMdiv<<16)+(Startup_EPdiv<<8)+(Startup_ESdiv))
str r1,[r0]
PLL的輸出頻率由MPLLCON和EPLLCON寄存器的值來決定,其值盡量根據(jù)S3C2443用戶手冊中推薦使用的表來選擇
MPLLCON相關(guān)參數(shù)的表:
?
EPLLCON相關(guān)參數(shù)的表:
?
?
?
ldr r0,=CLKSRC ; Select MPLL clock out for SYSCLK
ldr r1,[r0]
orr r1,r1,#0x50
str r1,[r0]
設(shè)置CLKSRC中的ESYSCLK選擇方式為EPLL輸出和MSYSCLK選擇方式為MPLL輸出,見下圖:
4) 設(shè)置總線的同步方式
bl MMU_SetAsyncBusMode
這個(gè)函數(shù)的代碼如下所示:
LEAF_ENTRY MMU_SetAsyncBusMode
mrc? p15, 0, r0, c1, c0, 0
orr? r0, r0, #R1_nF:OR:R1_iA
mcr? p15, 0, r0, c1, c0, 0
mov? pc, lr
?? 5) 初始化內(nèi)存控制器
bl InitMEM
這個(gè)函數(shù)體如下所示:
InitMEM
ldr r0,=GPKCON
ldr r1,=0xaaaaaaaa ; set Sdata[31:16]
str r1, [r0]
/**********************************************************************/
GPKCON就是SDATACFG寄存器,這是32位SDRAM的配置寄存器,為了控制32位的SDRAM,在內(nèi)存初始化之前,SDATACFG應(yīng)該設(shè)置為0xAAAAAAAA
/**********************************************************************/
?
add???? r0, pc, #MEMDATA - (. + 8)
?
ldr r1,=BANKCFG ;
add r2, r0, #16 ;End address of MEMDATA
110
/**********************************************************************/
先將存儲器地址為r0的字?jǐn)?shù)據(jù)讀入到寄存器r3中,然后將新地址r0+4寫入r0.
ldr r3, [r0], #4
將寄存器r3的值寫入存儲器地址為r0的寄存器,也即BANKCFG,也就是把MEMDATA標(biāo)號處的第一個(gè)分配的單元數(shù)據(jù)給BANKCFG(0x48000000)賦值,然后將新地址r1+4寫入r1,這時(shí)的r1指向BANKCON1(0x48000008)
str r3, [r1], #4
比較r2和r0的值,如果相等,表示對BANKCFG、BANKCON1、BANKCON2和BANKCON3這四個(gè)寄存器的初始化已經(jīng)完成,如果沒有,則跳到上面110處繼續(xù)執(zhí)行,直到對這四個(gè)寄存器始
化完成。
cmp r2, r0
bne %B110
?
先清除BANKCON1的最低兩位,再賦值01給這兩位,用于產(chǎn)生一個(gè)PALL命令
ldr r2,=BANKCON1
ldr r1,[r2]
bic r1,r1,#(0x3<<0)
orr r1,r1,#(0x1<<0) ; 4nd : Issue a PALL command
str r1,[r2]
對REFRESH的DRAM刷新周期賦值,這個(gè)值REFCYC=refresh period(這個(gè)和SDRAM的刷新周期有關(guān),本系統(tǒng)使用K4S56163PF,其刷新周期為64ms,計(jì)算時(shí)是以s為單位的)*HCLK
ldr r4,=REFRESH ; 5fh : refresh cycle every 255-clock cycles
ldr r0,=0xff
str r0,[r4]
?
?
mov r0, #0x100 ; 6th : wait 2 auto - clk
120 subs r0, r0,#1;
bne %B120
?
bic r1,r1,#(0x3<<0) ; 7th : Issue a MRS command
orr r1,r1,#(0x2<<0)
str r1,[r2]
?
ldr r4,=REFRESH ; 8fh : refresh? normal
ldr r0,=REFCYC
str r0,[r4]
?
orr r1,r1,#(0x3<<0) ; 9th : Issue a EMRS command
str r1,[r2]
?
bic r1,r1,#(0x3<<0) ; 10th : Issue a Normal mode
str r1,[r2]
?
// R14也稱作子程序連接寄存器lr,當(dāng)執(zhí)行BL子程序調(diào)用指令時(shí),lr得到R15(程序計(jì)數(shù)器PC)的備份,下面這行語句可以實(shí)現(xiàn)返回到跳轉(zhuǎn)的地址處。
mov pc, lr
?
?
6)靜態(tài)內(nèi)存控制器(staic memory controller,SMC)的初始化,這個(gè)控制器在本開發(fā)板中用于控制nor flash,而mx300沒有使用nor flash,所以應(yīng)該不需要對SMC進(jìn)行初始化.
bl InitSSMC
InitSSMC函數(shù)的定義如下:
InitSSMC
?
;Set SSMC Memory parameter control registers : AMD Flash
ldr r0,=SMBIDCYR0
ldr r1,=IDCY0
str r1,[r0]
?
ldr r0,=SMBWSTRDR0
ldr r1,=WSTRD0
str r1,[r0]
?
ldr r0,=SMBWSTWRR0
ldr r1,=WSTWR0
str r1,[r0]
?
ldr r0,=SMBWSTOENR0
ldr r1,=WSTOEN0
str r1,[r0]
?
ldr r0,=SMBWSTWENR0
ldr r1,=WSTWEN0
str r1,[r0]
?
ldr r0,=SMBCR0
ldr r1,=(SMBCR0_2+SMBCR0_1+SMBCR0_0)
str r1,[r0]
?
ldr r0,=SMBWSTBRDR0
ldr r1,=WSTBRD0
str r1,[r0]
?
?
ldr r0,=SMBWSTBRDR0
ldr r1,=WSTBRD0
str r1,[r0]
?
ldr r0,=SSMCCR
ldr r1,=((MemClkRatio<<1)+(SMClockEn<<0))
str r1,[r0]
?
;ldr r0,=SMBWSTRDR5
;ldr r1,=0xe
;str r1,[r0]
?
mov pc, lr
?
7) S3C2443X的系統(tǒng)控制器(system controller)有三大功能:復(fù)位管理,產(chǎn)生時(shí)鐘和電源管理,下面先介紹復(fù)位管理。
當(dāng)給S3C2443X的系統(tǒng)上電(power-on)時(shí),外部設(shè)備必須插入復(fù)位來初始化S3C2443X的內(nèi)部狀態(tài),S3C2443X有四種復(fù)位類型,在復(fù)位時(shí),系統(tǒng)控制器的復(fù)位控制器能夠使系統(tǒng)進(jìn)入四種復(fù)位類型預(yù)先定義的狀態(tài)中,這四種復(fù)位類型是:硬件復(fù)位,看門狗復(fù)位,軟件復(fù)位和喚醒復(fù)位
I:硬件復(fù)位,當(dāng)nRESET引腳插入低電平時(shí)產(chǎn)生硬件復(fù)位,這種類型的復(fù)位是一種uncompromised,unmaskable和complete reset,以硬件復(fù)位方式啟動(dòng)時(shí),除了RTC以外的系統(tǒng)所有單元都被初始化為可知的狀態(tài)(初始化狀態(tài))。
II:看門狗復(fù)位,看門狗計(jì)數(shù)器監(jiān)測到設(shè)備異常的狀態(tài)時(shí)就會(huì)產(chǎn)生看門狗復(fù)位。
III:軟件復(fù)位(software reset),當(dāng)對SWRST寄存器的每一位寫1時(shí),就產(chǎn)生軟件復(fù)位。
IV:喚醒復(fù)位(wakeup reset),當(dāng)系統(tǒng)從sleep mode中喚醒時(shí),就產(chǎn)生喚醒復(fù)位。
?
通過reset狀態(tài)寄存器來得到復(fù)位狀態(tài)。
ldr r1, =RSTSTAT
ldr r0, [r1]
如果是從sleep中喚醒,則RSTSTAT[3]=1,否認(rèn)RSTSTAT[3]=0。如果是從sleep中喚醒,則指令TST運(yùn)算結(jié)果為非零,影響CPSR的Z標(biāo)志位,這時(shí)Z=0;如果不是從sleep中喚醒,則指令TST運(yùn)算結(jié)果為零,此時(shí)Z=1。
tst r0, #0x8
如果從sleep中喚醒,則接著執(zhí)行下面的指令;如果不是(正常的啟動(dòng)),則跳到下面標(biāo)號為2處接著執(zhí)行。beq指令在Z標(biāo)志位置位時(shí)(Z=1,表示上面的TST指令運(yùn)算結(jié)果為0,從而知//道RSTSTAT[3]=0,而這表明系統(tǒng)不是從sleep中喚醒。)跳轉(zhuǎn)。
beq %F2???????????????????? ; if not wakeup from PowerOffmode Skip
?
如果是從sleep mode中喚醒,接下來深入及具體判斷是通過RTC tick,或是RTC alarm,還是EINT終端模式來從sleep mode中喚醒。
ldr r1, =WKUPSTAT
ldr r0, [r1]
判斷是否通過RTC alarm來從sleep mode中喚醒系統(tǒng)
tst r0, #(1<<1)
如果是通過RTC alarm來喚醒,則WKUPSTAT[1]=1,那么上面tst運(yùn)算結(jié)果為非零,則CPSR的Z=0,那么就接著往下執(zhí)行;如果不是通過alarm來喚醒,則WKUPSTAT[1]=0,那么上面tst運(yùn)算結(jié)果為零,則CPSR的Z=1,那么跳轉(zhuǎn)到下面標(biāo)號6處執(zhí)行
beq %f6???????????????????? ; if not wakeup from PowerOffmode Skip
?
如果是通過RTC alarm來喚醒,則接著到此處執(zhí)行,設(shè)置RTCCON[0]=1:啟動(dòng)RTC控制。
ldr? r1,=RTCCON
ldr r3,[r1]
orr r3,r3,#0x1
str r3,[r1]
?
enable RTC alarm控制的相關(guān)功能項(xiàng)
ldr? r1,=RTCALM
ldr r3,=0x7f
str r3,[r1]
?
設(shè)置RTC alarm秒,分,小時(shí),日,月和年控制寄存器,以便下次喚醒所用。
ldr r1, =BCDSEC
ldr r2, =ALMSEC
ldr r3,[r1]
str r3,[r2]
?
ldr r1, =BCDMIN
ldr r2, =ALMMIN
ldr r3,[r1]
str r3,[r2]
?
ldr r1, =BCDHOUR
ldr r2, =ALMHOUR
ldr r3,[r1]
str r3,[r2]
?
ldr r1, =BCDDATE
ldr r2, =ALMDATE
ldr r3,[r1]
str r3,[r2]
?
ldr r1, =BCDMON
ldr r2, =ALMMON
ldr r3,[r1]
str r3,[r2]
?
ldr r1, =BCDYEAR
ldr r2, =ALMYEAR
ldr r3,[r1]
str r3,[r2]
?
ldr? r1,=RTCCON
ldr r3,[r1]
bic r3,r3,#0x1
str r3,[r1]
?
喚醒的復(fù)位方式啟動(dòng),但又不是通過RTC alarm喚醒,則直接跳到此處執(zhí)行;如果是通過RTC alarm喚醒,則先重新啟動(dòng)RTC alarm控制及設(shè)置相應(yīng)的控制寄存器再接著到標(biāo)號6處執(zhí)行。
6
?
ldr r2, =0x200000 ; offset into the RAM
add r2, r2, #0x30000000 ; add physical base
mov???? pc, r2 ;? & jump to StartUp address
nop
nop
nop
b .
跳轉(zhuǎn)到 RAM中的一個(gè)地址去執(zhí)行,這個(gè)地址是0x32000000。那么熟悉2443 WINCE啟動(dòng)的朋友們應(yīng)該明白了,這個(gè)地址就是Bootloader把NandFlash里的數(shù)據(jù)裝載完畢后,跳轉(zhuǎn)執(zhí)行的地址。那么在這里,跳轉(zhuǎn)到0x302000000這個(gè)地址后,WINCE系統(tǒng)就會(huì)被裝載了,也就是說WINCE的操作系統(tǒng)被喚醒了。
?
2?
如果不是從sleep中喚醒,而是其他的復(fù)位方式,將接著從這里執(zhí)行。
??? ldr r1, =RSTSTAT
ldr r0, [r1]
tst指令用于判斷當(dāng)前的復(fù)位方式是否時(shí)軟件復(fù)位:如果是軟件復(fù)位,則RSTSTAT[5]=1,tst指令的運(yùn)行結(jié)果為非零,則CPSR的Z=0;如果不是,則RSTSTAT[5]=0,tst指令的運(yùn)算結(jié)果為零,則CPSR的Z=1
tst r0, #(1<<5)
如果是軟件復(fù)位,根據(jù)上面tst指令的運(yùn)算,知道CPSR的Z=0,則接著執(zhí)行下面的語句;如果不是軟件復(fù)位,則跳轉(zhuǎn)到BringUpWinCE處接著執(zhí)行
beq BringUpWinCE???????????????????? ; if not wakeup from PowerOffmode Skip
?
如果是軟件復(fù)位,從此處接著執(zhí)行
JumpToRAM
0x30200000(=0x30000000+0x200000)是NK.bin的image start地址
?
ldr r2, =0x200000 ; offset into the RAM
add r2, r2, #0x30000000 ; add physical base
直接跳轉(zhuǎn)到SDRAM的0x30200000從WINCE操作系統(tǒng)內(nèi)核映像的入口處執(zhí)行,軟件復(fù)位方式只用到了stepldr,然后就直接跳轉(zhuǎn)到內(nèi)核中執(zhí)行了。
mov???? pc, r2 ;? & jump to StartUp address
nop
nop
nop
b .//???????????????????????????????????????????????????????????????????????
?
如果不是軟件復(fù)位,這時(shí)應(yīng)該是硬件復(fù)位(或是看門狗復(fù)位,應(yīng)該也是最常用的上電啟動(dòng)),緊接著此處執(zhí)行
BringUpWinCE
? [ {TRUE} ; DonGo
; Clear RAM.
;
mov? r1,#0
mov? r2,#0
mov? r3,#0
mov? r4,#0
mov? r5,#0
mov? r6,#0
mov? r7,#0
mov? r8,#0
?
ldr r0,=0x30000000?? ; Start address (physical 0x3000.0000).
ldr r9,=0x04000000?? ; 64MB of RAM.
20
stm指令用于將寄存器列表(在此r1到r8)所指示的多個(gè)寄存器中的值存入到由基址寄存器所指向的一片連續(xù)存儲器中,條件碼ia表示每次傳送后地址值(基址寄存器的值,在此的初始值為0x30000000)加,下面stmia指令的實(shí)際意義:用r1的值(0)給0x30000000指向的存儲器賦值,在此實(shí)際是對SDRAM清零,因?yàn)?x30000000到0x34000000這64MB的空間是用于SDRAM的,用r2的值給0x30000004指向的存儲器賦值,如此類推,用r8的值給0x30000028指向的存儲器賦值,這次傳送完成后,使r0=0x30000032。
stmia r0!, {r1-r8}
上面stmia指令每進(jìn)行一次數(shù)據(jù)傳送,0x04000000相應(yīng)減去32(4*8),用于判斷對64MB的
SDRAM清零動(dòng)作是否完成
subs r9, r9, #32
如果清零完成,則接著執(zhí)行下面的語句;否則會(huì)跳到到上面標(biāo)號為20處繼續(xù)對SDRAM的清零。
bne %B20
]
?
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/chinesedragon2010/archive/2010/07/21/5753720.aspx
總結(jié)
以上是生活随笔為你收集整理的WINCE6.0+S3C2443睡眠和唤醒(sleep and wake up)的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: activesync对应的COM口
- 下一篇: 如何导出wince6.0的SDK