/** @file hal/micro/cortexm3/sleep.c * * @brief STM32W108 micro specific sleep functions. * * */ #include PLATFORM_HEADER #include "hal/micro/micro-common.h" #include "hal/micro/cortexm3/micro-common.h" //We don't have a real register to hold this composite information. //Pretend we do so halGetWakeInfo can operate like halGetResetInfo. //This "register" is only ever set by halInternalSleep. // [31] = WakeInfoValid // [30] = SleepSkipped // [29] = CSYSPWRUPREQ // [28] = CDBGPWRUPREQ // [27] = WAKE_CORE // [26] = TIMER_WAKE_WRAP // [25] = TIMER_WAKE_COMPB // [24] = TIMER_WAKE_COMPA // [23:0] = corresponding GPIO activity #define WAKEINFOVALID_INTERNAL_WAKE_EVENT_BIT 31 #define SLEEPSKIPPED_INTERNAL_WAKE_EVENT_BIT 30 #define CSYSPWRUPREQ_INTERNAL_WAKE_EVENT_BIT 29 #define CDBGPWRUPREQ_INTERNAL_WAKE_EVENT_BIT 28 #define WAKE_CORE_INTERNAL_WAKE_EVENT_BIT 27 #define WRAP_INTERNAL_WAKE_EVENT_BIT 26 #define CMPB_INTERNAL_WAKE_EVENT_BIT 25 #define CMPA_INTERNAL_WAKE_EVENT_BIT 24 //This define shifts events from the PWRUP_EVENT register into the proper //place in the halInternalWakeEvent variable #define INTERNAL_WAKE_EVENT_BIT_SHIFT 20 static uint32_t halInternalWakeEvent=0; uint32_t halGetWakeInfo(void) { return halInternalWakeEvent; } void halInternalSleep(SleepModes sleepMode) { //Timer restoring always takes place during the wakeup sequence. We save //the state here in case SLEEPMODE_NOTIMER is invoked, which would disable //the clocks. uint32_t SLEEPTMR_CLKEN_SAVED = SLEEPTMR_CLKEN; //This code assumes all wake source registers are properly configured. //As such, it should be called from halSleepWithOptions() or from // halSleepForQsWithOptions() which configues the wake sources. //The parameter gpioWakeSel is a bitfield composite of the GPIO wake //sources derived from the 3 ports, indicating which of the 24 GPIO //are configured as a wake source. uint32_t gpioWakeSel = (GPIO_PAWAKE<<0); gpioWakeSel |= (GPIO_PBWAKE<<8); gpioWakeSel |= (GPIO_PCWAKE<<16); //PB2 is also WAKE_SC1. Set this wake source if PB2's GPIO wake is set. if(GPIO_PBWAKE & PB2) { WAKE_SEL |= WAKE_SC1; } //PA2 is also WAKE_SC2. Set this wake source if PA2's GPIO wake is set. if(GPIO_PAWAKE & PA2) { WAKE_SEL |= WAKE_SC2; } //The WAKE_IRQD source can come from any pin based on IRQD's sel register. if(gpioWakeSel & BIT(GPIO_IRQDSEL)) { WAKE_SEL |= WAKE_IRQD; } halInternalWakeEvent = 0; //clear old wake events switch(sleepMode) { case SLEEPMODE_NOTIMER: //The sleep timer clock sources (both RC and XTAL) are turned off. //Wakeup is possible from only GPIO. System time is lost. //NOTE: Timer restoring always takes place during the wakeup sequence. SLEEPTMR_CLKEN = 0; goto deepSleepCore; case SLEEPMODE_WAKETIMER: //The sleep timer clock sources remain running. The RC is always //running and the 32kHz XTAL depends on the board header. Wakeup //is possible from both GPIO and the sleep timer. System time //is maintained. The sleep timer is assumed to be configured //properly for wake events. //NOTE: This mode assumes the caller has configured the *entire* // sleep timer properly. if(INT_SLEEPTMRCFG&INT_SLEEPTMRWRAP) { WAKE_SEL |= WAKE_SLEEPTMRWRAP; } if(INT_SLEEPTMRCFG&INT_SLEEPTMRCMPB) { WAKE_SEL |= WAKE_SLEEPTMRCMPB; } if(INT_SLEEPTMRCFG&INT_SLEEPTMRCMPA) { WAKE_SEL |= WAKE_SLEEPTMRCMPA; } //fall into SLEEPMODE_MAINTAINTIMER's sleep code: case SLEEPMODE_MAINTAINTIMER: //The sleep timer clock sources remain running. The RC is always //running and the 32kHz XTAL depends on the board header. Wakeup //is possible from only GPIO. System time is maintained. //NOTE: System time is maintained without any sleep timer interrupts // because the hardware sleep timer counter is large enough // to hold the entire count value and not need a RAM counter. //////////////////////////////////////////////////////////////////////////// // Core deep sleep code //////////////////////////////////////////////////////////////////////////// deepSleepCore: // Interrupts *must* be/stay disabled for DEEP SLEEP operation // INTERRUPTS_OFF will use BASEPRI to disable all interrupts except // fault handlers and PendSV. INTERRUPTS_OFF(); // This is the point of no return. From here on out, only the interrupt // sources available in WAKE_SEL will be captured and propagated across // deep sleep. //stick all our saved info onto stack since it's only temporary { boolean restoreWatchdog = halInternalWatchDogEnabled(); boolean skipSleep = FALSE; // Only three register blocks keep power across deep sleep: // CM_HV, GPIO, SLOW_TIMERS // // All other register blocks lose their state across deep sleep: // BASEBAND, MAC, SECURITY, SERIAL, TMR1, TMR2, EVENT, CM_LV, RAM_CTRL, // AUX_ADC, CAL_ADC, FLASH_CONTROL, ITM, DWT, FPB, NVIC, TPIU // // The sleep code will only save and restore registers where it is // meaningful and necessary to do so. In most cases, there must still // be a powerup function to restore proper state. // // NOTE: halPowerUp() and halPowerDown() will always be called before // and after this function. halPowerDown and halPowerUp should leave // the modules in a safe state and then restart the modules. // (For example, shutting down and restarting Timer1) // //----BASEBAND // reinitialized by stStackPowerUp() //----MAC // reinitialized by stStackPowerUp() //----SECURITY // reinitialized by stStackPowerUp() //----SERIAL // reinitialized by halPowerUp() or similar //----TMR1 // reinitialized by halPowerUp() or similar //----TMR2 // reinitialized by halPowerUp() or similar //----EVENT //SRC or FLAG interrupts are not saved or restored //MISS interrupts are not saved or restored //MAC_RX_INT_MASK - reinitialized by stStackPowerUp() //MAC_TX_INT_MASK - reinitialized by stStackPowerUp() //MAC_TIMER_INT_MASK - reinitialized by stStackPowerUp() //BB_INT_MASK - reinitialized by stStackPowerUp() //SEC_INT_MASK - reinitialized by stStackPowerUp() uint32_t INT_SLEEPTMRCFG_SAVED = INT_SLEEPTMRCFG_REG; uint32_t INT_MGMTCFG_SAVED = INT_MGMTCFG_REG; //INT_TIM1CFG - reinitialized by halPowerUp() or similar //INT_TIM2CFG - reinitialized by halPowerUp() or similar //INT_SC1CFG - reinitialized by halPowerUp() or similar //INT_SC2CFG - reinitialized by halPowerUp() or similar //INT_ADCCFG - reinitialized by halPowerUp() or similar uint32_t GPIO_INTCFGA_SAVED = GPIO_INTCFGA_REG; uint32_t GPIO_INTCFGB_SAVED = GPIO_INTCFGB_REG; uint32_t GPIO_INTCFGC_SAVED = GPIO_INTCFGC_REG; uint32_t GPIO_INTCFGD_SAVED = GPIO_INTCFGD_REG; //SC1_INTMODE - reinitialized by halPowerUp() or similar //SC2_INTMODE - reinitialized by halPowerUp() or similar //----CM_LV uint32_t OSC24M_BIASTRIM_SAVED = OSC24M_BIASTRIM_REG; uint32_t OSCHF_TUNE_SAVED = OSCHF_TUNE_REG; uint32_t DITHER_DIS_SAVED = DITHER_DIS_REG; //OSC24M_CTRL - reinitialized by halPowerUp() or similar //CPU_CLKSEL - reinitialized by halPowerUp() or similar //TMR1_CLK_SEL - reinitialized by halPowerUp() or similar //TMR2_CLK_SEL - reinitialized by halPowerUp() or similar uint32_t PCTRACE_SEL_SAVED = PCTRACE_SEL_REG; //----RAM_CTRL uint32_t MEM_PROT_0_SAVED = MEM_PROT_0_REG; uint32_t MEM_PROT_1_SAVED = MEM_PROT_1_REG; uint32_t MEM_PROT_2_SAVED = MEM_PROT_2_REG; uint32_t MEM_PROT_3_SAVED = MEM_PROT_3_REG; uint32_t MEM_PROT_4_SAVED = MEM_PROT_4_REG; uint32_t MEM_PROT_5_SAVED = MEM_PROT_5_REG; uint32_t MEM_PROT_6_SAVED = MEM_PROT_6_REG; uint32_t MEM_PROT_7_SAVED = MEM_PROT_7_REG; uint32_t MEM_PROT_EN_SAVED = MEM_PROT_EN_REG; //----AUX_ADC // reinitialized by halPowerUp() or similar //----CAL_ADC // reinitialized by stStackPowerUp() //----FLASH_CONTROL // configured on the fly by the flash library //----ITM // reinitialized by halPowerUp() or similar //----DWT // not used by software on chip //----FPB // not used by software on chip //----NVIC //ST_CSR - fixed, restored by cstartup when exiting deep sleep //ST_RVR - fixed, restored by cstartup when exiting deep sleep uint32_t INT_CFGSET_SAVED = INT_CFGSET_REG; //mask against wake sources //INT_PENDSET - used below when overlapping interrupts and wake sources //NVIC_IPR_3to0 - fixed, restored by cstartup when exiting deep sleep //NVIC_IPR_7to4 - fixed, restored by cstartup when exiting deep sleep //NVIC_IPR_11to8 - fixed, restored by cstartup when exiting deep sleep //NVIC_IPR_15to12 - fixed, restored by cstartup when exiting deep sleep //NVIC_IPR_19to16 - fixed, restored by cstartup when exiting deep sleep uint32_t SCS_VTOR_SAVED = SCS_VTOR_REG; //SCS_CCR - fixed, restored by cstartup when exiting deep sleep //SCS_SHPR_7to4 - fixed, restored by cstartup when exiting deep sleep //SCS_SHPR_11to8 - fixed, restored by cstartup when exiting deep sleep //SCS_SHPR_15to12 - fixed, restored by cstartup when exiting deep sleep //SCS_SHCSR - fixed, restored by cstartup when exiting deep sleep //----TPIU // reinitialized by halPowerUp() or similar //stmDebugPowerDown() should have shutdown the DWT/ITM/TPIU already. //freeze input to the GPIO from LV (alternate output functions freeze) EVENT_CTRL = LV_FREEZE; //record GPIO state for wake monitoring purposes //By having a snapshot of GPIO state, we can figure out after waking //up exactly which GPIO could have woken us up. //Reading the three IN registers is done separately to avoid warnings //about undefined order of volatile access. uint32_t GPIO_IN_SAVED = GPIO_PAIN; GPIO_IN_SAVED |= (GPIO_PBIN<<8); GPIO_IN_SAVED |= (GPIO_PCIN<<16); //reset the power up events by writing 1 to all bits. PWRUP_EVENT = 0xFFFFFFFF; //By clearing the events, the wake up event capturing is activated. //At this point we can safely check our interrupt flags since event //capturing is now overlapped. Up to now, interrupts indicate //activity, after this point, powerup events indicate activity. //If any of the interrupt flags are set, that means we saw a wake event //sometime while entering sleep, so we need to skip over sleeping // //--possible interrupt sources for waking: // IRQA, IRQB, IRQC, IRQD // SleepTMR CMPA, CMPB, Wrap // WAKE_CORE (DebugIsr) // //check for IRQA interrupt and if IRQA (PB0) is wake source if((INT_PENDSET&INT_IRQA) && (GPIO_PBWAKE&PB0) && (WAKE_SEL&GPIO_WAKE)) { skipSleep = TRUE; //log IRQA as a wake event halInternalWakeEvent |= BIT(PORTB_PIN(0)); } //check for IRQB interrupt and if IRQB (PB6) is wake source if((INT_PENDSET&INT_IRQB) && (GPIO_PBWAKE&PB6) && (WAKE_SEL&GPIO_WAKE)) { skipSleep = TRUE; //log IRQB as a wake event halInternalWakeEvent |= BIT(PORTB_PIN(6)); } //check for IRQC interrupt and if IRQC (GPIO_IRQCSEL) is wake source if((INT_PENDSET&INT_IRQC) && (gpioWakeSel&BIT(GPIO_IRQCSEL)) && (WAKE_SEL&GPIO_WAKE)) { skipSleep = TRUE; //log IRQC as a wake event halInternalWakeEvent |= BIT(GPIO_IRQCSEL); } //check for IRQD interrupt and if IRQD (GPIO_IRQDSEL) is wake source if((INT_PENDSET&INT_IRQD) && (gpioWakeSel&BIT(GPIO_IRQDSEL)) && ((WAKE_SEL&GPIO_WAKE) || (WAKE_SEL&WAKE_IRQD))) { skipSleep = TRUE; //log IRQD as a wake event halInternalWakeEvent |= BIT(GPIO_IRQDSEL); } //check for SleepTMR CMPA interrupt and if SleepTMR CMPA is wake source if((INT_SLEEPTMR&INT_SLEEPTMRCMPA) && (WAKE_SEL&WAKE_SLEEPTMRCMPA)) { skipSleep = TRUE; //log SleepTMR CMPA as a wake event halInternalWakeEvent |= BIT32(CMPA_INTERNAL_WAKE_EVENT_BIT); } //check for SleepTMR CMPB interrupt and if SleepTMR CMPB is wake source if((INT_SLEEPTMR&INT_SLEEPTMRCMPB) && (WAKE_SEL&WAKE_SLEEPTMRCMPB)) { skipSleep = TRUE; //log SleepTMR CMPB as a wake event halInternalWakeEvent |= BIT32(CMPB_INTERNAL_WAKE_EVENT_BIT); } //check for SleepTMR WRAP interrupt and if SleepTMR WRAP is wake source if((INT_SLEEPTMR&INT_SLEEPTMRWRAP) && (WAKE_SEL&WAKE_SLEEPTMRWRAP)) { skipSleep = TRUE; //log SleepTMR WRAP as a wake event halInternalWakeEvent |= BIT32(WRAP_INTERNAL_WAKE_EVENT_BIT); } //check for Debug interrupt and if WAKE_CORE is wake source if((INT_PENDSET&INT_DEBUG) && (WAKE_SEL&WAKE_WAKE_CORE)) { skipSleep = TRUE; //log WAKE_CORE as a wake event halInternalWakeEvent |= BIT32(WAKE_CORE_INTERNAL_WAKE_EVENT_BIT); } //only propagate across deep sleep the interrupts that are both //enabled and possible wake sources { uint32_t wakeSourceInterruptMask = 0; if(GPIO_PBWAKE&PB0) { wakeSourceInterruptMask |= INT_IRQA; } if(GPIO_PBWAKE&PB6) { wakeSourceInterruptMask |= INT_IRQB; } if(gpioWakeSel&BIT(GPIO_IRQCSEL)) { wakeSourceInterruptMask |= INT_IRQC; } if(gpioWakeSel&BIT(GPIO_IRQDSEL)) { wakeSourceInterruptMask |= INT_IRQD; } if( (WAKE_SEL&WAKE_SLEEPTMRCMPA) || (WAKE_SEL&WAKE_SLEEPTMRCMPB) || (WAKE_SEL&WAKE_SLEEPTMRWRAP) ) { wakeSourceInterruptMask |= INT_SLEEPTMR; } if(WAKE_SEL&WAKE_WAKE_CORE) { wakeSourceInterruptMask |= INT_DEBUG; } INT_CFGSET_SAVED &= wakeSourceInterruptMask; } //disable watchdog while sleeping (since we can't reset it asleep) halInternalDisableWatchDog(MICRO_DISABLE_WATCH_DOG_KEY); //The chip is not allowed to enter a deep sleep mode (which could //cause a core reset cycle) while CSYSPWRUPREQ is set. CSYSPWRUPREQ //indicates that the debugger is trying to access sections of the //chip that would get reset during deep sleep. Therefore, a reset //cycle could very easily cause the debugger to error and we don't //want that. While the power management state machine will stall //if CSYSPWRUPREQ is set (to avoid the situation just described), //in this stalled state the chip will not be responsive to wake //events. To be sensitive to wake events, we must handle them in //software instead. To accomplish this, we request that the //CSYSPWRUPACK be inhibited (which will indicate the debugger is not //connected). But, we cannot induce deep sleep until CSYSPWRUPREQ/ACK //go low and these are under the debuggers control, so we must stall //and wait here. If there is a wake event during this time, break //out and wake like normal. If the ACK eventually clears, //we can proceed into deep sleep. The CSYSPWRUPACK_INHIBIT //functionality will hold off the debugger (by holding off the ACK) //until we are safely past and out of deep sleep. The power management //state machine then becomes responsible for clearing //CSYSPWRUPACK_INHIBIT and responding to a CSYSPWRUPREQ with a //CSYSPWRUPACK at the right/safe time. CSYSPWRUPACK_INHIBIT = CSYSPWRUPACK_INHIBIT_CSYSPWRUPACK_INHIBIT; { //Use a local copy of WAKE_SEL to avoid warnings from the compiler //about order of volatile accesses uint32_t wakeSel = WAKE_SEL; //stall until a wake event or CSYSPWRUPREQ/ACK clears while( (CSYSPWRUPACK_STATUS) && (!(PWRUP_EVENT&wakeSel)) ) {} //if there was a wake event, allow CSYSPWRUPACK and skip sleep if(PWRUP_EVENT&wakeSel) { CSYSPWRUPACK_INHIBIT = CSYSPWRUPACK_INHIBIT_RESET; skipSleep = TRUE; } } if(!skipSleep) { //FogBugz 7283 states that we must switch to the OSCHF when entering //deep sleep since using the 24MHz XTAL could result in RAM //corruption. This switch must occur at least 2*24MHz cycles before //sleeping. //FogBugz 8858 states that we cannot go into deep-sleep when the //chip is clocked with the 24MHz XTAL with a duty cycle as low as //70/30 since this causes power_down generation timing to fail. OSC24M_CTRL &= ~OSC24M_CTRL_OSC24M_SEL; //If DS12 needs to be forced regardless of state, clear //REGEN_DSLEEP here. This is hugely dangerous and //should only be done in very controlled chip tests. SCS_SCR |= SCS_SCR_SLEEPDEEP; //enable deep sleep extern volatile boolean halPendSvSaveContext; halPendSvSaveContext = 1; //1 means save context //The INTERRUPTS_OFF used at the beginning of this function set //BASEPRI such that the only interrupts that will fire are faults //and PendSV. Trigger PendSV now to induce a context save. SCS_ICSR |= SCS_ICSR_PENDSVSET; //pend the context save and Dsleep //Since the interrupt will not fire immediately it is possible to //execute a few lines of code. To stay halted in this spot until the //WFI instruction, spin on the context flag (which will get cleared //during the startup sequence when restoring context). while(halPendSvSaveContext) {} //I AM ASLEEP. WHEN EXECUTION RESUMES, CSTARTUP WILL RESTORE TO HERE } else { //Record the fact that we skipped sleep halInternalWakeEvent |= BIT32(SLEEPSKIPPED_INTERNAL_WAKE_EVENT_BIT); //If this was a true deep sleep, we would have executed cstartup and //PRIMASK would be set right now. If we skipped sleep, PRIMASK is not //set so we explicitely set it to guarantee the powerup sequence //works cleanly and consistently with respect to interrupt //dispatching and enabling. _setPriMask(); } //Clear the interrupt flags for all wake sources. This //is necessary because if we don't execute an actual deep sleep cycle //the interrupt flags will never be cleared. By clearing the flags, //we always mimick a real deep sleep as closely as possible and //guard against any accidental interrupt triggering coming out //of deep sleep. (The interrupt dispatch code coming out of sleep //is responsible for translating wake events into interrupt events, //and if we don't clear interrupt flags here it's possible for an //interrupt to trigger even if it wasn't the true wake event.) INT_SLEEPTMRFLAG = (INT_SLEEPTMRCMPA | INT_SLEEPTMRCMPB | INT_SLEEPTMRWRAP); INT_GPIOFLAG = (INT_IRQAFLAG | INT_IRQBFLAG | INT_IRQCFLAG | INT_IRQDFLAG); //immediately restore the registers we saved before sleeping //so IRQ and SleepTMR capture can be reenabled as quickly as possible //this is safe because our global interrupts are still disabled //other registers will be restored later SLEEPTMR_CLKEN_REG = SLEEPTMR_CLKEN_SAVED; INT_SLEEPTMRCFG_REG = INT_SLEEPTMRCFG_SAVED; INT_MGMTCFG_REG = INT_MGMTCFG_SAVED; GPIO_INTCFGA_REG = GPIO_INTCFGA_SAVED; GPIO_INTCFGB_REG = GPIO_INTCFGB_SAVED; GPIO_INTCFGC_REG = GPIO_INTCFGC_SAVED; GPIO_INTCFGD_REG = GPIO_INTCFGD_SAVED; OSC24M_BIASTRIM_REG = OSC24M_BIASTRIM_SAVED; OSCHF_TUNE_REG = OSCHF_TUNE_SAVED; DITHER_DIS_REG = DITHER_DIS_SAVED; PCTRACE_SEL_REG = PCTRACE_SEL_SAVED; MEM_PROT_0_REG = MEM_PROT_0_SAVED; MEM_PROT_1_REG = MEM_PROT_1_SAVED; MEM_PROT_2_REG = MEM_PROT_2_SAVED; MEM_PROT_3_REG = MEM_PROT_3_SAVED; MEM_PROT_4_REG = MEM_PROT_4_SAVED; MEM_PROT_5_REG = MEM_PROT_5_SAVED; MEM_PROT_6_REG = MEM_PROT_6_SAVED; MEM_PROT_7_REG = MEM_PROT_7_SAVED; MEM_PROT_EN_REG = MEM_PROT_EN_SAVED; INT_CFGSET_REG = INT_CFGSET_SAVED; SCS_VTOR_REG = SCS_VTOR_SAVED; //WAKE_CORE/INT_DEBUG and INT_IRQx is cleared by INT_PENDCLR below INT_PENDCLR = 0xFFFFFFFF; //Now that we're awake, normal interrupts are operational again //Take a snapshot of the new GPIO state and the EVENT register to //record our wake event uint32_t GPIO_IN_NEW = GPIO_PAIN; GPIO_IN_NEW |= (GPIO_PBIN<<8); GPIO_IN_NEW |= (GPIO_PCIN<<16); //Only operate on power up events that are also wake events. Power //up events will always trigger like an interrupt flag, so we have //to check them against events that are enabled for waking. (This is //a two step process because we're accessing two volatile values.) uint32_t powerUpEvents = PWRUP_EVENT; powerUpEvents &= WAKE_SEL; halInternalWakeEvent |= ((GPIO_IN_SAVED^GPIO_IN_NEW)&gpioWakeSel); //PWRUP_SC1 is PB2 which is bit 10 halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_SC1))<<((1*8)+2); //PWRUP_SC2 is PA2 which is bit 2 halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_SC2))<<((0*8)+2); //PWRUP_IRQD is chosen by GPIO_IRQDSEL halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_IRQD))<<(GPIO_IRQDSEL); halInternalWakeEvent |= ((powerUpEvents & (PWRUP_CSYSPWRUPREQ_MASK | PWRUP_CDBGPWRUPREQ_MASK | PWRUP_WAKECORE_MASK | PWRUP_SLEEPTMRWRAP_MASK | PWRUP_SLEEPTMRCOMPB_MASK | PWRUP_SLEEPTMRCOMPA_MASK )) <>0)&0xFF; GPIO_PBWAKE = (gpioWakeBitMask>>8)&0xFF; GPIO_PCWAKE = (gpioWakeBitMask>>16)&0xFF; //use the defines found in the board file to choose our wakeup source(s) WAKE_SEL = 0; //start with no wake sources //if any of the GPIO wakeup monitor bits are set, enable the top level //GPIO wakeup monitor if((GPIO_PAWAKE)||(GPIO_PBWAKE)||(GPIO_PCWAKE)) { WAKE_SEL |= GPIO_WAKE; } //always wakeup when the debugger is connected WAKE_SEL |= WAKE_CDBGPWRUPREQ; //always wakeup when the debugger attempts to access the chip WAKE_SEL |= WAKE_CSYSPWRUPREQ; //always wakeup when the debug channel attempts to access the chip WAKE_SEL |= WAKE_WAKE_CORE; //the timer wakeup sources are enabled below in POWERSAVE, if needed //wake sources are configured so do the actual sleeping halInternalSleep(sleepMode); }