Power Management and Sleep
The Poll-Sleep-Interrupt Cycle
The entire protocol stack shall be a single threaded state machine, working in an infinite poll() -> sleep() cycle.
Programmer is responsible for an application level poll function! The OS is responsible for sleeping and waking up.
MCU must provide hardware mechanism for waking up from sleep, which is called interrupt, such as
- Timer Hardware - Scheduledto wake up within certain ticks
- GPIO - e.g. end-user pressed a button
- Radio - A wireless packet is received
Power State
Hornet implementation puts MCU into “low power mode” while sleeping to further conserving energy.
Low power mode is crucial to battery powered devices. For mains powered device, lower power consumption corresponds to longer life of AC/DC components which affects overall life of the device.
typedef enum {
PM_STATE_ACTIVE = 0,
PM_STATE_IDLE = 1,
PM_STATE_SUSPENDED = 2,
PM_STATE_SOFT_OFF = 3,
} hornet_power_state_t;
The deeper power state, the less functional the MCU will be.
Power State | Wake Up Events |
---|---|
PM_STATE_ACTIVE | Keeps polling |
PM_STATE_IDLE | Any event Most importantly, RF Radio and RTC Timer |
PM_STATE_SUSPENDED | GPIO Pins RTC Timer |
PM_STATE_SOFT_OFF | GPIO Pins Only |
As we can see, for router and RRED, radio needs to on (and listening) all the time, we can only use PM_STATE_IDLE
.
For battery powered device and sensors, we need sleep timer. So we can only reach sleep PM_STATE_SUSPENDED
. In PM_STATE_SUSPENDED
the radio is turned off. As a result, battery powered devices needs to wake up periodically to “poll” queued messages from parent router, using the RTC Timer.
HORNET_ARCH_MAX_PWR_STATE
HORNET_ARCH_MAX_PWR_STATE
is the maximum power state the firmware can use. It is defined by default. Usually there is no reason to redefined it.
#ifndef HORNET_ARCH_MAX_PWR_STATE
#if HORNET_DEVICE_TYPE == HORNET_RFD
#define HORNET_ARCH_MAX_PWR_STATE (PM_STATE_SUSPENDED)
#else
#define HORNET_ARCH_MAX_PWR_STATE (PM_STATE_IDLE)
#endif
#endif
Power Management
In Hornet code, at the end of iteration of poll, before entering the sleep mode, our code queries every layer for the maximum power state it can use.
For example, for MAC layer, mac_get_power_state()
is defined. Below is how it works.
- If there is unprocessed incoming message, do not sleep at all (returns
PM_STATE_ACTIVE
); - If stack is in ed scan or active scan mode, do not turn off the radio (returns
PM_STATE_IDLE
); - If the stack is sending a message or waiting for ACK message, do not turn off the radio (returns
PM_STATE_IDLE
); - Otherwise, returns
HORNET_ARCH_MAX_PWR_STATE
, which could bePM_STATE_IDLE
for battery powered devices.
app_get_power_state
The developer has a chance to implement app_get_power_state
to further control the power state. The default implementation is below:
hornet_power_state_t app_get_power_state() {
return HORNET_ARCH_MAX_PWR_STATE;
}
Hornet OS implementation will combine the final power mode from all three functions and use the lowest value of all.