WINCE6.0+S3C2443睡眠和唤醒(sleep and wake up)的实现

1. 系统进入睡眠状态的过程

1.1 硬件相关电路

我们的产品使用GPF0/EINT0作为系统进入睡眠和从睡眠中唤醒的唤醒源,如下图所示:

 

EINT0作为唤醒源,而EINT0S3C2443datasheet中相关描述如下:

 

那么我们就需要知道触发这个中断(EINT0)的电平变化情况,是低电平触发?或是高电平触发?或是下降沿触发?或是上升沿触发?或是上升沿和下降沿触发?上面的设计是:在未按下按键(S5)时,EINT0是低电平,当按下按键时,EINT0是高电平,我们以松开按键时作为触发条件,也即下降沿时触发,初始化代码如下所示

 

1.2 系统进入睡眠的方式

WINCE6.0有三种方式让系统进入睡眠的状态,如下所示:

 

我们系统是采用第三种方式使系统进入睡眠状态的,

 

1.3 系统进入睡眠状态的调用流程

1.3.1 SetSystemPowerState()

power按键驱动的IST中,当我们按下power键,在松开按键时,会调用SetSystemPowerState()函数,如下:

SetSystemPowerState( NULL, POWER_STATE_ON, POWER_FORCE );

下图是这个函数的定义

 

1.3.2 Power manager的相关调用

OEM调用了SetSystemPowerState()函数,就转入power manager的工作流,执行下面的动作:

 

 FileSystemPowerFunction()

 

 PowerOffSystem()

 

 Sleep()

 

1.3.3 内核的相关调用

Power manager的以上调用之后,接下来转入内核的调用流程,执行以下操作

 

其中power off GWES和文件系统进程是内核的工作,下面重点介绍OEMPowerOff()函数,这个函数在/Src/Common/Power/off.c下定义,这个函数体所实现的内容就对应到S3C2243 CPU的相关部分了,下图是系统进入睡眠状态之前的工作:

 

 

1.3.4 OEMPowerOff()函数

根据OEMPowerOff函数的流程图来说明这个函数体的功能。

 

 

下面分别介绍这个函数体主体部分:

BSPPowerOff()函数

à pRTCPort->RTCCON=0x0;

这句主要目的就是在系统进入睡眠之前,禁止RTC控制使能,预防在系统进入睡眠状态后意外修改RTC寄存器的值,CPU的相关描述如下

 

à pADCPort->ADCCON|=(1<<2);

设置ADC的工作模式为standby mode,在睡眠状态下,触摸屏不需要工作,所以设置为standy mode,见下图:

 

à pIOPort->MISCCR|=(1<<12); //USB port = suspend

设置USB port为挂起模式,降低在睡眠时的功耗。

à pCLKPWR->USB_PHYPWR |= (0xf<<0);

见下图:

 

à pCLKPWR->PWRCFG &= ~(1<<4);

关闭对usb物理端口的供电。

 

à pCLKPWR->USB_CLKCON &= ~(1<<31);

见下图

 

à pCLKPWR->INFORM0 = 0x2BED;

 

 

 

这个寄存器可用于在进入睡眠前保留一些重要或者特别目的的数据,以便唤醒过程或唤醒后可以使用。

à 关闭背光灯和LCD

 

 save system registers

…………………………………..

saveArea[5]  = INPORT32(&pIOPort->GPCCON);

saveArea[6]  = INPORT32(&pIOPort->GPCDAT);

saveArea[7]  = INPORT32(&pIOPort->GPCUDP);

…………………………………

GPIO寄存器的值保存在saveArea[]数组中,以便唤醒后恢复寄存器保存的数值。

 

 ConfigStopGPIO函数

在这个函数可以设置好作为唤醒睡眠的GPIO口,比如GPF0/EINT0作为唤醒的GPIO口,就要在这里设置好,也可在OALCPUPowerOff函数中设置好,其他GPIO口一般设置为输入,已减少系统在睡眠时的功耗。

 

 OALCPUPowerOff函数

这个函数在/Src/Oal/Oallib/startup.s中定义,如下所示

LEAF_ENTRY OALCPUPowerOff

;       1. Push SVC state onto our stack

stmdb   sp!, {r4-r12}                   

stmdb   sp!, {lr}

/***************************************************************/

