WinCE实现电源管理

出处:互联网    发布于:2011-09-04 10:56:32

    对于移动设备来说,电源管理是比较重要的。为了让设备有更长的待机和工作时间,实现一个完善的电源管理功能也是必须的。下文将讲述如何实现电源管理。

    [背景和早期版本]

  我们对电源管理的目的是出于节能,使系统适时的进出休眠状态是节能的基本方法。比如用户按下On/Off按钮,或者监视用户活动的定时器超时,或者应用呼叫API(Application Programming Interface)都可以使得系统休眠,如果想让系统退出休眠,用户再次按下On/Off或者其他唤醒中断即可。从而可见,电源管理模块和用户活动情况密不可分,电源管理是用户活动所驱动的。 WinCE中处理用户与系统交互的部分是GWES(Graphics,Windows and Events Subsystem.图形,窗口和事件子系统。主要负责图形输出和用户交互)所以早期电源管理工作是由GWES来实现。但GWES提供的电源管理模块功能过于粗糙死板:所有子设备只能有On和Suspend状态,应用程序无法得到任何状态转换通知,等等……直到WinCE4.0才引入了电源管理模块用以替代GWES中的电源管理功能。(进一步的,为了方便电源管理模块的集中管理,还需要关闭原来GWES对电源管理功能。方法是注册表HKLM\SYSTEM\CurrentControlSet\Control\Power设置DisableGwesPowerOff=1来禁止GWES插手电源管理。系统是默认禁止的。此外,一些用户活动情况仍旧依赖GWES获得,设置注册表HKLM\system\GWE下的ActivityEvent=PowerManager/ActivityTimer/UserActivity.从而告诉GWES,当鼠标,键盘,触摸屏等输入发生时候,GWES要SetEvent这个全局事件以通知电源管理模块。)

  新的电源管理模块提供更完整和更灵活的功能,使系统电源可以自由灵活的设定,子设备电源状态可以单独设定,应用可以获得电源通知等等。

  [系统电源]

  OEM可以依据需要定义如On,ScreenOff,UserIdle,SystemIdle,Suspend等任意系统电源状态。系统电源状态更多的是代表系统电源的一种配置方案,它是各个子设备电源配置的集合。它设定一种可能会出现的情景,并且事先拟定了此情景下电力分配策略(哪些子设备打开,哪些子设备关闭)。

    On可以代表常规工作的情景,所有子设备打开的状态;

    ScreenOff可以代表LCD被用户请求关闭的情景,LCD背灯电源被关闭的状态;

    UserIdle可以代表用户一段时间没有操作的情景,cpu/soc将进入low power的状态;

    Suspend可以代表设备空闲很久了可以挂起的情景,所有非必要供电的子设备电源关闭的状态;

    等等…系统的电源状态的定义很灵活而且自由。 可以在注册表定义系统电源状态。比如:

  [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\State\On]

  "Default"=dword:0;D0

  "Flags"=dword:10000;POWER_STATE_ON

  上面定义了On状态,Flags是附加的状态信息(hints),对应pm.h中的宏定义POWER_STATE_ON.defaule表示在这个状态下所有子设备的默认状态。

  制订系统电源管理策略是电源管理模块的重点,这包括定义系统电源状态,决定状态间转换的条件。用默认的版本为例子,简单图示如下:


 

  On:用户与系统交互时候的状态。

  UserIdle: 代表用户停止输入,但可能仍然在使用的情景,比如阅读文件。

  SystemIdle: 代表用户停止使用设备,但处理器仍然工作的情景,比如,后台文件传输。

  Suspend: 代表休眠状态。

  用户在使用时候,系统处于On状态,用户停止输入,系统自动转入UserIdle状态,持续没有输入时间后,进入SystemIdle状态,持续一段时间后,系统将自动进入Suspend状态。应用程序也可以调用SetSystemPowerState()来进行状态切换。

  在这个基础上,根据自己的平台特点,增加新的策略就基本可以满足常规产品需要。

  (1) On/Off按键。

    ① 电源管理模块已经支持了电源按键功能,直接的办法可以在pdd中增加电源按键定义,按键io的初始化,检测等等;

    ② 从外部发送消息给电源管理模块来通知按键事件;

    ③ 使用api直接转换状态。即不使用电源管理模块提供的按键功能,直接调用SetSystemPowerState使得系统进入Suspend状态。

    这是很常见的做法,我们设计一个电源按键的流驱动,检测到按键时候,呼叫api将系统电源转换到Suspend.

  (2) 加入背灯控制。

    比如在On状态下打开请求显示驱动打开背灯,在UserIdle和SystemIdle状态下请求显示驱动关闭背灯。

  [设备电源]

  支持电源管理的设备驱动的实现,还有很多例子。简单介绍如下:

  电源管理模块并不是直接对子设备的电源开关控制,而是由各个设备驱动来控制的。电源管理模块透过设备驱动的IOCTLs来请求设备控制自身电源。系统电源状态是灵活自由设定的,只有设备电源状态是固定的,多有5个:D0,D1,D2,D3,D4代表Full on,Low on, Standby, Sleep, Off这5个状态。

  不是所有的设备驱动都支持电源管理(至少,在电源管理出现前的早期的设备驱动不会支持)。电源管理模块对设备驱动提出了一个规范和架构,只有满足规范的驱动才能纳入电源管理。如果流驱动控制的设备想要得到电源管理的支持要满足的条件,简单来说有:

    ① 声明自己是支持电源管理的(Iclass值);

    ② 驱动中实现电源管理模块所要求的IOCTLs;

    ③ 驱动加载时候要汇报所支持的电源状态和相关特征;

    ④ ***_PowerDown和***_PowerUp接口接收系统休眠和唤醒通知。

    除此之外,设计驱动还应该了解:设备不一定具备所有5种状态,但至少可以工作在D0;电源管理模块可能会要求设备进入任何设备电源状态,并不仅仅是设备所汇报自己支持的那几个;如果被要求进入不支持的状态,应该进入另一个它所支持的更高功耗的状态;当前状态不需要重复设置;设备电源状态不一定和系统的电源状态同步。除了流驱动外,还有许多内建驱动需要支持电源管理功能。简单总结:

    ① 显示驱动通过ExtCode接口(SETPOWERMANAGEMENT命令,类似IOCTLs)来控制显示驱动的电源,还控制背灯;

    ② 键盘驱动的接口KeybdDriverPowerHandler;

    ③ 触摸屏是TouchPanelPowerHandler;

    ④ 内建网络miniport驱动是MiniportReset接口;

    ⑤ PCMCIA驱动是PowerUp和PowerDown.还有打印机,红外等一些内建驱动。

  [OAL对电源管理的支持]

  [系统的 idle状态]

  当系统没有线程准备运行的时候,内核就调用OEMIdle()。这个函数在bsp中,可以由OEM来修改定制。一般我们在这个函数里面会要求cpu进入low power状态节省电流消耗。一般的cpu/soc都提供了对应idle的睡眠模式。当中断发生或者唤醒事件发生时候,要保证cpu快速离开idle状态,返回运行状态。

  系统idle状态和前面说的UserIdle状态概念不同,前者是cpu负荷情况驱动,代表系统空闲;后者是用户活动驱动,代表用户空闲。

  一个OEMIdle()的推荐流程:

  a) 根据dwReschedTime变量来计算下次唤醒时间

  b) 判断sleep类型,假如需要,调整唤醒时间

  c) Idle处理器和时钟

  d) 中断发生

  e) 判断唤醒源

  f) 更新CurMSec,idle计数值。

  [系统suspend状态]

  当用户按下OFF按钮或者应用调用api进入suspend状态时候,内核会调用OEMPowerOff()函数。在OEMPowerOff()函数里面实现系统挂起,并且系统唤醒后继续从OEMPowerOff()被挂起处执行。OEMPowerOff()时候要进入睡眠模式,睡眠模式根据cpu芯片的sleep模式来选择,要选择功耗的模式。如果cpu芯片提供的功耗模式是PowerDown模式,处理工作就比较复杂了,因为唤醒后是从reset处开始执行,要恢复挂起时候的环境,使得应用程序不知道自己被挂起过。一般按照这样流程来处理:关屏,清framebuffer,保存必须的寄存器到内存,设置io,保存通用寄存器,保存wakeup地址,静止中断,清除cache,使能唤醒源中断,设置sdram自刷新,cpu进入PowerDown.唤醒后的流程相反即可。除了PowerDown模式之外的其他模式,如慢时钟模式,相对来说处理就简单了很多,重要的是设置唤醒源(一般是任何中断可唤醒),sdram进入自刷新状态。

  [SDRAM的控制]

  sdram是的电力消耗设备,系统里面一般除了lcd背光外,没有基本没有耗电的了。sdram常见有mobile sdram和normal sdram这2种,mobile sdram相对于normal sdram增加了温度补偿自刷新,局部阵列自刷新,深度休眠特性,更加适合功耗限制设备,(但mobile sdram工作在更低电压(1.8~2.5v),我想,对有些3.3v总线的cpu未必适合,因为总线会增加很多电平转换的电路。)

  在OEMPowerOff()函数里面,保存好当前环境到sdram,然后使得sdram进入自刷新状态,cpu就可以进入功耗的sleep模式。唤醒后需要退出自刷新状态。

  [应用层于电源管理]

  电源管理模块也提供了应用层接口,使得应用程序也可以参与到电源管理。

  应用层可以通过SetSystemPowerState()来设置系统电源状态,可以通过SetDevicePower来设置子设备电源状态,可以通过SetPowerRequirement通知电源管理模块将子设备设置在特殊电源状态下,不随系统电源改变。此外,电源管理还提供了消息队列,应用层还可以通过RequestPowerNotifications函数请求电源管理模块发送相关消息(PBT_RESUME, PBT_POWERSTATUSCHANGE, PBT_TRANSITION, PBT_POWERINFOCHANGE)。

  设计应用程序也许有几点值得考虑:不随便占用cpu,尽可能快的让出cpu.比如一个很小的动画,哪怕只占1%的cpu也会导致一些系统无法进入低功耗。这里是2点建议:

    (1)当应用不在foreground时候,停止占用cpu;

    (2)用户没有和应用交互时候,停止应用对cpu的占用。

    另外一些应用的情况恰恰相反,播放媒体文件时候,当开始播放时候,不自动进入suspend模式。

    (1)每隔一些时间就reset定时器;

    (2)或者设置所有定时器为0,停止电源管理(tcpmp就是这样的)。

  [电源管理的系统实现]

  电源管理模块实体是一个动态链接库pm.dll来实现的。可以在pb的catalog窗口中选择电源管理组件添加到os中。如下图,微软提供了2个选择(二选一)。

    个代表完整功能,所有api全功能实现。

    第二个代表空实现(形式上提供接口,但空函数)。


 

  电源管理模块的代码结构是分层的,MDD PDD.MDD是抽象公共库,不需要改动,PDD是平台相关,主要改动都在PDD.针对平台特性,微软提供了2种类型PDD示例。一种是default,另外一种是pda版本的。默认的情况,使用的是default.如果要使用pda版本的,需要在系统中指定环境变量SYSGEN_PM_PDA. default和pda版本的主要区别:

  default版本定义了4种状态:On, UserIdle, SystemIdle, Suspend;

  PDA版本定义了On, ScreenOff, Unattended, Resume, Suspend.

  default版本的简单描述:UserIdle状态是描述用户在使用但没有操作,比如阅读。SystemIdle状态描述用户停止使用,但系统仍然工作,比如文件传输。

  PDA版本简单描述:ScreenOff状态描述用户请求把屏幕背灯关闭。是用户主动关闭的情况,区别于UserIdle,UserIdle是自动的。Unattended状态表示后台工作,用户不会对其察觉的情景,比如ActiveSync每5分钟唤醒系统同步,然后继续suspend; Resume状态描述唤醒后情景,比如唤醒后在指定时间内决定转到哪个状态,否则继续suspend.

  [定制电源管理模块的方法]

  Pm.dll是由device.exe加载的,首先device.exe当然是必须的,在pb的catalog中检查Device Manager组件,或者检查SYSGEN_DEVICE变量。其次,仍旧应该选择上图的电源管理组件power management full.

  方案一(推荐方案):在bsp的驱动目录中新建一个pm目录,在这里完成电源管理模块PDD部分的实现,并链接MDD终生成一个pm.dll替代原来系统的pm.dll.

  PDD参考微软提供的代码platform.cpp,主要修改是增加状态转换的动作执行单元。

  方案二:完全不修改电源管理部分,因为默认的PDD在状态转换时候虽然没有动作,但是广播了PBT_TRANSITION消息,可以截获这个消息来进行状态转换。这样作法不如方案一直接。如果是进程实现,还浪费一个宝贵进程资源。

  [影响系统功耗各方面考虑]

  (1)系统时钟周期

  典型的WinCE系统时钟周期是1ms,增加时钟周期有助进一步降低设备功耗。在OEMInit()àOALTimerInit()修改系统时钟。

  (2)可变系统时钟节拍Variable Tick Scheduler

  典型设计里wince每毫秒产生系统时钟中断,那么每隔1ms都会使得idle退出,如果发现没有线程就绪时候继续idle. 对有功耗限制的设计,可以考虑改变系统时钟节拍后进入idle状态。这样在预期的时间段里,idle状态不会被无谓的系统时钟中断唤醒。

  (3)LCD背灯的调节策略

  早期的设计使用一个独立的驱动来实现背灯的控制和调节策略。背灯驱动原理是启动一个监视工作线程,不停等待3个事件:

  ① BackLightChangeEvent

  ② PowerChangedEvent(供电电源发生变化,比如插手了AC电源,会获得了这个事件)

  ③ PowerManager/ActivityTimer/UserActivity(用户输入事件)

  从注册表中读取超时值,当超时事件发生,则将系统背灯关闭。背灯关闭期间,用户重新活动时候,发生第3个事件,则打开背灯。注册表的超时值决定了背灯工作时间。类同pc上设置屏幕保护时间。此外,背灯驱动也需要提供对系统电源状态切换的支持。power down时候要关闭背灯,power up时候打开背灯。

  电源管理模块可以定义一种系统电源状态来描述背灯关闭的情景(比如在UserIdle或者ScreenOff状态时候关闭背灯,On状态时候打开背灯)所以,背灯驱动可以被取消。

  (4)IO口的漏电流

  空载IO避免设置成为输入口,考虑悬空输入导致门电路开关,造成电流消耗。负载IO依照情况设定,一般设置输出低。

  (5)电池驱动

  监视系统电力是电池驱动主要的功能。它提供了其他模块和应用对系统电源状态的查询,查询是AC,还是battary供电,查询电池电量等

    关于API

    API是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。API除了有应用"应用程序接口"的意思外,还特指 API的说明文档,也称为帮助文档。另外,也是美国石油协会、空气污染指数、医药、空中位置指示器的英文简称。


  
关键词:电源电源管理

版权与免责声明

凡本网注明“出处:维库电子市场网”的所有作品,版权均属于维库电子市场网,转载请必须注明维库电子市场网,https://www.dzsc.com,违反者本网将追究相关法律责任。

本网转载并注明自其它出处的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品出处,并自负版权等法律责任。

如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。

上传BOM文件: BOM文件
*公司名:
*联系人:
*手机号码:
QQ:
应用领域:

有效期:
OEM清单文件: OEM清单文件
*公司名:
*联系人:
*手机号码:
QQ:
有效期:

扫码下载APP,
一键连接广大的电子世界。

在线人工客服

买家服务:
卖家服务:

0571-85317607

客服在线时间周一至周五
9:00-17:30

关注官方微信号,
第一时间获取资讯。

建议反馈

联系人:

联系方式:

按住滑块,拖拽到最右边
>>
感谢您向阿库提出的宝贵意见,您的参与是维库提升服务的动力!意见一经采纳,将有感恩红包奉上哦!