void hw_enter_lowpower_mode(uint8_t mode) { switch(mode) { case 0: { EMU_EnterEM1(); break; } case 1: { EMU_EnterEM2(true); break; } case 2: { EMU_EnterEM3(true); break; } case 4: { EMU_EnterEM4(); break; } default: { assert(0); } } }
/**************************************************************************//** * @brief Check if PB0 is pushed and EM4 entry is due. *****************************************************************************/ static void CheckEM4Entry( void ) { if ( enterEM4 ) { enterEM4 = false; printf( "\f\n\n Ready to enter" "\n energy mode" "\n EM4" "\n\n Push PB0 to" "\n enter EM4" "\n\n Wakeup from" "\n EM4 by pushing" "\n PB1 or the" "\n reset button" ); while ( enterEM4 == false ); enterEM4 = false; /* Disable the RTC and PCNT. */ printf( "\f" ); displayEnabled = false; NVIC_DisableIRQ( RTC_IRQn ); NVIC_DisableIRQ( PCNT0_IRQn ); /* Power down the display. */ displayDevice.pDisplayPowerOn( &displayDevice, false ); /* Enable wakeup from EM4 on PB1 GPIO pin. */ GPIO_EM4EnablePinWakeup( GPIO_EM4WUEN_EM4WUEN_C9, 0 ); EMU_EnterEM4(); } }
enum lpm_mode lpm_arch_set(enum lpm_mode target) { switch (target) { case LPM_ON: /* nothing to do */ break; case LPM_IDLE: /* wait for next event or interrupt */ EMU_EnterEM1(); break; case LPM_SLEEP: /* after exiting EM2, clocks are restored */ EMU_EnterEM2(true); break; case LPM_POWERDOWN: /* after exiting EM3, clocks are restored */ EMU_EnterEM3(true); break; case LPM_OFF: /* only a reset can wake up from EM4 */ EMU_EnterEM4(); break; /* do nothing here */ case LPM_UNKNOWN: default: break; } /* no matter which case was selected, instructions executed in EM0 only */ return LPM_ON; }
/**************************************************************************//** * @brief Sleeps in EM4 until reset *****************************************************************************/ void EM4Sleep(void) { /* Tell AEM we're in EM4 */ BSP_EnergyModeSet(4); EMU_EnterEM4(); /* we will never wake up again here - reset required */ }
ERROR_CODE Statemachine::startApplication( STATUS_BLOCK *statusBlock ) { callingStatusBlock = currentStatusBlock; currentStatusBlock = statusBlock; if(!setupDone) return FSM_NotInitialized; // Run the FSM until the execution is stopped by the Application-Code. // The State-Function is called within the WHILE-STATEMENT !!!! while( ( *(stateDefinition)[statusBlock->nextState] )() ) { // Is the State-Function, which is selected for execution in the next step a valid one? if( currentStatusBlock->nextState < maxNumberOfStates ) { // Does the MCU have to enter a sleep-mode? if( currentStatusBlock->wantToSleep ) { // Which sleep-mode has to be entered? switch( currentStatusBlock->sleepMode ) { case 0: break; case 1: EMU_EnterEM1(); break; case 2: EMU_EnterEM2( currentStatusBlock->restoreClockSetting ); break; case 3: EMU_EnterEM3( currentStatusBlock->restoreClockSetting ); break; case 4: EMU_EnterEM4(); default: return EM_invalid; // Invalid sleep-mode!!! } } } else return StateID_Invalid; // Invalid State-Function number!!! } currentStatusBlock = callingStatusBlock; return FSM_finalized; // FSM-execution successfully finalized!!! }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { /* Initialize chip */ CHIP_Init(); setupSWO(); BSP_LedsInit(); /* Enable clock for GPIO module */ CMU_ClockEnable(cmuClock_GPIO, true); /* Configure interrupt for Push Button 0 */ GPIO_PinModeSet(PB0_PORT, PB0_PIN, gpioModeInput, 1); #if defined(_EFM32_GIANT_FAMILY) NVIC_EnableIRQ(GPIO_ODD_IRQn); #else NVIC_EnableIRQ(GPIO_EVEN_IRQn); #endif GPIO_IntConfig(PB0_PORT, PB0_PIN, false, true, true); /* By turning on retention in EM4, the state of the GPIO pins * can be retained in all energy modes */ GPIO->CTRL = GPIO_CTRL_EM4RET; /* Uncomment to drive LED in all energy modes */ /* BSP_LedSet(0);*/ while (1) { switch (STATE) { case EM0: break; case EM1: EMU_EnterEM1(); break; case EM2: EMU_EnterEM2(true); break; case EM3: EMU_EnterEM3(true); case EM4: EMU_EnterEM4(); break; } } }
/***************************************************************************//** * @brief * Call the callbacks and enter the requested energy mode. * * @details * This function is not part of the API, therefore it shall not be called by * the user directly as it doesn not have any checks if the system is ready * for sleep! * * @note * The EM4 wakeup callback is not being called from this function because * waking up from EM4 causes a reset. * If SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to true, SLEEP_Init() function * checks for the cause of the reset and calls the wakeup callback if the * reset was a wakeup from EM4. ******************************************************************************/ static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode) { EFM_ASSERT((eMode > sleepEM0) && (eMode <= sleepEM4)); /* Call sleepCallback() before going to sleep. */ if (NULL != sleepCallback) { /* Call the callback before going to sleep. */ sleepCallback(eMode); } /* Enter the requested energy mode. */ switch (eMode) { case sleepEM1: { EMU_EnterEM1(); } break; case sleepEM2: { EMU_EnterEM2(true); } break; case sleepEM3: { EMU_EnterEM3(true); } break; case sleepEM4: { EMU_EnterEM4(); } break; default: { /* Don't do anything, stay in EM0. */ } break; } /* Call the callback after waking up from sleep. */ if (NULL != wakeUpCallback) { wakeUpCallback(eMode); } }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { const int msDelay = 100; /* Chip errata */ CHIP_Init(); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Power down special RAM blocks to reduce current consumption with some nA. */ CMU_ClockEnable(cmuClock_CORELE, true); LESENSE->POWERDOWN = LESENSE_POWERDOWN_RAM; CMU_ClockEnable(cmuClock_CORELE, false); /* Configure push button interrupts */ gpioSetup(); /* Setup SysTick Timer for 1 msec interrupts */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; /* Initialize LCD controller */ SegmentLCD_Init(false); /* Run countdown for user to select energy mode */ msCountDown = 4000; /* milliseconds */ while (msCountDown > 0) { switch (eMode) { case 0: SegmentLCD_Write("EM0 32M"); break; case 1: SegmentLCD_Write("EM1 32M"); break; case 2: SegmentLCD_Write("EM2 32K"); break; case 3: SegmentLCD_Write("EM3"); break; case 4: SegmentLCD_Write("EM4"); break; case 5: SegmentLCD_Write("EM2+RTC"); break; case 6: SegmentLCD_Write("RTC+LCD"); break; case 7: SegmentLCD_Write("EM3+RTC"); break; case 8: SegmentLCD_Write("USER"); break; } SegmentLCD_Number(msCountDown); Delay(msDelay); msCountDown -= msDelay; } /* Disable components, reenable when needed */ SegmentLCD_Disable(); RTC_Enable(false); /* GPIO->ROUTE = 0x00000000; */ /* Go to energy mode and wait for reset */ switch (eMode) { case 0: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; /* 32Mhz primes demo - running off HFXO */ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; /* Supress Conditional Branch Target Prefetch */ MSC->READCTRL = MSC_READCTRL_MODE_WS1SCBTP; { #define PRIM_NUMS 64 uint32_t i, d, n; uint32_t primes[PRIM_NUMS]; /* Find prime numbers forever */ while (1) { primes[0] = 1; for (i = 1; i < PRIM_NUMS;) { for (n = primes[i - 1] + 1;; n++) { for (d = 2; d <= n; d++) { if (n == d) { primes[i] = n; goto nexti; } if (n % d == 0) break; } } nexti: i++; } } } case 1: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM1(); break; case 2: /* Enable LFRCO */ CMU->OSCENCMD = CMU_OSCENCMD_LFRCOEN; /* Disable everything else */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; /* Disable LFB clock select */ CMU->LFCLKSEL = 0x00000000; EMU_EnterEM2(false); break; case 3: /* Disable all clocks */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM3(false); break; case 4: /* Go straight down to EM4 */ EMU_EnterEM4(); break; case 5: /* EM2 + RTC - only briefly wake up to reconfigure every 2 seconds */ /* Disable LFB clock select */ CMU->LFCLKSEL &= ~(_CMU_LFCLKSEL_LFB_MASK); RTCDRV_Setup(cmuSelect_LFRCO, cmuClkDiv_32); while (1) { RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); } case 6: /* EM2 + RTC + LCD (if battery slips below 3V vboost should be enabled) */ /* Disable LFB clock select */ CMU->LFCLKSEL &= ~(_CMU_LFCLKSEL_LFB_MASK); SegmentLCD_Init(false); RTCDRV_Setup(cmuSelect_LFRCO, cmuClkDiv_32); while (1) { SegmentLCD_Write("Silicon"); /* Sleep in EM2 */ RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); SegmentLCD_Write(" Labs"); /* Sleep in EM2 */ RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); } case 7: /* EM3 + RTC - only briefly wake up to reconfigure every ~5 seconds */ while (1) { /* Disable LFB clock select */ CMU->LFCLKSEL &= ~(_CMU_LFCLKSEL_LFB_MASK); /* This RTCDRV_Setup will configure LFCLK A as ULFRCO */ RTCDRV_Setup(cmuSelect_ULFRCO, cmuClkDiv_1); RTCDRV_Trigger(5000, NULL); /* Sleep in EM3, wake up on RTC trigger */ EMU_EnterEM3(false); /* SegmentLCD_Init will configure LFCLK A as LFRCO */ SegmentLCD_Init(false); SegmentLCD_Write("ULFRCO"); Delay(1000); SegmentLCD_Disable(); } case 8: default: /* User defined */ break; } return 0; }
/**************************************************************************//** * @brief Energy Mode 4 demonstration *****************************************************************************/ void Demo_EM4(void) { EMU_EnterEM4(); }
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 */ } }
/**************************************************************************//** * @brief Sleeps in EM4 until reset *****************************************************************************/ void EM4Sleep(void) { EMU_EnterEM4(); /* we will never wake up again here - reset required */ }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { int msCountDown; const int msDelay = 100; char displayString[8]; LCD_AnimInit_TypeDef anim = { true, 0x00, lcdAnimShiftNone, 0x03, lcdAnimShiftLeft, lcdAnimLogicOr }; LCD_FrameCountInit_TypeDef fc = { true, 2, /* Update each 2nd frame */ lcdFCPrescDiv1, }; /* Chip errata */ CHIP_Init(); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Configure push button interrupts */ gpioSetup(); /* Setup SysTick Timer for 1 msec interrupts */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; /* Initialize LCD controller */ SegmentLCD_Init(false); /* Run countdown for user to select energy mode */ msCountDown = 4000; /* milliseconds */ while(msCountDown > 0) { if ( eMode >=3 && eMode<=4) { sprintf(displayString, "EM%d", eMode); SegmentLCD_Write(displayString); } switch( eMode ) { case 0: SegmentLCD_Write("EM0 32M"); break; case 1: SegmentLCD_Write("EM1 32M"); break; case 2: SegmentLCD_Write("EM2 32K"); break; case 5: SegmentLCD_Write("EM2+RTC"); break; case 6: SegmentLCD_Write("RTC+LCD"); break; } SegmentLCD_Number(msCountDown); Delay(msDelay); msCountDown -= msDelay; } /* Disable components, reenable when needed */ SegmentLCD_Disable(); RTC_Enable(false); /* Go to energy mode and wait for reset */ switch(eMode) { case 0: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; /* 32Mhz primes demo - running off HFXO */ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; /* Supress Conditional Branch Target Prefetch */ MSC->READCTRL = MSC_READCTRL_MODE_WS1SCBTP; { #define PRIM_NUMS 64 uint32_t i, d, n; uint32_t primes[PRIM_NUMS]; /* Find prime numbers forever */ while (1) { primes[0] = 1; for (i = 1; i < PRIM_NUMS;) { for (n = primes[i - 1] + 1; ;n++) { for (d = 2; d <= n; d++) { if (n == d) { primes[i] = n; goto nexti; } if (n%d == 0) break; } } nexti: i++; } } } case 1: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM1(); break; case 2: /* Enable LFRCO */ CMU->OSCENCMD = CMU_OSCENCMD_LFRCOEN; /* Disable everything else */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM2(false); break; case 3: /* Disable all clocks */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; EMU_EnterEM3(false); break; case 4: EMU_EnterEM4(); break; case 5: /* EM2 + RTC - only briefly wake up to reconfigure each second */ CMU->LFCLKSEL = CMU_LFCLKSEL_LFA_LFRCO; while(1) { RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); } case 6: default: /* EM2 + RTC + LCD (if battery slips below 3V vboost should be */ /* enabled) */ CMU->LFCLKSEL = CMU_LFCLKSEL_LFA_LFRCO; SegmentLCD_Init(false); /* Animate LCD */ LCD_FrameCountInit(&fc); LCD_AnimInit(&anim); while(1) { SegmentLCD_Write("Energy"); /* Sleep in EM2 */ RTCDRV_Trigger(2000,NULL); EMU_EnterEM2(false); SegmentLCD_Write("Micro"); /* Sleep in EM2 */ RTCDRV_Trigger(2000,NULL); EMU_EnterEM2(false); } } return 0; }