我们知道R13常用作堆栈指针(sp),用于保存当前堆栈地址。SVC:表示处理器模式为管理模式。Stm指令是多寄存器存储指令,在此表示把r4r129个寄存器中的值存储到基址寄存器(sp)所指示的一片连续存储器中,stm后面的db表示每次传送前地址值减;!表示数据加载与存储完毕之后,将最后的地址写入基址寄存器,如不使用!,则基址寄存器的内容不改变。假设sp=0x90020stmdb   sp!, {r4-r12}的操作如下:

第一步:在存储前,0x90050的值减4(对于ARM指令是4,对Thumb指令是2),也即为0x9004c

第二步:把寄存器r12的值存储到0x9004c指向的存储区域。

第三步:0x9004c-4=0x90048

第四步:把寄存器r11的值存储到0x90048指向的存储区域。

……………………………………

最后一步:就是sp=0x90030

 

lrR14寄存器也称为子程序连接器(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

/****************************************************************/

计算睡眠数据的checksum,保存在r2寄存器中

/****************************************************************/

ldr     r0, =vINFORM3

str     r2, [r0] ; Store in Power Manager Scratch pad register

/****************************************************************/

把保存在r2寄存器中的睡眠数据的checksum保存到INFORM3寄存器中,以便唤醒过程计算checksum时比较。

/****************************************************************/

 

 

;       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]

/****************************************************************/

设置GPF0EINT0,并且设置为下降沿触发,只要这里的设置准确才能正常从睡眠状态唤醒系统。

/****************************************************************/

 

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 系统进入休眠前必须的动作

 

在系统进入休眠前,正确设置外部唤醒中断,才能够唤醒CPU.一般来说,正确设置唤醒中断源,有三个要点。 

 把对应的GPIO设置为中断功能 

 

明确外部中断触发条件,比如我们把这个唤醒用的中断源所对应的IO接到一个按键上,希望通过按下按键来实现唤醒。那么就得明确,当按下这个按键时,IO口上的电平会发生什么样的变化。

 

 设置EXTINTn寄存器,按照按键按下时IO电平的变化条件来设置。比如当按下按键时,IO口上的电平会发生从高到低的变化,那么我们就设置对应的EXTINTn,使得中断触发条件为Falling edge trigeerde,即下降沿触发。 

 

 

2. 系统从睡眠状态唤醒的过程

2.1 唤醒

当按下power(GPF0/EINT0端口产生下降沿),程序就从nboot开始执行,也即从/Src/Bootloader/Stepldr/statup.s文件的入口ResetHandler开始

 

Stepldr的入口函数startup.s是由stepldr目录下的sources文件下EXEENTRY=StartUp来指定的,startup.s函数的主要功能如下所示: 

1startup.s函数的入口处 

STARTUPTEXT 

LEAF_ENTRY StartUp ;用于指定Startup.s函数的入口点 

b ResetHandler ;无条件跳转到ResetHandler函数 

b . 

………………………

b . 

;----------------------------------- 

; Steppingstone loader entry point. 

;----------------------------------- 

ResetHandler 

ldr r0, =WTCON ; disable the watchdog timer. 

mov r1,#0 

str r1, [r0] 

…………………… 

2) 禁止看门狗,屏蔽所有的中断及设置中断模式 

ResetHandler 

ldr r0, =WTCON ; disable the watchdog timer. 

mov r1,#0 

str r1, [r0] 

 

ldr r0, = GPACDH 

ldr r1, = 0x1AA8A 

str r1, [r0] 

/**********************************************************************/

GPACONGPADATS3C2443中已不存在,被GPACDLGPACDH代替,其作用如下: 

GPACDLConfiguration and data register for port A low 

GPACDHConfiguration and data register for port A high 

配置为功能端,但不甚清楚如此配置的原因。 

/**********************************************************************/

ldr r0, = GPFCON 

ldr r1, = 0x5500 

 

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阶段不能使用中断服务功能。 

/**********************************************************************/

 

ldr r0, = INTMOD 

mov r1, #0x0 ; set all interrupt as IRQ 

str r1, [r0] 

/**********************************************************************/

设置所有的中断为IRQ中断。 

/**********************************************************************/

3)设置时钟频率 

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] 

/**********************************************************************/

先清除PREDIVPCLKDIVHCLKDIVARMCLKDIV,在重新根据系统的需要来设置这几个参数,Startup_ARMCLKdiv等这几个参数在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] 

LOCKCON0MPLL锁存时间的统计寄存器,启用PLL之后,由这个寄存器的值来决定为ARMCLKHCLKPCLK服务的MPLL锁存时间的计数值,典型情况下,这个值必须大于300us 

