Contiki 2.6

sleep.c

Go to the documentation of this file.
00001 /** @file hal/micro/cortexm3/sleep.c
00002  * 
00003  * @brief STM32W108 micro specific sleep functions.
00004  *
00005  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
00006  */
00007 
00008 #include PLATFORM_HEADER
00009 #include "hal/micro/micro-common.h"
00010 #include "hal/micro/cortexm3/micro-common.h"
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 
00094 
00095 
00096 //We don't have a real register to hold this composite information.
00097 //Pretend we do so halGetWakeInfo can operate like halGetResetInfo.
00098 //This "register" is only ever set by halInternalSleep.
00099 // [31] = WakeInfoValid
00100 // [30] = SleepSkipped
00101 // [29] = CSYSPWRUPREQ
00102 // [28] = CDBGPWRUPREQ
00103 // [27] = WAKE_CORE
00104 // [26] = TIMER_WAKE_WRAP
00105 // [25] = TIMER_WAKE_COMPB
00106 // [24] = TIMER_WAKE_COMPA
00107 // [23:0] = corresponding GPIO activity
00108 #define WAKEINFOVALID_INTERNAL_WAKE_EVENT_BIT 31
00109 #define SLEEPSKIPPED_INTERNAL_WAKE_EVENT_BIT  30
00110 #define CSYSPWRUPREQ_INTERNAL_WAKE_EVENT_BIT  29
00111 #define CDBGPWRUPREQ_INTERNAL_WAKE_EVENT_BIT  28
00112 #define WAKE_CORE_INTERNAL_WAKE_EVENT_BIT     27
00113 #define WRAP_INTERNAL_WAKE_EVENT_BIT          26
00114 #define CMPB_INTERNAL_WAKE_EVENT_BIT          25
00115 #define CMPA_INTERNAL_WAKE_EVENT_BIT          24
00116 //This define shifts events from the PWRUP_EVENT register into the proper
00117 //place in the halInternalWakeEvent variable
00118 #define INTERNAL_WAKE_EVENT_BIT_SHIFT         20
00119 
00120 static int32u halInternalWakeEvent=0;
00121 
00122 int32u halGetWakeInfo(void)
00123 {
00124   return halInternalWakeEvent;
00125 }
00126   
00127 void halInternalSleep(SleepModes sleepMode)
00128 {
00129   //Timer restoring always takes place during the wakeup sequence.  We save
00130   //the state here in case SLEEPMODE_NOTIMER is invoked, which would disable
00131   //the clocks.
00132   int32u SLEEPTMR_CLKEN_SAVED = SLEEPTMR_CLKEN;
00133   
00134   //This code assumes all wake source registers are properly configured.
00135   //As such, it should be called from halSleepWithOptions() or from
00136   // halSleepForQsWithOptions() which configues the wake sources.
00137   
00138   //The parameter gpioWakeSel is a bitfield composite of the GPIO wake
00139   //sources derived from the 3 ports, indicating which of the 24 GPIO
00140   //are configured as a wake source.
00141   int32u gpioWakeSel  = (GPIO_PAWAKE<<0);
00142          gpioWakeSel |= (GPIO_PBWAKE<<8);
00143          gpioWakeSel |= (GPIO_PCWAKE<<16);
00144   
00145   //PB2 is also WAKE_SC1.  Set this wake source if PB2's GPIO wake is set.
00146   if(GPIO_PBWAKE & PB2) {
00147     WAKE_SEL |= WAKE_SC1;
00148   }
00149   
00150   //PA2 is also WAKE_SC2.  Set this wake source if PA2's GPIO wake is set.
00151   if(GPIO_PAWAKE & PA2) {
00152     WAKE_SEL |= WAKE_SC2;
00153   }
00154   
00155   //The WAKE_IRQD source can come from any pin based on IRQD's sel register.
00156   if(gpioWakeSel & BIT(GPIO_IRQDSEL)) {
00157     WAKE_SEL |= WAKE_IRQD;
00158   }
00159   
00160   halInternalWakeEvent = 0; //clear old wake events
00161   
00162   switch(sleepMode)
00163   {
00164     case SLEEPMODE_NOTIMER:
00165       //The sleep timer clock sources (both RC and XTAL) are turned off.
00166       //Wakeup is possible from only GPIO.  System time is lost.
00167       //NOTE: Timer restoring always takes place during the wakeup sequence.
00168       SLEEPTMR_CLKEN = 0;
00169       goto deepSleepCore;
00170     
00171     case SLEEPMODE_WAKETIMER:
00172       //The sleep timer clock sources remain running.  The RC is always
00173       //running and the 32kHz XTAL depends on the board header.  Wakeup
00174       //is possible from both GPIO and the sleep timer.  System time
00175       //is maintained.  The sleep timer is assumed to be configured
00176       //properly for wake events.
00177       //NOTE: This mode assumes the caller has configured the *entire*
00178       //      sleep timer properly.
00179       
00180       if(INT_SLEEPTMRCFG&INT_SLEEPTMRWRAP) {
00181         WAKE_SEL |= WAKE_SLEEPTMRWRAP;
00182       }
00183       if(INT_SLEEPTMRCFG&INT_SLEEPTMRCMPB) {
00184         WAKE_SEL |= WAKE_SLEEPTMRCMPB;
00185       }
00186       if(INT_SLEEPTMRCFG&INT_SLEEPTMRCMPA) {
00187         WAKE_SEL |= WAKE_SLEEPTMRCMPA;
00188       }
00189       //fall into SLEEPMODE_MAINTAINTIMER's sleep code:
00190       
00191     case SLEEPMODE_MAINTAINTIMER:
00192       //The sleep timer clock sources remain running.  The RC is always
00193       //running and the 32kHz XTAL depends on the board header.  Wakeup
00194       //is possible from only GPIO.  System time is maintained.
00195       //NOTE: System time is maintained without any sleep timer interrupts
00196       //      because the hardware sleep timer counter is large enough
00197       //      to hold the entire count value and not need a RAM counter.
00198       
00199     ////////////////////////////////////////////////////////////////////////////
00200     // Core deep sleep code
00201     ////////////////////////////////////////////////////////////////////////////
00202 deepSleepCore:
00203       // Interrupts *must* be/stay disabled for DEEP SLEEP operation
00204       // INTERRUPTS_OFF will use BASEPRI to disable all interrupts except
00205       // fault handlers and PendSV.
00206       INTERRUPTS_OFF();
00207       // This is the point of no return.  From here on out, only the interrupt
00208       // sources available in WAKE_SEL will be captured and propagated across
00209       // deep sleep.
00210       //stick all our saved info onto stack since it's only temporary
00211       {
00212         boolean restoreWatchdog = halInternalWatchDogEnabled();
00213         boolean skipSleep = FALSE;
00214         
00215         // Only three register blocks keep power across deep sleep:
00216         //  CM_HV, GPIO, SLOW_TIMERS
00217         //
00218         // All other register blocks lose their state across deep sleep:
00219         //  BASEBAND, MAC, SECURITY, SERIAL, TMR1, TMR2, EVENT, CM_LV, RAM_CTRL,
00220         //  AUX_ADC, CAL_ADC, FLASH_CONTROL, ITM, DWT, FPB, NVIC, TPIU
00221         //
00222         // The sleep code will only save and restore registers where it is
00223         // meaningful and necessary to do so.  In most cases, there must still
00224         // be a powerup function to restore proper state.
00225         //
00226         // NOTE: halPowerUp() and halPowerDown() will always be called before
00227         // and after this function.  halPowerDown and halPowerUp should leave
00228         // the modules in a safe state and then restart the modules.
00229         // (For example, shutting down and restarting Timer1)
00230         //
00231         //----BASEBAND
00232         //        reinitialized by stStackPowerUp()
00233         //----MAC
00234         //        reinitialized by stStackPowerUp()
00235         //----SECURITY
00236         //        reinitialized by stStackPowerUp()
00237         //----SERIAL
00238         //        reinitialized by halPowerUp() or similar
00239         //----TMR1
00240         //        reinitialized by halPowerUp() or similar
00241         //----TMR2
00242         //        reinitialized by halPowerUp() or similar
00243         //----EVENT
00244         //SRC or FLAG interrupts are not saved or restored
00245         //MISS interrupts are not saved or restored
00246         //MAC_RX_INT_MASK - reinitialized by stStackPowerUp()
00247         //MAC_TX_INT_MASK - reinitialized by stStackPowerUp()
00248         //MAC_TIMER_INT_MASK - reinitialized by stStackPowerUp()
00249         //BB_INT_MASK - reinitialized by stStackPowerUp()
00250         //SEC_INT_MASK - reinitialized by stStackPowerUp()
00251         int32u INT_SLEEPTMRCFG_SAVED = INT_SLEEPTMRCFG_REG;
00252         int32u INT_MGMTCFG_SAVED = INT_MGMTCFG_REG;
00253         //INT_TIM1CFG - reinitialized by halPowerUp() or similar
00254         //INT_TIM2CFG - reinitialized by halPowerUp() or similar
00255         //INT_SC1CFG - reinitialized by halPowerUp() or similar
00256         //INT_SC2CFG - reinitialized by halPowerUp() or similar
00257         //INT_ADCCFG - reinitialized by halPowerUp() or similar
00258         int32u GPIO_INTCFGA_SAVED = GPIO_INTCFGA_REG;
00259         int32u GPIO_INTCFGB_SAVED = GPIO_INTCFGB_REG;
00260         int32u GPIO_INTCFGC_SAVED = GPIO_INTCFGC_REG;
00261         int32u GPIO_INTCFGD_SAVED = GPIO_INTCFGD_REG;
00262         //SC1_INTMODE - reinitialized by halPowerUp() or similar
00263         //SC2_INTMODE - reinitialized by halPowerUp() or similar
00264         //----CM_LV
00265         int32u OSC24M_BIASTRIM_SAVED = OSC24M_BIASTRIM_REG;
00266         int32u OSCHF_TUNE_SAVED = OSCHF_TUNE_REG;
00267         int32u DITHER_DIS_SAVED = DITHER_DIS_REG;
00268         //OSC24M_CTRL - reinitialized by halPowerUp() or similar
00269         //CPU_CLKSEL  - reinitialized by halPowerUp() or similar
00270         //TMR1_CLK_SEL - reinitialized by halPowerUp() or similar
00271         //TMR2_CLK_SEL - reinitialized by halPowerUp() or similar
00272         int32u PCTRACE_SEL_SAVED = PCTRACE_SEL_REG;
00273         //----RAM_CTRL
00274         int32u MEM_PROT_0_SAVED = MEM_PROT_0_REG;
00275         int32u MEM_PROT_1_SAVED = MEM_PROT_1_REG;
00276         int32u MEM_PROT_2_SAVED = MEM_PROT_2_REG;
00277         int32u MEM_PROT_3_SAVED = MEM_PROT_3_REG;
00278         int32u MEM_PROT_4_SAVED = MEM_PROT_4_REG;
00279         int32u MEM_PROT_5_SAVED = MEM_PROT_5_REG;
00280         int32u MEM_PROT_6_SAVED = MEM_PROT_6_REG;
00281         int32u MEM_PROT_7_SAVED = MEM_PROT_7_REG;
00282         int32u MEM_PROT_EN_SAVED = MEM_PROT_EN_REG;
00283         //----AUX_ADC
00284         //        reinitialized by halPowerUp() or similar
00285         //----CAL_ADC
00286         //        reinitialized by stStackPowerUp()
00287         //----FLASH_CONTROL
00288         //        configured on the fly by the flash library
00289         //----ITM
00290         //        reinitialized by halPowerUp() or similar
00291         //----DWT
00292         //        not used by software on chip
00293         //----FPB
00294         //        not used by software on chip
00295         //----NVIC
00296         //ST_CSR - fixed, restored by cstartup when exiting deep sleep
00297         //ST_RVR - fixed, restored by cstartup when exiting deep sleep
00298         int32u INT_CFGSET_SAVED = INT_CFGSET_REG; //mask against wake sources
00299         //INT_PENDSET - used below when overlapping interrupts and wake sources
00300         //NVIC_IPR_3to0 - fixed, restored by cstartup when exiting deep sleep
00301         //NVIC_IPR_7to4 - fixed, restored by cstartup when exiting deep sleep
00302         //NVIC_IPR_11to8 - fixed, restored by cstartup when exiting deep sleep
00303         //NVIC_IPR_15to12 - fixed, restored by cstartup when exiting deep sleep
00304         //NVIC_IPR_19to16 - fixed, restored by cstartup when exiting deep sleep
00305         int32u SCS_VTOR_SAVED = SCS_VTOR_REG;
00306         //SCS_CCR - fixed, restored by cstartup when exiting deep sleep
00307         //SCS_SHPR_7to4 - fixed, restored by cstartup when exiting deep sleep
00308         //SCS_SHPR_11to8 - fixed, restored by cstartup when exiting deep sleep
00309         //SCS_SHPR_15to12 - fixed, restored by cstartup when exiting deep sleep
00310         //SCS_SHCSR - fixed, restored by cstartup when exiting deep sleep
00311         //----TPIU
00312         //        reinitialized by halPowerUp() or similar
00313         
00314         //stmDebugPowerDown() should have shutdown the DWT/ITM/TPIU already.
00315         
00316         //freeze input to the GPIO from LV (alternate output functions freeze)
00317         EVENT_CTRL = LV_FREEZE;
00318         //record GPIO state for wake monitoring purposes
00319         //By having a snapshot of GPIO state, we can figure out after waking
00320         //up exactly which GPIO could have woken us up.
00321         //Reading the three IN registers is done separately to avoid warnings
00322         //about undefined order of volatile access.
00323         int32u GPIO_IN_SAVED =   GPIO_PAIN;
00324                GPIO_IN_SAVED |= (GPIO_PBIN<<8);
00325                GPIO_IN_SAVED |= (GPIO_PCIN<<16);
00326         //reset the power up events by writing 1 to all bits.
00327         PWRUP_EVENT = 0xFFFFFFFF;
00328 
00329 
00330 
00331         //By clearing the events, the wake up event capturing is activated.
00332         //At this point we can safely check our interrupt flags since event
00333         //capturing is now overlapped.  Up to now, interrupts indicate
00334         //activity, after this point, powerup events indicate activity.
00335         //If any of the interrupt flags are set, that means we saw a wake event
00336         //sometime while entering sleep, so we need to skip over sleeping
00337         //
00338         //--possible interrupt sources for waking:
00339         //  IRQA, IRQB, IRQC, IRQD
00340         //  SleepTMR CMPA, CMPB, Wrap
00341         //  WAKE_CORE (DebugIsr)
00342         //
00343         //check for IRQA interrupt and if IRQA (PB0) is wake source
00344         if((INT_PENDSET&INT_IRQA) &&
00345            (GPIO_PBWAKE&PB0) &&
00346            (WAKE_SEL&GPIO_WAKE)) {
00347           skipSleep = TRUE;
00348           //log IRQA as a wake event
00349           halInternalWakeEvent |= BIT(PORTB_PIN(0));
00350 
00351 
00352 
00353         }
00354         //check for IRQB interrupt and if IRQB (PB6) is wake source
00355         if((INT_PENDSET&INT_IRQB) &&
00356            (GPIO_PBWAKE&PB6) &&
00357            (WAKE_SEL&GPIO_WAKE)) {
00358           skipSleep = TRUE;
00359           //log IRQB as a wake event
00360           halInternalWakeEvent |= BIT(PORTB_PIN(6));
00361 
00362 
00363 
00364         }
00365         //check for IRQC interrupt and if IRQC (GPIO_IRQCSEL) is wake source
00366         if((INT_PENDSET&INT_IRQC) &&
00367            (gpioWakeSel&BIT(GPIO_IRQCSEL)) &&
00368            (WAKE_SEL&GPIO_WAKE)) {
00369           skipSleep = TRUE;
00370           //log IRQC as a wake event
00371           halInternalWakeEvent |= BIT(GPIO_IRQCSEL);
00372 
00373 
00374 
00375         }
00376         //check for IRQD interrupt and if IRQD (GPIO_IRQDSEL) is wake source
00377         if((INT_PENDSET&INT_IRQD) &&
00378            (gpioWakeSel&BIT(GPIO_IRQDSEL)) &&
00379            ((WAKE_SEL&GPIO_WAKE) ||
00380             (WAKE_SEL&WAKE_IRQD))) {
00381           skipSleep = TRUE;
00382           //log IRQD as a wake event
00383           halInternalWakeEvent |= BIT(GPIO_IRQDSEL);
00384 
00385 
00386 
00387         }
00388         //check for SleepTMR CMPA interrupt and if SleepTMR CMPA is wake source
00389         if((INT_SLEEPTMR&INT_SLEEPTMRCMPA) && (WAKE_SEL&WAKE_SLEEPTMRCMPA)) {
00390           skipSleep = TRUE;
00391           //log SleepTMR CMPA as a wake event
00392           halInternalWakeEvent |= BIT32(CMPA_INTERNAL_WAKE_EVENT_BIT);
00393 
00394 
00395 
00396         }
00397         //check for SleepTMR CMPB interrupt and if SleepTMR CMPB is wake source
00398         if((INT_SLEEPTMR&INT_SLEEPTMRCMPB) && (WAKE_SEL&WAKE_SLEEPTMRCMPB)) {
00399           skipSleep = TRUE;
00400           //log SleepTMR CMPB as a wake event
00401           halInternalWakeEvent |= BIT32(CMPB_INTERNAL_WAKE_EVENT_BIT);
00402 
00403 
00404 
00405         }
00406         //check for SleepTMR WRAP interrupt and if SleepTMR WRAP is wake source
00407         if((INT_SLEEPTMR&INT_SLEEPTMRWRAP) && (WAKE_SEL&WAKE_SLEEPTMRWRAP)) {
00408           skipSleep = TRUE;
00409           //log SleepTMR WRAP as a wake event
00410           halInternalWakeEvent |= BIT32(WRAP_INTERNAL_WAKE_EVENT_BIT);
00411 
00412 
00413 
00414         }
00415         //check for Debug interrupt and if WAKE_CORE is wake source
00416         if((INT_PENDSET&INT_DEBUG) && (WAKE_SEL&WAKE_WAKE_CORE)) {
00417           skipSleep = TRUE;
00418           //log WAKE_CORE as a wake event
00419           halInternalWakeEvent |= BIT32(WAKE_CORE_INTERNAL_WAKE_EVENT_BIT);
00420 
00421 
00422 
00423         }
00424 
00425         //only propagate across deep sleep the interrupts that are both
00426         //enabled and possible wake sources
00427         {
00428           int32u wakeSourceInterruptMask = 0;
00429           
00430           if(GPIO_PBWAKE&PB0) {
00431             wakeSourceInterruptMask |= INT_IRQA;
00432 
00433 
00434 
00435           }
00436           if(GPIO_PBWAKE&PB6) {
00437             wakeSourceInterruptMask |= INT_IRQB;
00438 
00439 
00440 
00441           }
00442           if(gpioWakeSel&BIT(GPIO_IRQCSEL)) {
00443             wakeSourceInterruptMask |= INT_IRQC;
00444 
00445 
00446 
00447           }
00448           if(gpioWakeSel&BIT(GPIO_IRQDSEL)) {
00449             wakeSourceInterruptMask |= INT_IRQD;
00450 
00451 
00452 
00453           }
00454           if( (WAKE_SEL&WAKE_SLEEPTMRCMPA) ||
00455               (WAKE_SEL&WAKE_SLEEPTMRCMPB) ||
00456               (WAKE_SEL&WAKE_SLEEPTMRWRAP) ) {
00457             wakeSourceInterruptMask |= INT_SLEEPTMR;
00458 
00459 
00460 
00461           }
00462           if(WAKE_SEL&WAKE_WAKE_CORE) {
00463             wakeSourceInterruptMask |= INT_DEBUG;
00464 
00465 
00466 
00467           }
00468           
00469           INT_CFGSET_SAVED &= wakeSourceInterruptMask;
00470         }
00471         
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486 
00487         
00488         //disable watchdog while sleeping (since we can't reset it asleep)
00489         halInternalDisableWatchDog(MICRO_DISABLE_WATCH_DOG_KEY);
00490         
00491         //The chip is not allowed to enter a deep sleep mode (which could
00492         //cause a core reset cycle) while CSYSPWRUPREQ is set.  CSYSPWRUPREQ
00493         //indicates that the debugger is trying to access sections of the
00494         //chip that would get reset during deep sleep.  Therefore, a reset
00495         //cycle could very easily cause the debugger to error and we don't
00496         //want that.  While the power management state machine will stall
00497         //if CSYSPWRUPREQ is set (to avoid the situation just described),
00498         //in this stalled state the chip will not be responsive to wake
00499         //events.  To be sensitive to wake events, we must handle them in
00500         //software instead.  To accomplish this, we request that the
00501         //CSYSPWRUPACK be inhibited (which will indicate the debugger is not
00502         //connected).  But, we cannot induce deep sleep until CSYSPWRUPREQ/ACK
00503         //go low and these are under the debuggers control, so we must stall
00504         //and wait here.  If there is a wake event during this time, break
00505         //out and wake like normal.  If the ACK eventually clears,
00506         //we can proceed into deep sleep.  The CSYSPWRUPACK_INHIBIT
00507         //functionality will hold off the debugger (by holding off the ACK)
00508         //until we are safely past and out of deep sleep.  The power management
00509         //state machine then becomes responsible for clearing
00510         //CSYSPWRUPACK_INHIBIT and responding to a CSYSPWRUPREQ with a
00511         //CSYSPWRUPACK at the right/safe time.
00512         CSYSPWRUPACK_INHIBIT = CSYSPWRUPACK_INHIBIT_CSYSPWRUPACK_INHIBIT;
00513         {
00514           //Use a local copy of WAKE_SEL to avoid warnings from the compiler
00515           //about order of volatile accesses
00516           int32u wakeSel = WAKE_SEL;
00517           //stall until a wake event or CSYSPWRUPREQ/ACK clears
00518           while( (CSYSPWRUPACK_STATUS) && (!(PWRUP_EVENT&wakeSel)) ) {}
00519           //if there was a wake event, allow CSYSPWRUPACK and skip sleep
00520           if(PWRUP_EVENT&wakeSel) {
00521             CSYSPWRUPACK_INHIBIT = CSYSPWRUPACK_INHIBIT_RESET;
00522             skipSleep = TRUE;
00523           }
00524         }
00525         
00526         
00527 
00528 
00529 
00530         if(!skipSleep) {
00531 
00532 
00533 
00534           //FogBugz 7283 states that we must switch to the OSCHF when entering
00535           //deep sleep since using the 24MHz XTAL could result in RAM
00536           //corruption.  This switch must occur at least 2*24MHz cycles before
00537           //sleeping.
00538           //FogBugz 8858 states that we cannot go into deep-sleep when the
00539           //chip is clocked with the 24MHz XTAL with a duty cycle as low as
00540           //70/30 since this causes power_down generation timing to fail.
00541           OSC24M_CTRL &= ~OSC24M_CTRL_OSC24M_SEL;
00542           //If DS12 needs to be forced regardless of state, clear
00543           //REGEN_DSLEEP here.  This is hugely dangerous and
00544           //should only be done in very controlled chip tests.
00545           SCS_SCR |= SCS_SCR_SLEEPDEEP;      //enable deep sleep
00546           extern volatile boolean halPendSvSaveContext;
00547           halPendSvSaveContext = 1;          //1 means save context
00548           //The INTERRUPTS_OFF used at the beginning of this function set
00549           //BASEPRI such that the only interrupts that will fire are faults
00550           //and PendSV.  Trigger PendSV now to induce a context save.
00551           SCS_ICSR |= SCS_ICSR_PENDSVSET;    //pend the context save and Dsleep
00552           //Since the interrupt will not fire immediately it is possible to
00553           //execute a few lines of code.  To stay halted in this spot until the
00554           //WFI instruction, spin on the context flag (which will get cleared
00555           //during the startup sequence when restoring context).
00556           while(halPendSvSaveContext) {}
00557           //I AM ASLEEP.  WHEN EXECUTION RESUMES, CSTARTUP WILL RESTORE TO HERE
00558         } else {
00559           //Record the fact that we skipped sleep
00560           halInternalWakeEvent |= BIT32(SLEEPSKIPPED_INTERNAL_WAKE_EVENT_BIT);
00561           //If this was a true deep sleep, we would have executed cstartup and
00562           //PRIMASK would be set right now.  If we skipped sleep, PRIMASK is not
00563           //set so we explicitely set it to guarantee the powerup sequence
00564           //works cleanly and consistently with respect to interrupt
00565           //dispatching and enabling.
00566           _setPriMask();
00567         }
00568 
00569 
00570 
00571         
00572 
00573 
00574 
00575         
00576         //Clear the interrupt flags for all wake sources.  This
00577         //is necessary because if we don't execute an actual deep sleep cycle
00578         //the interrupt flags will never be cleared.  By clearing the flags,
00579         //we always mimick a real deep sleep as closely as possible and
00580         //guard against any accidental interrupt triggering coming out
00581         //of deep sleep.  (The interrupt dispatch code coming out of sleep
00582         //is responsible for translating wake events into interrupt events,
00583         //and if we don't clear interrupt flags here it's possible for an
00584         //interrupt to trigger even if it wasn't the true wake event.)
00585         INT_SLEEPTMRFLAG = (INT_SLEEPTMRCMPA |
00586                             INT_SLEEPTMRCMPB |
00587                             INT_SLEEPTMRWRAP);
00588         INT_GPIOFLAG = (INT_IRQAFLAG |
00589                         INT_IRQBFLAG |
00590                         INT_IRQCFLAG |
00591                         INT_IRQDFLAG);
00592         
00593         //immediately restore the registers we saved before sleeping
00594         //so IRQ and SleepTMR capture can be reenabled as quickly as possible
00595         //this is safe because our global interrupts are still disabled
00596         //other registers will be restored later
00597 
00598 
00599 
00600 
00601 
00602 
00603 
00604         SLEEPTMR_CLKEN_REG = SLEEPTMR_CLKEN_SAVED;
00605         INT_SLEEPTMRCFG_REG = INT_SLEEPTMRCFG_SAVED;
00606         INT_MGMTCFG_REG = INT_MGMTCFG_SAVED;
00607         GPIO_INTCFGA_REG = GPIO_INTCFGA_SAVED;
00608         GPIO_INTCFGB_REG = GPIO_INTCFGB_SAVED;
00609         GPIO_INTCFGC_REG = GPIO_INTCFGC_SAVED;
00610         GPIO_INTCFGD_REG = GPIO_INTCFGD_SAVED;
00611         OSC24M_BIASTRIM_REG = OSC24M_BIASTRIM_SAVED;
00612         OSCHF_TUNE_REG = OSCHF_TUNE_SAVED;
00613         DITHER_DIS_REG = DITHER_DIS_SAVED;
00614         PCTRACE_SEL_REG = PCTRACE_SEL_SAVED;
00615         MEM_PROT_0_REG = MEM_PROT_0_SAVED;
00616         MEM_PROT_1_REG = MEM_PROT_1_SAVED;
00617         MEM_PROT_2_REG = MEM_PROT_2_SAVED;
00618         MEM_PROT_3_REG = MEM_PROT_3_SAVED;
00619         MEM_PROT_4_REG = MEM_PROT_4_SAVED;
00620         MEM_PROT_5_REG = MEM_PROT_5_SAVED;
00621         MEM_PROT_6_REG = MEM_PROT_6_SAVED;
00622         MEM_PROT_7_REG = MEM_PROT_7_SAVED;
00623         MEM_PROT_EN_REG = MEM_PROT_EN_SAVED;
00624         INT_CFGSET_REG = INT_CFGSET_SAVED;
00625         SCS_VTOR_REG = SCS_VTOR_SAVED;
00626         
00627         //WAKE_CORE/INT_DEBUG and INT_IRQx is cleared by INT_PENDCLR below
00628         INT_PENDCLR = 0xFFFFFFFF;
00629         
00630         //Now that we're awake, normal interrupts are operational again
00631         //Take a snapshot of the new GPIO state and the EVENT register to
00632         //record our wake event
00633         int32u GPIO_IN_NEW =   GPIO_PAIN;
00634                GPIO_IN_NEW |= (GPIO_PBIN<<8);
00635                GPIO_IN_NEW |= (GPIO_PCIN<<16);
00636         //Only operate on power up events that are also wake events.  Power
00637         //up events will always trigger like an interrupt flag, so we have
00638         //to check them against events that are enabled for waking. (This is
00639         //a two step process because we're accessing two volatile values.)
00640         int32u powerUpEvents = PWRUP_EVENT;
00641                powerUpEvents &= WAKE_SEL;
00642         halInternalWakeEvent |= ((GPIO_IN_SAVED^GPIO_IN_NEW)&gpioWakeSel);
00643         //PWRUP_SC1 is PB2 which is bit 10
00644         halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_SC1))<<((1*8)+2);
00645         //PWRUP_SC2 is PA2 which is bit 2
00646         halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_SC2))<<((0*8)+2);
00647         //PWRUP_IRQD is chosen by GPIO_IRQDSEL
00648         halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_IRQD))<<(GPIO_IRQDSEL);
00649         halInternalWakeEvent |= ((powerUpEvents & 
00650                                   (PWRUP_CSYSPWRUPREQ_MASK  |
00651                                    PWRUP_CDBGPWRUPREQ_MASK  |
00652                                    PWRUP_WAKECORE_MASK      |
00653                                    PWRUP_SLEEPTMRWRAP_MASK  |
00654                                    PWRUP_SLEEPTMRCOMPB_MASK |
00655                                    PWRUP_SLEEPTMRCOMPA_MASK ))
00656                                           <<INTERNAL_WAKE_EVENT_BIT_SHIFT);
00657         //at this point wake events are fully captured and interrupts have
00658         //taken over handling all new events
00659         
00660 
00661 
00662 
00663 
00664         
00665         //Bring limited interrupts back online.  INTERRUPTS_OFF will use
00666         //BASEPRI to disable all interrupts except fault handlers and PendSV.
00667         //PRIMASK is still set though (global interrupt disable) so we need
00668         //to clear that next.
00669         INTERRUPTS_OFF();
00670         
00671 
00672 
00673 
00674         
00675         //Now that BASEPRI has taken control of interrupt enable/disable,
00676         //we can clear PRIMASK to reenable global interrupt operation.
00677         _clearPriMask();
00678         
00679 
00680 
00681 
00682         
00683         //wake events are saved and interrupts are back on track,
00684         //disable gpio freeze
00685         EVENT_CTRL = EVENT_CTRL_RESET;
00686         
00687         //restart watchdog if it was running when we entered sleep
00688         //do this before dispatching interrupts while we still have tight
00689         //control of code execution
00690         if(restoreWatchdog) {
00691           halInternalEnableWatchDog();
00692         }
00693         
00694 
00695 
00696 
00697         
00698         //Pend any interrupts associated with deep sleep wake sources.  The
00699         //restoration of INT_CFGSET above and the changing of BASEPRI below
00700         //is responsible for proper dispatching of interrupts at the end of
00701         //halSleepWithOptions.
00702         //
00703         //
00704         //The WAKE_CORE wake source triggers a Debug Interrupt.  If INT_DEBUG
00705         //interrupt is enabled and WAKE_CORE is a wake event, then pend the
00706         //Debug interrupt (using the wake_core bit).
00707         if( (INT_CFGSET&INT_DEBUG) &&
00708             (halInternalWakeEvent&BIT(WAKE_CORE_INTERNAL_WAKE_EVENT_BIT)) ) {
00709           WAKE_CORE = WAKE_CORE_FIELD;
00710 
00711 
00712 
00713         }
00714         //
00715         //
00716         //The SleepTMR CMPA is linked to a real ISR.  If the SleepTMR CMPA
00717         //interrupt is enabled and CMPA is a wake event, then pend the CMPA
00718         //interrupt (force the second level interrupt).
00719         if( (INT_SLEEPTMRCFG&INT_SLEEPTMRCMPA) &&
00720             (halInternalWakeEvent&BIT(CMPA_INTERNAL_WAKE_EVENT_BIT)) ) {
00721           INT_SLEEPTMRFORCE = INT_SLEEPTMRCMPA;
00722 
00723 
00724 
00725         }
00726         //
00727         //The SleepTMR CMPB is linked to a real ISR.  If the SleepTMR CMPB
00728         //interrupt is enabled and CMPB is a wake event, then pend the CMPB
00729         //interrupt (force the second level interrupt).
00730         if( (INT_SLEEPTMRCFG&INT_SLEEPTMRCMPB) &&
00731             (halInternalWakeEvent&BIT(CMPB_INTERNAL_WAKE_EVENT_BIT)) ) {
00732           INT_SLEEPTMRFORCE = INT_SLEEPTMRCMPB;
00733 
00734 
00735 
00736         }
00737         //
00738         //The SleepTMR WRAP is linked to a real ISR.  If the SleepTMR WRAP
00739         //interrupt is enabled and WRAP is a wake event, then pend the WRAP
00740         //interrupt (force the second level interrupt).
00741         if( (INT_SLEEPTMRCFG&INT_SLEEPTMRWRAP) &&
00742             (halInternalWakeEvent&BIT(WRAP_INTERNAL_WAKE_EVENT_BIT)) ) {
00743           INT_SLEEPTMRFORCE = INT_SLEEPTMRWRAP;
00744 
00745 
00746 
00747         }
00748         //
00749         //
00750         //The four IRQs are linked to a real ISR.  If any of the four IRQs
00751         //triggered, then pend their ISR
00752         //
00753         //If the IRQA interrupt mode is enabled and IRQA (PB0) is wake
00754         //event, then pend the interrupt.
00755         if( ((GPIO_INTCFGA&GPIO_INTMOD)!=0) &&
00756             (halInternalWakeEvent&BIT(PORTB_PIN(0))) ) {
00757           INT_PENDSET = INT_IRQA;
00758 
00759 
00760 
00761         }
00762         //If the IRQB interrupt mode is enabled and IRQB (PB6) is wake
00763         //event, then pend the interrupt.
00764         if( ((GPIO_INTCFGB&GPIO_INTMOD)!=0) &&
00765             (halInternalWakeEvent&BIT(PORTB_PIN(6))) ) {
00766           INT_PENDSET = INT_IRQB;
00767 
00768 
00769 
00770         }
00771         //If the IRQC interrupt mode is enabled and IRQC (GPIO_IRQCSEL) is wake
00772         //event, then pend the interrupt.
00773         if( ((GPIO_INTCFGC&GPIO_INTMOD)!=0) &&
00774             (halInternalWakeEvent&BIT(GPIO_IRQCSEL)) ) {
00775           INT_PENDSET = INT_IRQC;
00776 
00777 
00778 
00779         }
00780         //If the IRQD interrupt mode is enabled and IRQD (GPIO_IRQDSEL) is wake
00781         //event, then pend the interrupt.
00782         if( ((GPIO_INTCFGD&GPIO_INTMOD)!=0) &&
00783             (halInternalWakeEvent&BIT(GPIO_IRQDSEL)) ) {
00784           INT_PENDSET = INT_IRQD;
00785 
00786 
00787 
00788         }
00789       }
00790       
00791 
00792 
00793 
00794 
00795       
00796       //Mark the wake events valid just before exiting
00797       halInternalWakeEvent |= BIT32(WAKEINFOVALID_INTERNAL_WAKE_EVENT_BIT);
00798       
00799       //We are now reconfigured, appropriate ISRs are pended, and ready to go,
00800       //so enable interrupts!
00801       INTERRUPTS_ON();
00802       
00803 
00804 
00805 
00806       
00807       break; //and deep sleeping is done!
00808     
00809     case SLEEPMODE_IDLE:
00810       //Only the CPU is idled.  The rest of the chip continues runing
00811       //normally.  The chip will wake from any interrupt.
00812       {
00813         boolean restoreWatchdog = halInternalWatchDogEnabled();
00814         //disable watchdog while sleeping (since we can't reset it asleep)
00815         halInternalDisableWatchDog(MICRO_DISABLE_WATCH_DOG_KEY);
00816         //Normal ATOMIC/INTERRUPTS_OFF/INTERRUPTS_ON uses the BASEPRI mask
00817         //to juggle priority levels so that the fault handlers can always
00818         //be serviced.  But, the WFI instruction is only capable of
00819         //working with the PRIMASK bit.  Therefore, we have to switch from
00820         //using BASEPRI to PRIMASK to keep interrupts disabled so that the
00821         //WFI can return on an interrupt
00822         //Globally disable interrupts with PRIMASK
00823         _setPriMask();
00824         //Bring the BASEPRI up to 0 to allow interrupts (but still disabled
00825         //with PRIMASK)
00826         INTERRUPTS_ON();
00827         //an internal function call is made here instead of injecting the
00828         //"WFI" assembly instruction because injecting assembly code will
00829         //cause the compiler's optimizer to reduce efficiency.
00830         halInternalIdleSleep();
00831         //The WFI instruction does not actually clear the PRIMASK bit, it
00832         //only allows the PRIMASK bit to be bypassed.  Therefore, we must
00833         //manually clear PRIMASK to reenable all interrupts.
00834         _clearPriMask();
00835         //restart watchdog if it was running when we entered sleep
00836         if(restoreWatchdog)
00837           halInternalEnableWatchDog();
00838       }
00839       break;
00840       
00841     default:
00842       //Oops!  Invalid sleepMode parameter.
00843       assert(0);
00844   }
00845 }
00846 
00847 
00848 void halSleepWithOptions(SleepModes sleepMode, int32u gpioWakeBitMask)
00849 {
00850   //configure all GPIO wake sources
00851   GPIO_PAWAKE = (gpioWakeBitMask>>0)&0xFF;
00852   GPIO_PBWAKE = (gpioWakeBitMask>>8)&0xFF;
00853   GPIO_PCWAKE = (gpioWakeBitMask>>16)&0xFF;
00854   
00855   //use the defines found in the board file to choose our wakeup source(s)
00856   WAKE_SEL = 0;  //start with no wake sources
00857   
00858   //if any of the GPIO wakeup monitor bits are set, enable the top level
00859   //GPIO wakeup monitor
00860   if((GPIO_PAWAKE)||(GPIO_PBWAKE)||(GPIO_PCWAKE)) {
00861     WAKE_SEL |= GPIO_WAKE;
00862   }
00863   //always wakeup when the debugger is connected
00864   WAKE_SEL |= WAKE_CDBGPWRUPREQ;
00865   //always wakeup when the debugger attempts to access the chip
00866   WAKE_SEL |= WAKE_CSYSPWRUPREQ;
00867   //always wakeup when the debug channel attempts to access the chip
00868   WAKE_SEL |= WAKE_WAKE_CORE;
00869   //the timer wakeup sources are enabled below in POWERSAVE, if needed
00870   
00871   //wake sources are configured so do the actual sleeping
00872   halInternalSleep(sleepMode);
00873 }