Contiki 3.x
|
Driver for the cc2538 power modes. More...
Files | |
file | lpm.c |
Implementation of low power modes ofr the cc2538. | |
file | lpm.h |
Header file with register, macro and function declarations for the cc2538 low power module. | |
Macros | |
#define | lpm_init(void) |
Initialise the LPM module. | |
#define | lpm_enter(void) |
Drop to Deep Sleep. More... | |
#define | lpm_exit(void) |
Perform an 'Exit Deep Sleep' sequence. More... | |
Functions | |
void | lpm_set_max_pm (uint8_t pm) |
Prevent the SoC from dropping to a PM higher than max_pm. More... | |
void | lpm_register_peripheral (lpm_periph_permit_pm1_func_t permit_pm1_func) |
Register a peripheral function which will get called by the LPM module to get 'permission' to drop to PM1+. More... | |
LPM stats | |
Maintains a record of how many rtimer ticks spent in each Power Mode. Mainly used for debugging the module | |
#define | LPM_STATS_GET(pm) |
Constants to be used as arguments to lpm_set_max_pm() | |
#define | LPM_PM0 0 |
#define | LPM_PM1 1 |
#define | LPM_PM2 2 |
Driver for the cc2538 power modes.
void lpm_enter | ( | void | ) |
Drop to Deep Sleep.
This function triggers a sequence to enter Deep Sleep. The sequence involves determining the most suitable PM and switching the system clock source to the 16MHz if required. If the energest module is enabled, the sequence also performs some simple energest calculations.
Broadly speaking, this function will be called from the main loop when all events have been serviced. This functions aims to be clever enough in order to be able to choose between PMs 0/1/2 depending on chip status and anticipated sleep duration. This choice is made subject to configuration restrictions and subject to restrictions imposed by calls to lpm_set_max_pm().
This PM selection heuristic has the following primary criteria:
If the answer to any of those questions is no, we will drop to PM0 and will wake up to any interrupt. Best case scenario (if nothing else happens), we will idle until the next SysTick in no more than 1000/CLOCK_SECOND ms (7.8125ms).
If all can be answered with 'yes', we can drop to PM1/2 knowing that the Sleep Timer will wake us up. Depending on the estimated deep sleep duration and the max PM allowed by user configuration, we select the most efficient Power Mode to drop to. If the duration is too short, we simply IDLE in PM0.
Dropping to PM1/2 requires a switch to the 16MHz OSC. We have the option of letting the SoC do this for us automatically. However, if an interrupt fires during this automatic switch, we will need to re-assert WFI. To avoid this complexity, we perform the switch to the 16MHz OSC manually in software and we assert WFI after the transition has been completed. This gives us a chance to bail out if an interrupt fires or an event is raised during the transition. If nothing happens, dropping to PM1+ is un-interruptible and with a deterministic duration. When we wake up, we switch back to the 32MHz OSC manually before handing control back to main. This is implemented in lpm_exit(), which will always be called from within the Sleep Timer ISR context.
Definition at line 212 of file lpm.h.
Referenced by main().
void lpm_exit | ( | void | ) |
Perform an 'Exit Deep Sleep' sequence.
This routine is called from within the context of the ISR that caused us to come out of PM1/2. It performs a wake up sequence to make sure the 32MHz OSC is back on and the system clock is sourced on it.
While in PMs 1 and 2, the system clock stops ticking. This functions adjusts it when we wake up.
We always exit PM1/2 as a result of a scheduled rtimer task or a GPIO interrupt. This may lead to other parts of the code trying to use the RF, so we need to switch the clock source before said code gets executed.
This function also makes sure that the sleep timer value is up-to-date following wake-up from PM1/2 so that RTIMER_NOW() works.
Definition at line 213 of file lpm.h.
Referenced by gpio_port_a_isr(), gpio_port_b_isr(), gpio_port_c_isr(), gpio_port_d_isr(), and rtimer_isr().
void lpm_register_peripheral | ( | lpm_periph_permit_pm1_func_t | permit_pm1_func | ) |
Register a peripheral function which will get called by the LPM module to get 'permission' to drop to PM1+.
permit_pm1_func | Pointer to the function |
Some peripherals are sensitive to PM changes. For instance, we don't want to drop to PM1+ if the USB PLL is active or if the UART TX FIFO is not clear.
When changing power modes, the LPM driver will call all FPs registered with this function. The peripheral's function will return true or false to permit / prohibit PM1+ respectively. If at least one peripheral returns false, the SoC will drop to PM0 Deep Sleep instead.
Registering several times the same function makes the LPM module behave as if the function had been registered once.
Referenced by uart_init().
void lpm_set_max_pm | ( | uint8_t | pm | ) |
Prevent the SoC from dropping to a PM higher than max_pm.
pm | The highest PM we are allowed to enter, specified as a number in [0, 2] |
Defines for the pm argument are LPM_PMx.
This function can be used by software in situations where some power modes are undesirable. If, for example, an application needs to avoid PM2, it would call lpm_set_max_pm(LPM_PM1). If an application wants to avoid PM1 as well, it would call lpm_set_max_pm(LPM_PM0)
PM0 can not be disabled at runtime. Use LPM_CONF_ENABLE to disable LPM support altogether