/**********************************************************************/

ldr r0,=LOCKCON1 ; Set lock time of EPLL. added by junon 

mov r1,#0x800 ; Fin = 12MHz - 0x800, 16.9844MHz - 0xA00 

str r1,[r0] 

/**********************************************************************/

LOCKCON1EPLL锁存时间的统计寄存器,启用PLL之后,由这个寄存器的值来决定为ARMCLKHCLKPCLK服务的MPLL锁存时间的计数值,典型情况下,这个值必须大于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寄存器的值来决定,其值尽量根据S3C2443用户手册中推荐使用的表来选择

MPLLCON相关参数的表:

 

EPLLCON相关参数的表:

 

 

 

ldr r0,=CLKSRC ; Select MPLL clock out for SYSCLK

ldr r1,[r0]

orr r1,r1,#0x50

str r1,[r0]

设置CLKSRC中的ESYSCLK选择方式为EPLL输出和MSYSCLK选择方式为MPLL输出,见下图: 

4) 设置总线的同步方式

bl MMU_SetAsyncBusMode

这个函数的代码如下所示:

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) 初始化内存控制器

bl InitMEM

这个函数体如下所示:

InitMEM

ldr r0,=GPKCON

ldr r1,=0xaaaaaaaa ; set Sdata[31:16]

str r1, [r0]

/**********************************************************************/

GPKCON就是SDATACFG寄存器,这是32位SDRAM的配置寄存器,为了控制32位的SDRAM,在内存初始化之前,SDATACFG应该设置为0xAAAAAAAA

/**********************************************************************/

 

add     r0, pc, #MEMDATA - (. + 8)

 

ldr r1,=BANKCFG ;

add r2, r0, #16 ;End address of MEMDATA

110

/**********************************************************************/

先将存储器地址为r0的字数据读入到寄存器r3中,然后将新地址r0+4写入r0.

ldr r3, [r0], #4

将寄存器r3的值写入存储器地址为r0的寄存器,也即BANKCFG,也就是把MEMDATA标号处的第一个分配的单元数据给BANKCFG(0x48000000)赋值,然后将新地址r1+4写入r1,这时的r1指向BANKCON1(0x48000008)

str r3, [r1], #4

比较r2和r0的值,如果相等,表示对BANKCFG、BANKCON1、BANKCON2和BANKCON3这四个寄存器的初始化已经完成,如果没有,则跳到上面110处继续执行,直到对这四个寄存器始

化完成。

cmp r2, r0

bne %B110

 

先清除BANKCON1的最低两位,再赋值01给这两位,用于产生一个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刷新周期赋值,这个值REFCYC=refresh period(这个和SDRAM的刷新周期有关,本系统使用K4S56163PF,其刷新周期为64ms,计算时是以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,当执行BL子程序调用指令时,lr得到R15(程序计数器PC)的备份,下面这行语句可以实现返回到跳转的地址处。

mov pc, lr

 

 

6)静态内存控制器(staic memory controller,SMC)的初始化,这个控制器在本开发板中用于控制nor flash,而mx300没有使用nor flash,所以应该不需要对SMC进行初始化.

bl InitSSMC

InitSSMC函数的定义如下:

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的系统控制器(system controller)有三大功能:复位管理,产生时钟和电源管理,下面先介绍复位管理。

当给S3C2443X的系统上电(power-on)时,外部设备必须插入复位来初始化S3C2443X的内部状态,S3C2443X有四种复位类型,在复位时,系统控制器的复位控制器能够使系统进入四种复位类型预先定义的状态中,这四种复位类型是:硬件复位,看门狗复位,软件复位和唤醒复位

I:硬件复位,当nRESET引脚插入低电平时产生硬件复位,这种类型的复位是一种uncompromised,unmaskable和complete reset,以硬件复位方式启动时,除了RTC以外的系统所有单元都被初始化为可知的状态(初始化状态)。

II:看门狗复位,看门狗计数器监测到设备异常的状态时就会产生看门狗复位。

III:软件复位(software reset),当对SWRST寄存器的每一位写1时,就产生软件复位。

IV:唤醒复位(wakeup reset),当系统从sleep mode中唤醒时,就产生唤醒复位。

 

通过reset状态寄存器来得到复位状态。

ldr r1, =RSTSTAT

ldr r0, [r1]

