/*---------------------------------------------------------------------------*/ void lpm_exit() { if((REG(SYS_CTRL_PMCTL) & SYS_CTRL_PMCTL_PM3) == SYS_CTRL_PMCTL_PM0) { /* We either just exited PM0 or we were not sleeping in the first place. * We don't need to do anything clever */ return; } LPM_STATS_ADD(REG(SYS_CTRL_PMCTL) & SYS_CTRL_PMCTL_PM3, RTIMER_NOW() - sleep_enter_time); /* Adjust the system clock, since it was not counting while we were sleeping * We need to convert sleep duration from rtimer ticks to clock ticks and * this will cost us some accuracy */ clock_adjust((clock_time_t) ((RTIMER_NOW() - sleep_enter_time) / RTIMER_CLOCK_TICK_RATIO)); /* Restore system clock to the 32 MHz XOSC */ select_32_mhz_xosc(); /* Restore PMCTL to PM0 for next pass */ REG(SYS_CTRL_PMCTL) = SYS_CTRL_PMCTL_PM0; /* Remember IRQ energest for next pass */ ENERGEST_IRQ_SAVE(irq_energest); ENERGEST_ON(ENERGEST_TYPE_CPU); ENERGEST_OFF(ENERGEST_TYPE_LPM); }
/* * Routine to put is in PM0. We also need to do some housekeeping if the stats * or the energest module is enabled */ static void enter_pm0(void) { ENERGEST_OFF(ENERGEST_TYPE_CPU); ENERGEST_ON(ENERGEST_TYPE_LPM); /* We are only interested in IRQ energest while idle or in LPM */ ENERGEST_IRQ_RESTORE(irq_energest); /* * After PM0 we don't need to adjust the system clock. Thus, saving the time * we enter Deep Sleep is only required if we are keeping stats. */ if(LPM_CONF_STATS) { sleep_enter_time = RTIMER_NOW(); } assert_wfi(); /* We reach here when the interrupt context that woke us up has returned */ LPM_STATS_ADD(0, RTIMER_NOW() - sleep_enter_time); /* Remember IRQ energest for next pass */ ENERGEST_IRQ_SAVE(irq_energest); ENERGEST_ON(ENERGEST_TYPE_CPU); ENERGEST_OFF(ENERGEST_TYPE_LPM); }
/*---------------------------------------------------------------------------*/ void lpm_exit() { if((REG(SYS_CTRL_PMCTL) & SYS_CTRL_PMCTL_PM3) == SYS_CTRL_PMCTL_PM0) { /* We either just exited PM0 or we were not sleeping in the first place. * We don't need to do anything clever */ return; } /* * When returning from PM1/2, the sleep timer value (used by RTIMER_NOW()) is * not up-to-date until a positive edge on the 32-kHz clock has been detected * after the system clock restarted. To ensure an updated value is read, wait * for a positive transition on the 32-kHz clock by polling the * SYS_CTRL_CLOCK_STA.SYNC_32K bit, before reading the sleep timer value. */ while(REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYNC_32K); while(!(REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYNC_32K)); LPM_STATS_ADD(REG(SYS_CTRL_PMCTL) & SYS_CTRL_PMCTL_PM3, RTIMER_NOW() - sleep_enter_time); /* Adjust the system clock, since it was not counting while we were sleeping * We need to convert sleep duration from rtimer ticks to clock ticks and * this will cost us some accuracy */ clock_adjust((clock_time_t) ((RTIMER_NOW() - sleep_enter_time) / RTIMER_CLOCK_TICK_RATIO)); /* Restore system clock to the 32 MHz XOSC */ select_32_mhz_xosc(); /* Restore PMCTL to PM0 for next pass */ REG(SYS_CTRL_PMCTL) = SYS_CTRL_PMCTL_PM0; /* Remember IRQ energest for next pass */ ENERGEST_IRQ_SAVE(irq_energest); ENERGEST_ON(ENERGEST_TYPE_CPU); ENERGEST_OFF(ENERGEST_TYPE_LPM); }
/* * Routine to put is in PM0. We also need to do some housekeeping if the stats * or the energest module is enabled */ static void enter_pm0(void) { ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM); /* We are only interested in IRQ energest while idle or in LPM */ ENERGEST_IRQ_RESTORE(irq_energest); /* Remember the current time so we can keep stats when we wake up */ if(LPM_CONF_STATS) { sleep_enter_time = RTIMER_NOW(); } assert_wfi(); /* We reach here when the interrupt context that woke us up has returned */ LPM_STATS_ADD(0, RTIMER_NOW() - sleep_enter_time); /* Remember IRQ energest for next pass */ ENERGEST_IRQ_SAVE(irq_energest); ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU); }