/***************************************************************************//** * @brief * Initialize the Sleep module. * * @details * Use this function to initialize the Sleep module, should be called * only once! Pointers to sleep and wake-up callback functions shall be * provided when calling this function. * If SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to true, this function checks * for the cause of the reset that implicitly called it and calls the wakeup * callback if the reset was a wakeup from EM4 (does not work on Gecko MCU). * * @param[in] pSleepCb * Pointer to the callback function that is being called before the device is * going to sleep. * * @param[in] pWakeUpCb * Pointer to the callback function that is being called after wake up. ******************************************************************************/ void SLEEP_Init(SLEEP_CbFuncPtr_t pSleepCb, SLEEP_CbFuncPtr_t pWakeUpCb) { /* Initialize callback functions. */ sleepCallback = pSleepCb; wakeUpCallback = pWakeUpCb; /* Reset sleep block counters. Note: not using for() saves code! */ sleepBlockCnt[0U] = 0U; sleepBlockCnt[1U] = 0U; sleepBlockCnt[2U] = 0U; #if (SLEEP_EM4_WAKEUP_CALLBACK_ENABLED == true) && defined(RMU_RSTCAUSE_EM4WURST) /* Check if the Init() happened after an EM4 reset. */ if (RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4WURST) { /* Clear the cause of the reset. */ RMU_ResetCauseClear(); /* Call wakeup callback with EM4 parameter. */ if (NULL != wakeUpCallback) { wakeUpCallback(sleepEM4); } } #endif }
void main () { uint32_t lfa_Hz; uint16_t reset_cause; int sleep_mode = 0; uint32_t burtc_ctrl; CHIP_Init(); reset_cause = RMU->RSTCAUSE; RMU_ResetCauseClear(); #if ! defined(_EFM32_ZERO_FAMILY) BSPACM_CORE_BITBAND_PERIPH(RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT) = 0; #endif SystemCoreClockUpdate(); vBSPACMledConfigure(); setvbuf(stdout, NULL, _IONBF, 0); BSPACM_CORE_ENABLE_INTERRUPT(); printf("\n" __DATE__ " " __TIME__ "\n"); printf("System clock %lu Hz\n", SystemCoreClock); { int i = sizeof(xResetCause)/sizeof(*xResetCause); printf("Reset cause [%04x]:", reset_cause); while (0 <= --i) { const sResetCause * const rcp = xResetCause + i; if (rcp->value == (reset_cause & rcp->mask)) { printf(" %s", rcp->name); } } printf("\nRMU CTRL %lx\n", RMU->CTRL); } /* Enable low-energy support. */ CMU_ClockEnable(cmuClock_CORELE, true); BURTC_Enable(true); if (MAGIC != retained_state->magic) { memset(retained_state, 0, sizeof(*retained_state)); retained_state->magic = MAGIC; printf("Resetting retained state\n"); } ++retained_state->boots; printf("Boot count %lu\n", retained_state->boots); printf("BURTC clock source: "); #if (WITH_ULFRCO - 0) /* Use ULFRCO, which enables EM4 wakeup but is pretty inaccurate. */ printf("ULFRCO\n"); /* NB: DIV2 means 1 kHz instead of 2 kHz */ burtc_ctrl = BURTC_CTRL_CLKSEL_ULFRCO | BURTC_CTRL_PRESC_DIV2; CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_ULFRCO); lfa_Hz = CMU_ClockFreqGet(cmuClock_LFA); { EMU_EM4Init_TypeDef cfg = { .lockConfig = 1, .osc = EMU_EM4CONF_OSC_ULFRCO, .buRtcWakeup = 1, .vreg = 1, }; EMU_EM4Init(&cfg); } #elif (WITH_LFRCO - 0) printf("LFRCO/32\n"); CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); burtc_ctrl = BURTC_CTRL_CLKSEL_LFRCO | BURTC_CTRL_PRESC_DIV32; lfa_Hz = CMU_ClockFreqGet(cmuClock_LFA) / 32; #else printf("LFXO/32\n"); CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO); burtc_ctrl = BURTC_CTRL_CLKSEL_LFXO | BURTC_CTRL_PRESC_DIV32; lfa_Hz = CMU_ClockFreqGet(cmuClock_LFA) / 32; #endif /* LFA source */ printf("LFA clock at %lu Hz ; wake every %u seconds\n", lfa_Hz, WAKE_INTERVAL_S); /* Initialize BURTC. */ if (! (RMU_RSTCAUSE_EM4WURST & reset_cause)) { printf("Initializing BURTC\n"); BURTC->FREEZE = BURTC_FREEZE_REGFREEZE; BURTC->LPMODE = BURTC_LPMODE_LPMODE_DISABLE; BURTC->CTRL = burtc_ctrl /* CLKSEL + PRESC */ | BURTC_CTRL_RSTEN | BURTC_CTRL_MODE_EM4EN ; BURTC->COMP0 = WAKE_INTERVAL_S * lfa_Hz; BURTC->IEN = BURTC_IF_COMP0; BURTC->CTRL &= ~BURTC_CTRL_RSTEN; BURTC->FREEZE = 0; } else { while (BURTC_SYNCBUSY_COMP0 & BURTC->SYNCBUSY) { } BURTC->COMP0 += WAKE_INTERVAL_S * lfa_Hz; } BURTC->IFC = BURTC_IFC_COMP0; NVIC_EnableIRQ(BURTC_IRQn); printf("BURTC CTRL %lx IEN %lx\n", BURTC->CTRL, BURTC->IEN); (void)iBSPACMperiphUARTflush(hBSPACMdefaultUART, eBSPACMperiphUARTfifoState_TX); while (1) { static const sBSPACMperiphUARTconfiguration cfg = { .speed_baud = 0 }; printf("Sleeping in mode %u, %lu to %lu rtc_if %x or %lx\n", sleep_mode, BURTC->CNT, BURTC->COMP0, burtc_if, BURTC->IF); BSPACM_CORE_DISABLE_INTERRUPT(); do { (void)iBSPACMperiphUARTflush(hBSPACMdefaultUART, eBSPACMperiphUARTfifoState_TX); hBSPACMperiphUARTconfigure(hBSPACMdefaultUART, 0); switch (sleep_mode) { case 0: while (! (BURTC_IF_COMP0 & BURTC->IF)) { } ++sleep_mode; break; case 1: EMU_EnterEM1(); ++sleep_mode; break; case 2: EMU_EnterEM2(true); SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; if (cmuSelect_ULFRCO == CMU_ClockSelectGet(cmuClock_LFA)) { ++sleep_mode; } else { sleep_mode = 0; } break; case 3: EMU_EnterEM3(true); SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; if (cmuSelect_ULFRCO == CMU_ClockSelectGet(cmuClock_LFA)) { ++sleep_mode; } else { sleep_mode = 0; } break; case 4: EMU_EnterEM4(); sleep_mode = 0; break; } } while (0); BSPACM_CORE_ENABLE_INTERRUPT(); hBSPACMperiphUARTconfigure(hBSPACMdefaultUART, &cfg); while (BURTC_SYNCBUSY_COMP0 & BURTC->SYNCBUSY) { } BURTC->COMP0 += WAKE_INTERVAL_S * lfa_Hz; /* Giant Gecko * Source EM0 EM1 EM2 EM3 EM4 * ULFRCO 2.5m 1.1m 622n 622n 450n */ } }
void halInternalClassifyReset(void) { // Table used to convert from RESET_EVENT register bits to reset types static const uint16_t resetEventTable[] = { #ifdef _EZR_DEVICE RESET_POWERON_HV, // bit 0: PORST RESET_BROWNOUT_UNREGPOWER, // bit 1: BODUNREGRST RESET_BROWNOUT_REGPOWER, // bit 2: BODREGRST RESET_EXTERNAL_PIN, // bit 3: EXTRST RESET_WATCHDOG_EXPIRED, // bit 4: WDOGRST RESET_FATAL_LOCKUP, // bit 5: LOCKUPRST RESET_SOFTWARE, // bit 6: SYSREQRST RESET_SOFTWARE_EM4, // bit 7: EM4RST RESET_EXTERNAL_EM4PIN, // bit 8: EM4WURST RESET_BROWNOUT_AVDD0, // bit 9: BODAVDD0 RESET_BROWNOUT_AVDD1, // bit 10: BODAVDD1 RESET_BROWNOUT_BACKUP_VDD_DREG, // bit 11: BUBODVDDDREG RESET_BROWNOUT_BACKUP_BU_VIN, // bit 12: BUBODBUVIN RESET_BROWNOUT_BACKUP_UNREGPOWER, // bit 13: BUBODUNREG RESET_BROWNOUT_BACKUP_REGPOWER, // bit 14: BUBODREG RESET_BROWNOUT_BACKUP_MODE, // bit 15: BUMODERST #elif defined _EFR_DEVICE RESET_POWERON_HV, // bit 0: PORST RESET_UNKNOWN_UNKNOWN, // bit 1: RESERVED RESET_BROWNOUT_AVDD, // bit 2: AVDDBOD RESET_BROWNOUT_DVDD, // bit 3: DVDDBOD RESET_BROWNOUT_DEC, // bit 4: DECBOD RESET_UNKNOWN_UNKNOWN, // bit 5: RESERVED RESET_UNKNOWN_UNKNOWN, // bit 6: RESERVED RESET_UNKNOWN_UNKNOWN, // bit 7: RESERVED RESET_EXTERNAL_PIN, // bit 8: EXTRST RESET_FATAL_LOCKUP, // bit 9: LOCKUPRST RESET_SOFTWARE, // bit 10: SYSREQRST RESET_WATCHDOG_EXPIRED, // bit 11: WDOGRST RESET_UNKNOWN_UNKNOWN, // bit 12: RESERVED RESET_UNKNOWN_UNKNOWN, // bit 13: RESERVED RESET_UNKNOWN_UNKNOWN, // bit 14: RESERVED RESET_UNKNOWN_UNKNOWN, // bit 15: RESERVED RESET_SOFTWARE_EM4, // bit 16: EM4RST #endif }; uint32_t resetEvent = RMU_ResetCauseGet(); RMU_ResetCauseClear(); uint16_t cause = RESET_UNKNOWN; uint16_t i; for (i = 0; i < sizeof(resetEventTable)/sizeof(resetEventTable[0]); i++) { if (resetEvent & (1 << i)) { cause = resetEventTable[i]; break; } } if (cause == RESET_SOFTWARE) { if((halResetInfo.crash.resetSignature == RESET_VALID_SIGNATURE) && (RESET_BASE_TYPE(halResetInfo.crash.resetReason) < NUM_RESET_BASE_TYPES)) { // The extended reset cause is recovered from RAM // This can be trusted because the hardware reset event was software // and additionally because the signature is valid savedResetCause = halResetInfo.crash.resetReason; } else { savedResetCause = RESET_SOFTWARE_UNKNOWN; } // mark the signature as invalid halResetInfo.crash.resetSignature = RESET_INVALID_SIGNATURE; } else if ( (cause == RESET_BOOTLOADER_DEEPSLEEP) && (halResetInfo.crash.resetSignature == RESET_VALID_SIGNATURE) && (halResetInfo.crash.resetReason == RESET_BOOTLOADER_DEEPSLEEP)) { // Save the crash info for bootloader deep sleep (even though it's not used // yet) and invalidate the resetSignature. halResetInfo.crash.resetSignature = RESET_INVALID_SIGNATURE; savedResetCause = halResetInfo.crash.resetReason; } else { savedResetCause = cause; } // If the last reset was due to an assert, save the assert info. if (savedResetCause == RESET_CRASH_ASSERT) { savedAssertInfo = halResetInfo.crash.data.assertInfo; } }