如果是从sleep中唤醒,则RSTSTAT[3]=1,否认RSTSTAT[3]=0。如果是从sleep中唤醒,则指令TST运算结果为非零,影响CPSR的Z标志位,这时Z=0;如果不是从sleep中唤醒,则指令TST运算结果为零,此时Z=1。

tst r0, #0x8

如果从sleep中唤醒,则接着执行下面的指令;如果不是(正常的启动),则跳到下面标号为2处接着执行。beq指令在Z标志位置位时(Z=1,表示上面的TST指令运算结果为0,从而知//道RSTSTAT[3]=0,而这表明系统不是从sleep中唤醒。)跳转。

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中唤醒系统

tst r0, #(1<<1)

如果是通过RTC alarm来唤醒,则WKUPSTAT[1]=1,那么上面tst运算结果为非零,则CPSR的Z=0,那么就接着往下执行;如果不是通过alarm来唤醒,则WKUPSTAT[1]=0,那么上面tst运算结果为零,则CPSR的Z=1,那么跳转到下面标号6处执行

beq %f6                     ; if not wakeup from PowerOffmode Skip

 

如果是通过RTC alarm来唤醒,则接着到此处执行,设置RTCCON[0]=1:启动RTC控制。

ldr  r1,=RTCCON

ldr r3,[r1]

orr r3,r3,#0x1

str r3,[r1]

 

enable RTC alarm控制的相关功能项

ldr  r1,=RTCALM

ldr r3,=0x7f

str r3,[r1]

 

设置RTC alarm秒,分,小时,日,月和年控制寄存器,以便下次唤醒所用。

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]

 

唤醒的复位方式启动,但又不是通过RTC alarm唤醒,则直接跳到此处执行;如果是通过RTC alarm唤醒,则先重新启动RTC alarm控制及设置相应的控制寄存器再接着到标号6处执行。

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 .

跳转到 RAM中的一个地址去执行,这个地址是0x32000000。那么熟悉2443 WINCE启动的朋友们应该明白了,这个地址就是BootloaderNandFlash里的数据装载完毕后,跳转执行的地址。那么在这里,跳转到0x302000000这个地址后,WINCE系统就会被装载了,也就是说WINCE的操作系统被唤醒了。

 

2  

如果不是从sleep中唤醒,而是其他的复位方式,将接着从这里执行。

    ldr r1, =RSTSTAT

ldr r0, [r1]

tst指令用于判断当前的复位方式是否时软件复位:如果是软件复位,则RSTSTAT[5]=1,tst指令的运行结果为非零,则CPSR的Z=0;如果不是,则RSTSTAT[5]=0,tst指令的运算结果为零,则CPSR的Z=1

tst r0, #(1<<5)

如果是软件复位,根据上面tst指令的运算,知道CPSR的Z=0,则接着执行下面的语句;如果不是软件复位,则跳转到BringUpWinCE处接着执行

beq BringUpWinCE                     ; if not wakeup from PowerOffmode Skip

 

如果是软件复位,从此处接着执行

JumpToRAM

0x30200000(=0x30000000+0x200000)是NK.bin的image start地址

 

ldr r2, =0x200000 ; offset into the RAM 

add r2, r2, #0x30000000 ; add physical base

直接跳转到SDRAM的0x30200000从WINCE操作系统内核映像的入口处执行,软件复位方式只用到了stepldr,然后就直接跳转到内核中执行了。

mov     pc, r2 ;  & jump to StartUp address

nop

nop

nop

b .//???????????????????????????????????????????????????????????????????????

 

如果不是软件复位,这时应该是硬件复位(或是看门狗复位,应该也是最常用的上电启动),紧接着此处执行

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)所指示的多个寄存器中的值存入到由基址寄存器所指向的一片连续存储器中,条件码ia表示每次传送后地址值(基址寄存器的值,在此的初始值为0x30000000)加,下面stmia指令的实际意义:用r1的值(0)给0x30000000指向的存储器赋值,在此实际是对SDRAM清零,因为0x30000000到0x34000000这64MB的空间是用于SDRAM的,用r2的值给0x30000004指向的存储器赋值,如此类推,用r8的值给0x30000028指向的存储器赋值,这次传送完成后,使r0=0x30000032。

stmia r0!, {r1-r8}

上面stmia指令每进行一次数据传送,0x04000000相应减去32(4*8),用于判断对64MB的

SDRAM清零动作是否完成

subs r9, r9, #32 

如果清零完成,则接着执行下面的语句;否则会跳到到上面标号为20处继续对SDRAM的清零。

bne %B20

]

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值