38 #include "contiki-conf.h"
52 #if LPM_CONF_ENABLE != 0
55 static unsigned long irq_energest = 0;
57 #define ENERGEST_IRQ_SAVE(a) do { \
58 a = energest_type_time(ENERGEST_TYPE_IRQ); } while(0)
59 #define ENERGEST_IRQ_RESTORE(a) do { \
60 energest_type_set(ENERGEST_TYPE_IRQ, a); } while(0)
62 #define ENERGEST_IRQ_SAVE(a) do {} while(0)
63 #define ENERGEST_IRQ_RESTORE(a) do {} while(0)
73 #define DEEP_SLEEP_PM1_THRESHOLD 10
74 #define DEEP_SLEEP_PM2_THRESHOLD 100
76 #define assert_wfi() do { asm("wfi"::); } while(0)
79 rtimer_clock_t lpm_stats[3];
81 #define LPM_STATS_INIT() \
82 do { memset(lpm_stats, 0, sizeof(lpm_stats)); } while(0)
83 #define LPM_STATS_ADD(pm, val) do { lpm_stats[pm] += val; } while(0)
85 #define LPM_STATS_INIT()
86 #define LPM_STATS_ADD(stat, val)
93 static rtimer_clock_t sleep_enter_time;
98 static uint8_t max_pm;
101 #ifdef LPM_CONF_PERIPH_PERMIT_PM1_FUNCS_MAX
102 #define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX LPM_CONF_PERIPH_PERMIT_PM1_FUNCS_MAX
104 #define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX 5
107 static lpm_periph_permit_pm1_func_t
108 periph_permit_pm1_funcs[LPM_PERIPH_PERMIT_PM1_FUNCS_MAX];
111 periph_permit_pm1(
void)
115 for(i = 0; i < LPM_PERIPH_PERMIT_PM1_FUNCS_MAX &&
116 periph_permit_pm1_funcs[i] !=
NULL; i++) {
117 if(!periph_permit_pm1_funcs[i]()) {
131 ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
134 ENERGEST_IRQ_RESTORE(irq_energest);
144 LPM_STATS_ADD(0,
RTIMER_NOW() - sleep_enter_time);
147 ENERGEST_IRQ_SAVE(irq_energest);
149 ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
153 select_32_mhz_xosc(
void)
166 #if SYS_CTRL_SYS_DIV == SYS_CTRL_CLOCK_CTRL_SYS_DIV_32MHZ
167 & ~SYS_CTRL_CLOCK_CTRL_SYS_DIV
169 #if SYS_CTRL_IO_DIV == SYS_CTRL_CLOCK_CTRL_IO_DIV_32MHZ
170 & ~SYS_CTRL_CLOCK_CTRL_IO_DIV
172 ) | SYS_CTRL_CLOCK_CTRL_OSC_PD;
176 select_16_mhz_rcosc(
void)
186 #if SYS_CTRL_SYS_DIV == SYS_CTRL_CLOCK_CTRL_SYS_DIV_32MHZ
187 | SYS_CTRL_CLOCK_CTRL_SYS_DIV_16MHZ
189 #if SYS_CTRL_IO_DIV == SYS_CTRL_CLOCK_CTRL_IO_DIV_32MHZ
190 | SYS_CTRL_CLOCK_CTRL_IO_DIV_16MHZ
192 ) & ~SYS_CTRL_CLOCK_CTRL_OSC_PD;
231 select_32_mhz_xosc();
237 ENERGEST_IRQ_SAVE(irq_energest);
239 ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
245 rtimer_clock_t lpm_exit_time;
246 rtimer_clock_t duration;
254 || !periph_permit_pm1() || max_pm == 0) {
270 if(duration < DEEP_SLEEP_PM1_THRESHOLD || lpm_exit_time == 0) {
281 select_16_mhz_rcosc();
289 if(duration < DEEP_SLEEP_PM1_THRESHOLD) {
296 select_32_mhz_xosc();
299 }
else if(duration >= DEEP_SLEEP_PM2_THRESHOLD && max_pm == 2) {
311 ENERGEST_IRQ_RESTORE(irq_energest);
312 ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
332 select_32_mhz_xosc();
337 ENERGEST_IRQ_SAVE(irq_energest);
338 ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
364 for(i = 0; i < LPM_PERIPH_PERMIT_PM1_FUNCS_MAX; i++) {
365 if(periph_permit_pm1_funcs[i] == permit_pm1_func) {
367 }
else if(periph_permit_pm1_funcs[i] ==
NULL) {
368 periph_permit_pm1_funcs[i] = permit_pm1_func;
Header file with register, macro and function declarations for the cc2538 low power module...
Header file with register manipulation macro definitions.
#define LPM_CONF_STATS
Set to 1 to enable LPM-related stats.
Header with declarations of the RF Core XREGs.
void lpm_set_max_pm(uint8_t pm)
Prevent the SoC from dropping to a PM higher than max_pm.
#define RTIMER_NOW()
Get the current clock time.
#define RFCORE_XREG_FSMSTAT0
Radio status register.
#define SYS_CTRL_PMCTL_PM0
PM0.
void lpm_init()
Initialise the low-power mode management module.
#define SYS_CTRL_PMCTL
Power Mode Control.
Header file for the energy estimation mechanism
Header file for the System Control Block (SCB)
#define SCB_SYSCTRL
System Control.
#define RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE
FIFO and FFCTRL status.
void clock_adjust(void)
Adjust the clock following missed SysTick ISRs.
#define SYS_CTRL_PMCTL_PM2
PM2.
Header file for the cc2538 rtimer driver.
#define SYS_CTRL_PMCTL_PM3
PM3.
#define SYS_CTRL_PMCTL_PM1
PM1.
#define SYS_CTRL_CLOCK_STA
Clock status register.
#define NULL
The null pointer.
Header file for the cc2538 System Control driver.
#define SYS_CTRL_CLOCK_CTRL
Clock control register.
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...
Header file for the Contiki process interface.
int process_nevents(void)
Number of events waiting to be processed.
#define LPM_CONF_MAX_PM
Maximum PM.
#define lpm_enter()
Drop to Deep Sleep.
#define SCB_SYSCTRL_SLEEPDEEP
Deep sleep enable.
#define lpm_exit()
Perform an 'Exit Deep Sleep' sequence.
rtimer_clock_t rtimer_arch_next_trigger(void)
Get the time of the next scheduled rtimer trigger.