Optimizing OEMIdle for lower power consumption
Posted by Matt Anfang
Optimizing OEMIdle is crucial for battery powered devices. While many power saving features on a device (like a backlight timeout) involve the user, power saving on the processor happens completely behind the scenes. OEMIdle() is the OAL entry point called by the kernel when there are no active threads to execute. At this point the processor should be placed into a low power state to conserve power.
An algorithm must be developed to calculate which low power state is most appropriate for the system on entry to OEMIdle. The difficulty in writing this algorithm is determining the timing thresholds that should be used for each low power state. Before the kernel calls OEMIdle it sets dwReschedTime, a global timer variable. This variable tells us how many milliseconds we can snooze before the kernel will need to run again. If this number is very small (say a few milliseconds), it may not make sense to enter a low power state at all.
There is typically an inverse relationship between the time it takes to recover from a low power state and the amount of current drawn in that state. Let’s say your processor has 3 low power modes:
Mode |
Wakeup Time |
Current Draw |
dwReschedTime Threshold |
Full Power |
0 |
2 mA |
< 1.5 us |
Low Power 1 |
1 us |
1 mA |
< 7.5 ms |
Low Power 2 |
5 ms |
.5 mA |
< 75 ms |
Low Power 3 |
50 ms |
.002 mA |
>= 75 ms |
For each power mode, a threshold needs to be determined, and that threshold is compared against how long the OEMIdle period is expected to last (dwReschedTime). In this example, the thresholds are set such that you must expect to be in the low power mode for at least 1.5 times as long as the wakeup period. Keep in mind that every processor is different; depending out how much power is consumed during the wakeup, as well as how long it takes to wakeup, these thresholds can differ. With these thresholds set, we can now enter low power modes based on the value of dwReschedTime (see Figure 1).
Before entering the low power state all interrupts should be disabled except for those which may serve as a wakeup (timer, keypad, etc.). The processor should then enter the low power state. When the processor wakes up, you must remember to update CurMsec if the timer interrupt was disabled during sleep. Finally, OEMIdle returns: it’s that easy. I drew up a little diagram to illustrate the entire process (see Figure 2).
Sleeping the processor in OEMIdle is an interesting problem that ultimately requires power measurements to validate. Because processor low power states have finite wakeup times, making use of these states also means you may add some latency to the real-time response of your system. Ultimately, each implementation of OEMIdle depends on the device’s use scenarios. A wall-powered CEPC will probably do little or nothing when OEMIdle is called. But a smartphone, for instance, may spend the majority of its battery life in a low power mode waiting on a call notification from the radio processor. In this case, a fully-optimized OEMIdle implementation is absolutely essential.