Windows CE 休眠唤醒全面解析(基于2440平台)(2)
LEAF_ENTRY CPUPowerOff
; 1. Save register state and return address on the stack.
;
stmdb sp!, {r4-r12}
stmdb sp!, {lr}
; 2. Save MMU & CPU Registers to RAM.
;。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
这里我就不把代码贴出来了,大家自己去BSP包里看。
这写部分代码的功能就是保存当前系统的状态,把CPU上一些寄存器里的数据保存到RAM里去,然后禁止RAM自刷新的功能。而且当CPU进入Sleep状态时,RAM是不会掉电的,这样RAM里得数据就不会丢失,当CPU被唤醒后再用RAM里的数据来恢复系统。
注意这一句
; 6. Set external wake-up interrupts (EINT0-2: power-button and keyboard).
。。。。。。。。。。。。。
。。。。。。。。。。。。
也就是说在这行话下面,你就得加入设置唤醒中断源的程序了
如果你在这里成功设置了某个IO 作为中断功能的话,那么系统在休眠后就可以通过人为触发这个中断来实现唤醒CPU(注意,是唤醒CPU,而不是唤醒Wince 系统).这里教大家个小窍门,我们完全可以不在这个语句下面来写汇编语句来实现设置外部唤醒中断的功能(谁让咱是汇编菜鸟呢)。而是在之前的 ConfigStopGPIO里,写C的程序来完成同样的功能。当然,你得保证你设置的那个IO的状态在进入休眠前没有被改变 :)
接下来,程序走到这里
。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。
ldr r4, =vCLKCON
ldr r5, =0x7fff8 ; Power Off Mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sometimes it is not working in cache mode. So I modify to jump to ROM area.
ldr r6, =0x92000000 ; make address to 0x9200 0020
add r6, r6, #0x20 ;
mov pc, r6 ; jump to Power off code in ROM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
b SelfRefreshAndPowerOff
ALIGN 32 ; for I-Cache Line(32Byte, 8 Word)
SelfRefreshAndPowerOff ; run with Instruction Cache's code
str r1, [r0] ; Enable SDRAM self-refresh
str r3, [r2] ; MISCCR Setting
str r5, [r4] ; Power Off !!
b .
LTORG
这段代码的意义,就是把 0x7fff8 这个32位数送到CLKCON寄存器里,这样就使得CPU进入了休眠的模式
不过在实际编译运行过程中,我发现,如果是在4.2的bsp中,这样的代码是没问题的,系统能够正常进入休眠,但是在升级到5.0后,在进入休眠之前,系统会发生异常错误,还没执行进入休眠的语句,程序就跑飞了。经过一段排查,发现把
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sometimes it is not working in cache mode. So I modify to jump to ROM area.
ldr r6, =0x92000000 ; make address to 0x9200 0020
add r6, r6, #0x20 ;
mov pc, r6 ; jump to Power off code in ROM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
这段代码注释掉,就解决了上面的问题(具体原理是什么还在摸索中)
至此,无论是4.2的BSP还是5.0的BSP,都可以进入休眠状态了。拿仪器测了测,恩,果然这时候系统中消耗的电流大幅度降低。那么接下来,就是另一个艰巨的任务了:系统唤醒。
正如之前我们提到的,必须在系统进入休眠前,正确设置外部唤醒中断,才能够唤醒CPU.一般来说,正确设置唤醒中断源,有三个要点。
1 把对应的GPIO设置为中断功能
2 明确外部中断触发条件,比如我们把这个唤醒用的中断源所对应的IO接到一个按键上,希望通过按下按键来实现唤醒。那么就得明确,当按下这个按键时,IO口上的电平会发生什么样的变化。
3 设置EXTINTn寄存器,按照按键按下时IO电平的变化条件来设置。比如当按下按键时,IO口上的电平会发生从高到低的变化,那么我们就设置对应的EXTINTn,使得中断触发条件为Falling edge trigeerde,即下降沿触发。
这三点都注意了,那么你会发现,当系统休眠后,按下这个按键,CPU就会被唤醒,消耗电流一下子就变大了。。。但是,这仅仅是唤醒了CPU,还没有使得WINCE系统恢复起来,那么要恢复WINCE 系统,要怎么做呢??
首先,通过看CPU 的Data Sheet
由上图可以看出,当系统发生由SLEEP到NORMAL的切换时,中间要经过一个 RESET的过程,这个过程称之为 Power On Reset,在2440 CPU的寄存器中,专门有一个用来判断发生Reset原因的寄存器GSTATUS2
也就是说,当CPU Reset后,这个寄存器里的值是会保留的。那么,就可以通过读取这个寄存器里的值,来判断究竟是什么原因发生的CPU Reset了。
说了这么多,无非是为了明确一点,当CPU被外部中断唤醒时,相当于发生了Power Reset的过程。那么唤醒CPU,就类似于给CPU做了一个 硬件复位,不过GSTATUS2里会保存一个数值,来表明Reset的原因。另外,Power On Reset后,在之前Sleep过程中保存下来的RAM里的系统数据是不会丢失的,我们要做的唤醒系统,就是把这些数值恢复到他原来的地址里去。
(未完待续)