从Var Tick角度来对CE电源管理
?從Var Tick角度來對CE電源管理
一.相關的基礎知識如下
1.OAL中Timer相關函數說明
1> OALTimerInit
參數:
msecPerSysTick: 每個系統調度Tick對應多少ms;
countsPerMSec: Timer的Counter變化多少為1ms,其值為Timer的Base Clock/1000;?????? margin:任何時鐘源都有其偏差,該值指出偏差為多少,單位為Tick;
功能:
???????? 初始化系統Timer中斷以及初始化系統時間的一些變量,如g_oalTimer/curridlehigh/ curridlelow,以及函數指針變量pQueryPerformanceFrequency和pQueryPerformanceCounter等。
2> OALTimerIntrHandler
參數:????
???????? 無。
功能:
???????? 系統Timer中斷Handle。
???????? 其返回值是系統SYSINTER,可能的值有SYSINTR_RESCHED和SYSINTR_NOP。如果是SYSINTR_RESCHED則說明當前的系統需要一次任務調度,如果是后者則不需要做任何處理。
3>? OEMIdle
參數:
???????? 無。
功能:
當系統進入System Idle的時候會調用該函數,主要完成的功能是使CPU進入低功耗模式。
2.OAL中相關變量說明
CurMSec:
該全局變量表示在系統啟動以后,過了多少毫秒。一般在OAL中有兩個地方會用到該變量,一個是在系統Timer的ISR中斷中要更新該變量,還有就是在OEMIdle中,當然這取決于你如何實現OEMIdle函數。用戶調用GetTickCount函數的時候,實際上也是獲得該變量的值。在MIPS架構的處理器上該變量名為AddrCurMSec。
?
dwReschedTime:
該變量指WinCE系統下一次調度的時間,它會和CurMSec配合使用,也是在系統Timer的ISR和OEMIdle中被用到。在系統Timer的ISR中,if((CurMSec - dwReschedTime) >= 0)則返回SYSINTR_RESCHED,否則返回SYSINTR_NOP。這個很好理解,如果當前時間大于系統下一次調度的時間就進行系統調度。在OEMIdle中,if ((dwReschedTime - CurMSec) > 0)則處理器進入Idle狀態,否則立即返回。就是說當前距離下一次調度還有一段時間,則處理器可以進入Idle狀態。
curridlelow,curridlehigh:
兩個變量組成一個64bit的計數器,一個表示低32bit,一個表示高32bit。這兩個遍兩會在Timer初始化的時候被設置為0,會在OEMIdle函數中被更新,用于記錄WinCE運行時的Idle時間,支持GetIdleTime函數。
dwDefaultThreadQuantum:
表示線程的時間片大小,默認值好像是100毫秒,可以在OEMInit函數中修改。
3.系統的工作模式
???????? CE主要應用在嵌入式設備中,由于多未移動設備或者體積很小,因此對系統的待機時間和工作時間有較多的考慮。
???????? 大概從3.0開始,CE引入了電源管理。
與其它模塊的通信方式如下:
???????? 標準的CE系統工作模式由下面5種:On/system idle/user idle/suspend/off。其中進入system idle的條件是當前系統中不存在Running的Thread,當進入該模式后,系統中的電源管理模塊會去調用OEM_Idle,使系統進入低功耗模式。
???????? 其中idle模式的說明如下“When there are no threads ready to run, kernel? will call OEMIdle to save power. For S3C2443X platform and our BSP, we let CPU go into “IDLE” state in OEMIdle. The clock to CPU core is stopped when in IDLE mode. When exceptions occur, CPU recovers and returns to normal mode before IRQHandler calls OEMInterruptHandler, OEMIdle just does busy loop. If OEMInterruptHandler is called, OEMIdle returns. In our platform, CPU is running in NORMAL mode unless in IDLE or SLEEP mode. Certain interrupt sources we configured in OEMPowerOff turn the CPU from SLEEP back into NORMAL again.”
二.VAR Tick介紹
1.Tick的概念
CE的任務調度的最小單位是Tick,一個Tick又可以對應一個或者多個MS,可以在OALTimerInit中通過配置g_oalTimer.msecPerSysTick來確定它們的對應關系。
2.Fixed Tick與VAR Tick的概念
???????? 這里都是引用Microsoft的概念,所以有必要解釋一下。Fixed Tick和VAR Tick差別在于,一個Tick包含固定多個MS還是可變多個MS。對于Fixed Tick,Tick的長度在函數OALTimerInit中確定,對于VAR Tick,其長度在函數OALTimerInit和OEM_Idle中確定。
???????? 無論是Fixed Tick還是VAR Tick,系統在System Idle的時候都回去調用OEM_Idle進入低功耗模式。對于Fixed Tick情況,OEM_Idle函數會去配置系統在1 Tick之后喚醒。對于VAR Tick,OEM_Idle函數會計算需要多久才開始下一次系統調用,假設需要10 Tick才會開始下一次系統調度的話,則會配置Timer Controller,使其10 Tick單位后使系統喚醒。
???????? 這么說可能有點拗口,代碼如下:
| void OEMIdle(DWORD idleParam) { ???? UINT32 baseMSec, idleMSec, idleSysTicks; ???? INT32 usedCounts, idleCounts; ???? ULARGE_INTEGER idle; ???? // Get current system timer counter ???? baseMSec = CurMSec; ? ???? // Compute the remaining idle time ??? ?// 計算距離下次系統調度的時間,如果需要馬上開始調度,則立即返回 ???? idleMSec = dwReschedTime - baseMSec; ? ???? // Idle time has expired - we need to return ???? if ((INT32)idleMSec <= 0) return; ? ???? // Limit the maximum idle time to what is supported.? ???? // Counter size is the limiting parameter.? When kernel ???? // profiler or interrupt latency timing is active it is set ???? // to one system tick. ???? // 是不是大于當前OAL中配置的Timer所支持的最大時間,如果大于它,則取最大值 ???? // 其實這個最大值就是g_oalTimer.maxPeriodMSec,在OALTimerInit中配置,計算方法可以參照 ???? // Timer的Spec,該值越大越好 ???? if (idleMSec > g_oalTimer.maxPeriodMSec) { ???????? idleMSec = g_oalTimer.maxPeriodMSec; ???? } ? ???? // We can wait only full systick ???? idleSysTicks = idleMSec/g_oalTimer.msecPerSysTick; ? ???? // This is idle time in hi-res ticks ???? idleCounts = idleSysTicks * g_oalTimer.countsPerSysTick; ? ???? // Find how many hi-res ticks was already used ???? // 計算當前用了多少個Counter,即過了多少個Timer Base Clock的時鐘周期 ???? usedCounts = OALTimerCountsSinceSysTick(); ? ???? if (usedCounts == g_oalTimer.countsPerSysTick) ???? { ???????? return; ???? } ? ???? // Prolong beat period to idle time -- don't do it idle time isn't ???? // longer than one system tick. Even if OALTimerExtendSysTick function ???? // should accept this value it can cause problems if kernel profiler ???? // or interrupt latency timing is active. ???? if (idleSysTicks > 1) { ???????? // Extend timer period ???? ?????// 根據計算出來的值重新配置Timer Counter的初始值,也即配置系統中斷喚醒的時間。 ????????? // 如果計算出來的時間等于一個Tick的時間長,則不用進行配置 ???????? OALTimerUpdate(idleCounts-usedCounts, g_oalTimer.countsMargin); ???????? // Update value for timer interrupt which wakeup from idle ????????? // 更新系統Tick的時間長,以MS為單位,可以看到此處更新的是actualMSecPerSysTick的值 ????????? // 而msecPerSysTick的值并不變化 ????????? // 隨之夜更新actualCountsPerSysTick的值 ???????? g_oalTimer.actualMSecPerSysTick = idleMSec; ???????? g_oalTimer.actualCountsPerSysTick = idleCounts; ???? } ? ???? g_idleMSec = idleMSec; ? ???? // Move SoC/CPU to idle mode ???? OALCPUIdle(); ? ???? // Return system tick period back to original. Don't call when idle ???? // time was one system tick. See comment above. ???? if (idleSysTicks > 1) { ???????? // If there wasn't timer interrupt we have to update CurMSec&curCounts ???????? if (CurMSec == baseMSec) { ????????????? // Return system tick period back to original ????????????? // 這個需要特別注意,否則系統的CPU Loading會計算錯誤 ????????????? idleCounts = OALTimerUpdate(g_oalTimer.countsPerSysTick, g_oalTimer.countsMargin)+usedCounts; ? ????????????? g_idleMSec = g_oalTimer.msecPerSysTick; ????????????? //??????????? RETAILMSG(1,(TEXT("(%x)"), idleSysTicks)); ? ????????????? // Restore original values ????????????? g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick; ????????????? g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick; ? ????????????? // Fix system tick counters & idle counter ?? ???????????// 這個地方一定要注意,否則系統的調度會出現問題 ????????????? CurMSec += idleCounts/g_oalTimer.countsPerMSec; ? ????????????? g_oalTimer.curCounts += idleCounts; ????????????? idleCounts += OALTimerCountsSinceSysTick(); ????????????? usedCounts = 0; ???????? } ???? } else { ???????? if (CurMSec == baseMSec) { ????????????? // Update actual idle counts, if there wasn't timer interrupt ????????????? idleCounts = OALTimerCountsSinceSysTick(); ????????????? usedCounts = 0; ???????? } ???? } ? ???? // Get real idle value. If result is negative we didn't idle at all. ???? idleCounts -= usedCounts; ? ???? if (idleCounts < 0) idleCounts = 0; ? ???? //?? RETAILMSG(1,(TEXT("(%x, %x)"), idleCounts, (CurMSec - baseMSec)*g_oalTimer.countsPerSysTick)); ? ???? // Update idle counters ???? // idle.QuadPart的值其實就是GetIdleTime的時間 ???? idle.LowPart = curridlelow; ???? idle.HighPart = curridlehigh; ???? idle.QuadPart += idleCounts; ???? curridlelow? = idle.LowPart; ???? curridlehigh = idle.HighPart; } |
3.VAR Tick的優點
???????? 省電。
?
?
?
?
總結
以上是生活随笔為你收集整理的从Var Tick角度来对CE电源管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IClass与电源管理
- 下一篇: Windows操作系统的几个TCP/IP