学习wince挂起和唤醒以及关机功能,后面再把自己调试心得记下来。
以下文章来源:
http://hi.baidu.com/mikenoodle/blog/item/3d659a16bb9ef656f3de328e.html
http://www.cnblogs.com/wangweixf/archive/2008/12/08/1350226.html
wince挂起和唤醒
不管任何方式的系统挂起,最终都会调用OEMPowerOff()函数来实现.OEMPowerOff()函数由OEM来完成,这个函数也许会位于 power.c或者off.c的文件中.OEMPowerOff()是OEM来实现的,代码和流程也许不同,但基本按照下面的方法来完成.
挂起的过程:
1.先进行平台相关的动作,比如清屏,设置AD,usb等.
2.保存芯片所有的寄存器值到一个静态数组(就是堆栈中)
3.设置io,关闭kitl等
4.呼叫OALCPUPowerOff()进行挂起.
OALCPUPowerOff()是一个位于startup.s中的汇编函数,它按照下面的流程实现挂起功能
5.保存通用寄存器r4-r12,lr到堆栈
6. 保存wakeup后的地址,MMU寄存器,进入各模式将sp和lr寄存器保存到内存RAM的某一个位置,这个位置是由config.bib指定保留的.为什么不象之前一样保存到堆栈呢?因为系统唤醒后跳转到reset开始执行,这时候堆栈还没有初始化.这也是poweroff过程复杂的原因.
7.计算刚才保存的数据块的检验和并保存到GSTATUS3寄存器.(GSTATUS3和GSTATUS4是状态寄存器,挂起直到唤醒过程都会保存里面的值)
8.禁止中断.
9.清cache
10.使能唤醒中断,能唤醒可以是外部中断0,1,2,或者RTC中断
11.设置sdram进入自刷新模式,最终cpu进入power off状态
唤醒的过程:
cpu的power off模式和其他睡眠模式不同,其他的睡眠模式唤醒后会从睡眠处继续运行,而power off模式唤醒后是从reset处执行.reset有3种可能情况,1.正常的上电冷启动,包括reset信号线有效造成的reset.2.看门狗失效造成的reset.3.power off之后被外部中断或者rtc中断唤醒的reset.在reset之后可以根据GSTATUS2寄存器来判断是否从power off唤醒.还有一个问题,不论何种方式reset,都是先执行bootloader的代码,所以唤醒过程需要bootloader的参与配合.具体流程:
1.外部中断或者rtc中断唤醒cpu进入bootloader
2.bootloader中停止sdram的自刷新模式,然后跳到内核开始地址.有些bootloader会做的更多,因为前面我们把数据都保存到了ram中的某处,事实上只要知道这个ram地址就可以取得数据进入唤醒过程.所以有些bootloader会直接去唤醒.我认为这并不好,增加了bootloader的依赖性,层次间的耦合性也高了.
3.检查checksum,因为之前设置sdram处于自刷新状态,在poweroff期间sdram里面的数据会保持,增加checksum是有必要的安全措施.
4.从RAM取得之前保存的参数,其中包含了唤醒后应该跳转的地址,和MMU的配置数据以及各个模式的sp和lr.
5.启动mmu
6.跳到唤醒后的新地址.
7.进入各个模式恢复sp和lr.
8.恢复r4-r12,lr
9.跳转到lr,即相当于OALCPUPowerOff()返回,返回到OEMPowerOff()中.
10.打开kitl,恢复所有寄存器,恢复平台之前状态.
唤醒过程实际是一个挂起的逆过程.如此,系统成功唤醒,所有运行的应用程序不知道自己被系统挂起过而继续运行.
实现关机功能
wince5.0带的电源管理驱动只实现了“休眠(SUSPEND)”功能,未实现“关机(SHUT_DOWN)”功能。调用函数 SetSystemPowerState()时,无论参数是POWRE_STATE_OFF还是POWRE_STATE_SUSPEND,最终均为 SUSPEND。如果需要关机,还需要其他的办法。
我看过有人专门写了一个PowerKey的驱动,用来实现关机。但是这种方法的问题在于,关机时系统不会通知应用程序,往往需要自己设计一套消息由PowerKey驱动来通知应用程序,在很多时候非常的不方便。
我使用的方法是利用Wince自身的电源管理驱动,与系统结合的比较紧密
1. 建立新的PM PDD(platform.cpp),系统自带的PDD在WINCE500/PUBLIC/COMMON/OAK/DRIVERS/PM/PDD目录,可以选取一个作为修改的模板.同时,修改电源管理的SOURCE文件,使用新的PDD。
2.PlatformMapPowerStateHint()函数负责把电源状态标记映射为电源状态的名称,在此函数中做如下修改:
把POWER_STATE_OFF映射为shutdown而不是suspend
3. PlatformSetSystemPowerState()函数负责设置电源的状态,函数中有这么一句
if((dwNewStateFlags & POWER_STATE_RESET) != 0)
这一句监测是否用户准备RESET系统,并在后面做相应的RESET动作。
在此之前,增加if((dwNewStateFlags & POWER_STATE_OFF) != 0){关机代码}
4. 在注册表文件中增加
; wwwwww, the following key is added to impliment the shut down function(not suspend)
; the application should deal with the POWER_BROADCAST(to POWER_STATE_OFF)
[HKEY_LOCAL_MACHINE"SYSTEM"CurrentControlSet"Control"Power"State"ShutDown]
"Default"=dword:4 ; D4
"Flags"=dword:20000 ; POWER_STATE_OFF
5. 修改到此完成,关机时调用 SetSystemPowerState即可,StateFlags参数设为POWER_STATE_OFF。关机时,系统会向应用程序发送POWER_BROADCAST(to POWER_STATE_OFF)消息
通过powerButton驱动分析WINCE的中断实现s2410INT->rSRCPND = BIT_EINT0;
// S3C2410X Developer Notice(page 4) warns against writing a 1 to a 0 bit in the INTPNDregister.
if (s2410INT->rINTPND &BIT_EINT0) s2410INT->rINTPND = BIT_EINT0;
s2410INT->rINTMSK &=~BIT_EINT0;
s2410INT->rSRCPND = BIT_EINT2;
// S3C2410X Developer Notice(page 4) warns against writing a 1 to a 0 bit in the INTPNDregister.
if (s2410INT->rINTPND &BIT_EINT2) s2410INT->rINTPND = BIT_EINT2;
s2410INT->rINTMSK &=~BIT_EINT2;
break;
{....
s2410INT->rINTMSK |=BIT_EINT0;
s2410INT->rINTMSK |=BIT_EINT2;
break;
.....
switch (idInt)
{...
s2410INT->rSRCPND =BIT_EINT0;
if (s2410INT->rINTPND &BIT_EINT0) s2410INT->rINTPND = BIT_EINT0;
s2410INT->rINTMSK &=~BIT_EINT0;
s2410INT->rSRCPND =BIT_EINT2;
if (s2410INT->rINTPND &BIT_EINT2) s2410INT->rINTPND = BIT_EINT2;
s2410INT->rINTMSK &=~BIT_EINT2;
break;
INTERRUPTS_ON();
s2410INT->rINTMSK |=BIT_EINT0;
s2410INT->rSRCPND = BIT_EINT0; /* InterruptClear */
if (s2410INT->rINTPND &BIT_EINT0) s2410INT->rINTPND = BIT_EINT0;
DSK_Init(DWORD dwContext)
{
{
gPwrButtonIntrThread =CreateThread(0, 0, (LPTHREAD_START_ROUTINE) PBT_IntrThread, 0, 0,&IDThread);//创建了一个PBT_IntrThread线程,这个就是PowerButton的IST
{
break;
}
} while (0);
PBT_IntrThread(PVOID pArg)
{
{
RETAILMSG(1, (TEXT(":::SYSINTR_POWER Init Fail\r\n")));
}
{
WaitForSingleObject(gPwrButtonIntrEvent,INFINITE);//等待中断发生
if (gOffFlag == FALSE)
{
if(PBT_IsPushed()) /*To FilterNoise *///判断是否是噪声
{
Sleep(200);
{
}
else
{//如果不是噪声则:
#if (WINCEOSVER >= 400)
if(gpfnSetSystemPowerState != NULL)
{
gpfnSetSystemPowerState(NULL, POWER_STATE_SUSPEND,POWER_FORCE);
}
else
{
PowerOffSystem();//调用PowerOffSystem函数,在这//个函数里面又会调用OEMPowerOff函数,这个函数在power.c里
}
#else
PowerOffSystem();
#endif
DriverSleep(0, FALSE);
}
}
}
}
}
本文出自 “Mobile and Linux Deve..” 博客,请务必保留此出处http://buaadallas.blog.51cto.com/399160/80929
WINCE的挂起/唤醒实现
{
volatile IOPreg *s2410IOP = (IOPreg*)IOP_BASE;
volatile INTreg *s2410INT =(INTreg *)INT_BASE;
volatile LCDreg *s2410LCD = (LCDreg*)LCD_BASE;
CPUSaveRegs(CPUBackupRegs);//保存寄存器的值
CPULCDOff();//关闭LCD电源
ConfigStopGPIO();//停止IO口
ConfigMiscReg();
/* ActualPower-Off ModeEntry */
CPUPowerOff();//调用CPUPowerOff,这个函数在fw.s里面,调用完之后会进入挂起状态
CPULoadRegs(CPUBackupRegs);//恢复寄存器值
s2410IOP->rGSTATUS2 =s2410IOP->rGSTATUS2;//清除GSTATUS2寄存器,这里面存放的是CPU挂起时PC指针的地址
...
}
;
stmdb sp!,{r4-r12}
stmdb sp!, {lr}
; 2. 保存MMU& CPU 寄存器到RAM.
;
ldr r3,=SLEEPDATA_BASE_VIRTUAL ; base of Sleep mode storage
str r2, [r3],#4 ; save resume function address (virtual).
mrc p15, 0, r2, c1, c0, 0
ldr r0, =MMU_CTL_MASK
bic r2, r2, r0
str r2, [r3],#4 ; save MMU control data.
ldr r0, =MMU_TTB_MASK
bic r2, r2, r0
str r2, [r3],#4 ; save TTB address.
str r2, [r3],#4 ; save domain access control.
str r2, [r3],#4 ; save SVC status register.
msr cpsr, r1
mrs r2, spsr
stmia r3!, {r2, r8-r12, sp,lr} ; save the FIQ mode registers.
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp,lr} ; save the ABT mode Registers.
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp,lr} ; save the IRQ Mode Registers.
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp,lr} ; save the UND mode Registers.
msr cpsr, r1
stmia r3!, {sp,lr} ; save the SYS mode Registers.
msr cpsr, r1
; 3. Compute the checksum onSleepData (verify integrity of data after resume).
;
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 ; compute the checksum.
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
ldr r0, =vGPIOBASE
str r2, [r0,#oGSTATUS3] ; save the checksum in the Power Manager Scratch pad register.
;
ldr r0, =vINTBASE
mvn r2, #0
str r2, [r0, #oINTMSK]
str r2, [r0, #oSRCPND]
str r2, [r0, #oINTPND]
;
ldr r0, =vGPIOBASE
ldr r1, =0x550a
str r1, [r0, #oGPFCON]
str r1, [r0, #oGPGCON]
;
ldr r0,=vMISCCR ; hitthe TLB
ldr r0,[r0]
ldr r0, =vCLKCON
ldr r0,[r0]
;
ldr r0, =vREFRESH
ldr r1,[r0] ; r1 = rREFRESH.
orr r1, r1, #(1 << 22)
;
ldr r2, =vMISCCR
ldr r3, [r2]
orr r3, r3, #(7 <<17) ; make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L duringboot-up.
;
ldr r4, =vCLKCON
ldr r5,=0x7fff8 ; power-off mode.
add r8, r8,#0x3f0
add r8, r8,#0xe ; make value to0xEA0003FE
cmp r7,r8
bne %f50
add r6, r6,#0x1000 ; Because eboot startupcode is located at 0x1000.
50
add r6, r6,#0x4 ;
mov pc,r6 ;jump to Power off code in ROM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ALIGN 32 ; for I-Cache Line(32Byte, 8 Word)
str r1, [r0] ; 使能SDRAMself-refresh模式,这样RAM中的数据不会丢失!!
str r3,[r2] ; MISCCR Setting
str r5, [r4] ; Power Off !!
b .
ldr r10,[r1]
tst r10,#0x2
beq %F2 ;if not wakeup from PowerOffmode如果第2位不为1则表示是唤醒
; Skip MISCCRsetting
b %F3 ;if wakeup from PowerOff mode
; goto Power-up code.
beq BringUpWinCE ; 如果GSTATUS2为1则正常启动,否则进入唤醒
ldr r1, [r3],#4 ; pointerto SLEEPDATA
and r1, r1,#0x1
mov r1, r1,LSL #31
orr r1, r1,r1, LSR #1
add r2, r2,r1
subs r0, r0,#1 ;dec the count
bne %b40 ; loop till done
ldr r3,[r0] ;get the Sleep data checksum from the Power Manager Scratch padregister
teq r2,r3 ; compare to what we saved before going to sleep
; bne BringUpWinCE ; bad news - do a cold boot - If emergency power off case, normalbooting.
bne JumpToRAM ;bad news - do a cold boot - If emergency power off case, normalbooting.
b MMUENABLE
JumpToRAM
ldr r2,=0x201000 ;offset into the RAM
ldr r3,=0x30000000 ;add physical base
add r2, r2,r3
mov pc,r2 ; & jump to StartUp address
; 2. MMU Enable
ldr r9, [r5,#SleepState_MMUTTB] ; load theMMU TTB info
ldr r8, [r5,#SleepState_MMUCTL] ; load theMMU control info
ldr r7, [r5, #SleepState_WakeAddr] ; load the LR address
nop
nop
nop
nop
nop
1
mcr p15, 0,r10, c3, c0, 0 ; setup access todomain 0
mcr p15, 0,r9, c2, c0,0 ; PT address
mcr p15, 0,r0, c8, c7,0 ; flush I+D TLBs
mcr p15, 0,r8, c1, c0,0 ; restore MMU control
mov pc,r7 ; & jump to new virtual address (back up Power managementstack)跳到挂起时的地址
nop
add r2, r3, #SleepState_FIQ_SPSR
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, nointerrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr r8, [r2], #4
ldr r9, [r2], #4
ldr r10, [r2], #4
ldr r11, [r2], #4
ldr r12, [r2], #4
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1,#Mode_ABT:OR:I_Bit ;Enter ABT mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1,#Mode_IRQ:OR:I_Bit ;Enter IRQ mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1,#Mode_UND:OR:I_Bit ;Enter UND mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1,#Mode_SYS:OR:I_Bit ;Enter SYS mode, no interrupts
msr cpsr, r1
ldr sp, [r2], #4
ldr lr, [r2]
mov r1,#Mode_SVC:OR:I_Bit ;Enter SVC mode, no interrupts
msr cpsr, r1
ldr r0, [r3, #SleepState_SVC_SPSR]
msr spsr, r0
ldr lr, [sp], #4
ldmia sp!,{r4-r12}
mov pc,lr ; and now back to our sponsors
本文出自 “Mobile and Linux Deve..” 博客,请务必保留此出处http://buaadallas.blog.51cto.com/399160/80930
求WinCE的关机函数[问题点数:20分,无满意答案结帖,结帖人:kornberg206]
|
|
|||
|
| ||
| |||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
| ||
|
|