作者:ARM-WinCE
在WinCE OAL中的電源管理主要由OEMIdle和OEMPowerOff兩個函數實現。應該說OEMIdle實現的是處理器級的電源管理,而OEMPowerOff實現的是板級的電源管理。
在WinCE系統運行的時候,如果沒有任何線程可以執行,那麼內核就會調用OEMIdle函數。一般在OEMIdle中,處理器都會進入sleep模式或者idle模式,這取決於處理器本身所能支持的低功耗模式。應該說,這個時候系統中的各個設備還是正常工作的,只是處理器進入了一種低功耗模式。OEMIdle函數是OAL中必須實現的,微軟也提供了一個例子,在%_WINCEROOT%/Platform/Common/Src/Common/Timer/Idle路徑下,下面就這個例子簡單分析一下:
void OEMIdle(DWORD idleParam)
{
UINT32 baseMSec, idleMSec, idleSysTicks;
INT32 usedCounts, idleCounts;
ULARGE_INTEGER idle;
//保存當前系統的毫秒數
baseMSec = CurMSec;
//根據下一次調度的時間計算出當前空閒的時間
idleMSec = dwReschedTime - baseMSec;
//如果沒有空閒時間,直接返回
if ((INT32)idleMSec <= 0) return;
//如果空閒時間超過了硬件Timer的最大技術,則以硬件Timer的最大計數爲準
if (idleMSec > g_oalTimer.maxPeriodMSec) {
idleMSec = g_oalTimer.maxPeriodMSec;
}
// 計算空閒時間相當於多少系統tick
idleSysTicks = idleMSec/g_oalTimer.msecPerSysTick;
// 計算空閒時間相當於多少個Timer的count
idleCounts = idleSysTicks * g_oalTimer.countsPerSysTick;
// 已經流逝了多少個Timer的count
usedCounts = OALTimerCountsSinceSysTick();
// 判斷空閒時間大於1個系統tick
if (idleSysTicks > 1) {
// 調用OALTimerUpdate函數更新硬件Timer的count,延長爲空閒時間
OALTimerUpdate(idleCounts, g_oalTimer.countsMargin);
// 更新實際的系統tick的毫秒數和count數
g_oalTimer.actualMSecPerSysTick = idleMSec;
g_oalTimer.actualCountsPerSysTick = idleCounts;
}
// 處理器進入Idle模式,並等待中斷喚醒,此期間可能被其他中斷喚醒,也可能
// 等到空間時間過去後,由系統Timer中斷喚醒
OALCPUIdle();
// 判斷空閒時間大於1個系統tick
if (idleSysTicks > 1) {
// 如果產生的中斷不是系統Timer中斷
if (CurMSec == baseMSec) {
// 調用OALTimerUpdate函數更新硬件Timer爲原來的計數值
idleSysTicks = OALTimerUpdate(
g_oalTimer.countsPerSysTick, g_oalTimer.countsMargin
);
// 恢複相關變量賦值
g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;
// 更新CurMSec和idleCounts
CurMSec += idleSysTicks * g_oalTimer.actualMSecPerSysTick;
idleCounts = idleSysTicks * g_oalTimer.actualCountsPerSysTick;
g_oalTimer.curCounts += idleCounts;
idleCounts += OALTimerCountsSinceSysTick();
}
} else {
if (CurMSec == baseMSec) {
// 不是系統Timer中斷,只更新idleCounts
idleCounts = OALTimerCountsSinceSysTick();
}
}
// 獲得實際的空閒的count值
idleCounts -= usedCounts;
if (idleCounts < 0) idleCounts = 0;
// 更新64位計數器的計數值
idle.LowPart = curridlelow;
idle.HighPart = curridlehigh;
idle.QuadPart += idleCounts;
curridlelow = idle.LowPart;
curridlehigh = idle.HighPart;
}
在該函數中調用了兩個重要的函數,以前沒有提到,這裏說一下:
UINT32 OALTimerUpdate(UINT32 period, UINT32 margin)
period:要更新的計數值
margin:硬件Timer被改變所需的count數
該函數主要用於更新硬件Timer的計數值,實際上就改變了硬件Timer產生中斷的頻率。
VOID OALCPUIdle()
該函數主要實現了硬件處理器進入Idle模式,進入Idle模式後,處理器會停止執行在該函數中,直到中斷產生後,處理器從Idle模式恢復到正常模式,然後從該函數中返回。
關於OEMIdle函數,這裏向大家推薦一篇不錯的blog,供大家參考:
該blog主要介紹了一種實現OEMIdle的思想。OEMIdle函數的實現依賴於處理器所支持的低功耗模式。有些處理器支持多種低功耗模式,根據需要可以在OEMIdle中實現。但是要知道進入低功耗後恢復到正常模式下所花費的時間會影響到整個系統的實時性,所以有時候要根據自己的產品需求,在省電和實時性之間做一個取捨。
在OAL中還有一個重要的函數OEMPowerOff。當系統進入Suspend的時候,首先所有的驅動的PowerDown函數會被調用,然後就會調用OEMPowerOff函數。在該函數中,處理器會進入深度休眠,直到中斷產生後,處理器恢復到正常工作模式,從該函數中返回,接下來所有驅動的PowerUp函數會被調用,然後系統恢復正常工作模式。
void OEMPowerOff (void)
該函數的實現流程如下:
如果支持KITL,調用OALKitlPowerOff關閉KITL功能
調用BSPPowerOff函數關閉板級的相關電源
保存所有寄存器的值
關閉所有中斷,清除所有中斷標記位
打開能夠喚醒處理器的中斷
SDRAM進入自刷新模式
處理器進入深度休眠模式,停止執行,等待中斷喚醒
中斷產生後,處理器被喚醒,並恢復到正常模式
SDRAM進入正常工作模式
打開並配置系統的相關中斷
恢復所有寄存器得值
調用BSPPowerOn函數打開板級的相關電源
如果支持KITL,調用OALKitlPowerOn重新初始化KITL
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/nanjianhui/archive/2009/03/25/4024279.aspx