Contiki 3.x
sleep.c
Go to the documentation of this file.
1 /** @file hal/micro/cortexm3/sleep.c
2  *
3  * @brief STM32W108 micro specific sleep functions.
4  *
5  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved. -->
6  */
7 
8 #include PLATFORM_HEADER
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 //We don't have a real register to hold this composite information.
97 //Pretend we do so halGetWakeInfo can operate like halGetResetInfo.
98 //This "register" is only ever set by halInternalSleep.
99 // [31] = WakeInfoValid
100 // [30] = SleepSkipped
101 // [29] = CSYSPWRUPREQ
102 // [28] = CDBGPWRUPREQ
103 // [27] = WAKE_CORE
104 // [26] = TIMER_WAKE_WRAP
105 // [25] = TIMER_WAKE_COMPB
106 // [24] = TIMER_WAKE_COMPA
107 // [23:0] = corresponding GPIO activity
108 #define WAKEINFOVALID_INTERNAL_WAKE_EVENT_BIT 31
109 #define SLEEPSKIPPED_INTERNAL_WAKE_EVENT_BIT 30
110 #define CSYSPWRUPREQ_INTERNAL_WAKE_EVENT_BIT 29
111 #define CDBGPWRUPREQ_INTERNAL_WAKE_EVENT_BIT 28
112 #define WAKE_CORE_INTERNAL_WAKE_EVENT_BIT 27
113 #define WRAP_INTERNAL_WAKE_EVENT_BIT 26
114 #define CMPB_INTERNAL_WAKE_EVENT_BIT 25
115 #define CMPA_INTERNAL_WAKE_EVENT_BIT 24
116 //This define shifts events from the PWRUP_EVENT register into the proper
117 //place in the halInternalWakeEvent variable
118 #define INTERNAL_WAKE_EVENT_BIT_SHIFT 20
119 
120 static uint32_t halInternalWakeEvent=0;
121 
122 uint32_t halGetWakeInfo(void)
123 {
124  return halInternalWakeEvent;
125 }
126 
127 void halInternalSleep(SleepModes sleepMode)
128 {
129  //Timer restoring always takes place during the wakeup sequence. We save
130  //the state here in case SLEEPMODE_NOTIMER is invoked, which would disable
131  //the clocks.
132  uint32_t SLEEPTMR_CLKEN_SAVED = SLEEPTMR_CLKEN;
133 
134  //This code assumes all wake source registers are properly configured.
135  //As such, it should be called from halSleepWithOptions() or from
136  // halSleepForQsWithOptions() which configues the wake sources.
137 
138  //The parameter gpioWakeSel is a bitfield composite of the GPIO wake
139  //sources derived from the 3 ports, indicating which of the 24 GPIO
140  //are configured as a wake source.
141  uint32_t gpioWakeSel = (GPIO_PAWAKE<<0);
142  gpioWakeSel |= (GPIO_PBWAKE<<8);
143  gpioWakeSel |= (GPIO_PCWAKE<<16);
144 
145  //PB2 is also WAKE_SC1. Set this wake source if PB2's GPIO wake is set.
146  if(GPIO_PBWAKE & PB2) {
147  WAKE_SEL |= WAKE_SC1;
148  }
149 
150  //PA2 is also WAKE_SC2. Set this wake source if PA2's GPIO wake is set.
151  if(GPIO_PAWAKE & PA2) {
152  WAKE_SEL |= WAKE_SC2;
153  }
154 
155  //The WAKE_IRQD source can come from any pin based on IRQD's sel register.
156  if(gpioWakeSel & BIT(GPIO_IRQDSEL)) {
157  WAKE_SEL |= WAKE_IRQD;
158  }
159 
160  halInternalWakeEvent = 0; //clear old wake events
161 
162  switch(sleepMode)
163  {
164  case SLEEPMODE_NOTIMER:
165  //The sleep timer clock sources (both RC and XTAL) are turned off.
166  //Wakeup is possible from only GPIO. System time is lost.
167  //NOTE: Timer restoring always takes place during the wakeup sequence.
168  SLEEPTMR_CLKEN = 0;
169  goto deepSleepCore;
170 
171  case SLEEPMODE_WAKETIMER:
172  //The sleep timer clock sources remain running. The RC is always
173  //running and the 32kHz XTAL depends on the board header. Wakeup
174  //is possible from both GPIO and the sleep timer. System time
175  //is maintained. The sleep timer is assumed to be configured
176  //properly for wake events.
177  //NOTE: This mode assumes the caller has configured the *entire*
178  // sleep timer properly.
179 
180  if(INT_SLEEPTMRCFG&INT_SLEEPTMRWRAP) {
181  WAKE_SEL |= WAKE_SLEEPTMRWRAP;
182  }
183  if(INT_SLEEPTMRCFG&INT_SLEEPTMRCMPB) {
184  WAKE_SEL |= WAKE_SLEEPTMRCMPB;
185  }
186  if(INT_SLEEPTMRCFG&INT_SLEEPTMRCMPA) {
187  WAKE_SEL |= WAKE_SLEEPTMRCMPA;
188  }
189  //fall into SLEEPMODE_MAINTAINTIMER's sleep code:
190 
191  case SLEEPMODE_MAINTAINTIMER:
192  //The sleep timer clock sources remain running. The RC is always
193  //running and the 32kHz XTAL depends on the board header. Wakeup
194  //is possible from only GPIO. System time is maintained.
195  //NOTE: System time is maintained without any sleep timer interrupts
196  // because the hardware sleep timer counter is large enough
197  // to hold the entire count value and not need a RAM counter.
198 
199  ////////////////////////////////////////////////////////////////////////////
200  // Core deep sleep code
201  ////////////////////////////////////////////////////////////////////////////
202 deepSleepCore:
203  // Interrupts *must* be/stay disabled for DEEP SLEEP operation
204  // INTERRUPTS_OFF will use BASEPRI to disable all interrupts except
205  // fault handlers and PendSV.
206  INTERRUPTS_OFF();
207  // This is the point of no return. From here on out, only the interrupt
208  // sources available in WAKE_SEL will be captured and propagated across
209  // deep sleep.
210  //stick all our saved info onto stack since it's only temporary
211  {
212  boolean restoreWatchdog = halInternalWatchDogEnabled();
213  boolean skipSleep = FALSE;
214 
215  // Only three register blocks keep power across deep sleep:
216  // CM_HV, GPIO, SLOW_TIMERS
217  //
218  // All other register blocks lose their state across deep sleep:
219  // BASEBAND, MAC, SECURITY, SERIAL, TMR1, TMR2, EVENT, CM_LV, RAM_CTRL,
220  // AUX_ADC, CAL_ADC, FLASH_CONTROL, ITM, DWT, FPB, NVIC, TPIU
221  //
222  // The sleep code will only save and restore registers where it is
223  // meaningful and necessary to do so. In most cases, there must still
224  // be a powerup function to restore proper state.
225  //
226  // NOTE: halPowerUp() and halPowerDown() will always be called before
227  // and after this function. halPowerDown and halPowerUp should leave
228  // the modules in a safe state and then restart the modules.
229  // (For example, shutting down and restarting Timer1)
230  //
231  //----BASEBAND
232  // reinitialized by stStackPowerUp()
233  //----MAC
234  // reinitialized by stStackPowerUp()
235  //----SECURITY
236  // reinitialized by stStackPowerUp()
237  //----SERIAL
238  // reinitialized by halPowerUp() or similar
239  //----TMR1
240  // reinitialized by halPowerUp() or similar
241  //----TMR2
242  // reinitialized by halPowerUp() or similar
243  //----EVENT
244  //SRC or FLAG interrupts are not saved or restored
245  //MISS interrupts are not saved or restored
246  //MAC_RX_INT_MASK - reinitialized by stStackPowerUp()
247  //MAC_TX_INT_MASK - reinitialized by stStackPowerUp()
248  //MAC_TIMER_INT_MASK - reinitialized by stStackPowerUp()
249  //BB_INT_MASK - reinitialized by stStackPowerUp()
250  //SEC_INT_MASK - reinitialized by stStackPowerUp()
251  uint32_t INT_SLEEPTMRCFG_SAVED = INT_SLEEPTMRCFG_REG;
252  uint32_t INT_MGMTCFG_SAVED = INT_MGMTCFG_REG;
253  //INT_TIM1CFG - reinitialized by halPowerUp() or similar
254  //INT_TIM2CFG - reinitialized by halPowerUp() or similar
255  //INT_SC1CFG - reinitialized by halPowerUp() or similar
256  //INT_SC2CFG - reinitialized by halPowerUp() or similar
257  //INT_ADCCFG - reinitialized by halPowerUp() or similar
258  uint32_t GPIO_INTCFGA_SAVED = GPIO_INTCFGA_REG;
259  uint32_t GPIO_INTCFGB_SAVED = GPIO_INTCFGB_REG;
260  uint32_t GPIO_INTCFGC_SAVED = GPIO_INTCFGC_REG;
261  uint32_t GPIO_INTCFGD_SAVED = GPIO_INTCFGD_REG;
262  //SC1_INTMODE - reinitialized by halPowerUp() or similar
263  //SC2_INTMODE - reinitialized by halPowerUp() or similar
264  //----CM_LV
265  uint32_t OSC24M_BIASTRIM_SAVED = OSC24M_BIASTRIM_REG;
266  uint32_t OSCHF_TUNE_SAVED = OSCHF_TUNE_REG;
267  uint32_t DITHER_DIS_SAVED = DITHER_DIS_REG;
268  //OSC24M_CTRL - reinitialized by halPowerUp() or similar
269  //CPU_CLKSEL - reinitialized by halPowerUp() or similar
270  //TMR1_CLK_SEL - reinitialized by halPowerUp() or similar
271  //TMR2_CLK_SEL - reinitialized by halPowerUp() or similar
272  uint32_t PCTRACE_SEL_SAVED = PCTRACE_SEL_REG;
273  //----RAM_CTRL
274  uint32_t MEM_PROT_0_SAVED = MEM_PROT_0_REG;
275  uint32_t MEM_PROT_1_SAVED = MEM_PROT_1_REG;
276  uint32_t MEM_PROT_2_SAVED = MEM_PROT_2_REG;
277  uint32_t MEM_PROT_3_SAVED = MEM_PROT_3_REG;
278  uint32_t MEM_PROT_4_SAVED = MEM_PROT_4_REG;
279  uint32_t MEM_PROT_5_SAVED = MEM_PROT_5_REG;
280  uint32_t MEM_PROT_6_SAVED = MEM_PROT_6_REG;
281  uint32_t MEM_PROT_7_SAVED = MEM_PROT_7_REG;
282  uint32_t MEM_PROT_EN_SAVED = MEM_PROT_EN_REG;
283  //----AUX_ADC
284  // reinitialized by halPowerUp() or similar
285  //----CAL_ADC
286  // reinitialized by stStackPowerUp()
287  //----FLASH_CONTROL
288  // configured on the fly by the flash library
289  //----ITM
290  // reinitialized by halPowerUp() or similar
291  //----DWT
292  // not used by software on chip
293  //----FPB
294  // not used by software on chip
295  //----NVIC
296  //ST_CSR - fixed, restored by cstartup when exiting deep sleep
297  //ST_RVR - fixed, restored by cstartup when exiting deep sleep
298  uint32_t INT_CFGSET_SAVED = INT_CFGSET_REG; //mask against wake sources
299  //INT_PENDSET - used below when overlapping interrupts and wake sources
300  //NVIC_IPR_3to0 - fixed, restored by cstartup when exiting deep sleep
301  //NVIC_IPR_7to4 - fixed, restored by cstartup when exiting deep sleep
302  //NVIC_IPR_11to8 - fixed, restored by cstartup when exiting deep sleep
303  //NVIC_IPR_15to12 - fixed, restored by cstartup when exiting deep sleep
304  //NVIC_IPR_19to16 - fixed, restored by cstartup when exiting deep sleep
305  uint32_t SCS_VTOR_SAVED = SCS_VTOR_REG;
306  //SCS_CCR - fixed, restored by cstartup when exiting deep sleep
307  //SCS_SHPR_7to4 - fixed, restored by cstartup when exiting deep sleep
308  //SCS_SHPR_11to8 - fixed, restored by cstartup when exiting deep sleep
309  //SCS_SHPR_15to12 - fixed, restored by cstartup when exiting deep sleep
310  //SCS_SHCSR - fixed, restored by cstartup when exiting deep sleep
311  //----TPIU
312  // reinitialized by halPowerUp() or similar
313 
314  //stmDebugPowerDown() should have shutdown the DWT/ITM/TPIU already.
315 
316  //freeze input to the GPIO from LV (alternate output functions freeze)
317  EVENT_CTRL = LV_FREEZE;
318  //record GPIO state for wake monitoring purposes
319  //By having a snapshot of GPIO state, we can figure out after waking
320  //up exactly which GPIO could have woken us up.
321  //Reading the three IN registers is done separately to avoid warnings
322  //about undefined order of volatile access.
323  uint32_t GPIO_IN_SAVED = GPIO_PAIN;
324  GPIO_IN_SAVED |= (GPIO_PBIN<<8);
325  GPIO_IN_SAVED |= (GPIO_PCIN<<16);
326  //reset the power up events by writing 1 to all bits.
327  PWRUP_EVENT = 0xFFFFFFFF;
328 
329 
330 
331  //By clearing the events, the wake up event capturing is activated.
332  //At this point we can safely check our interrupt flags since event
333  //capturing is now overlapped. Up to now, interrupts indicate
334  //activity, after this point, powerup events indicate activity.
335  //If any of the interrupt flags are set, that means we saw a wake event
336  //sometime while entering sleep, so we need to skip over sleeping
337  //
338  //--possible interrupt sources for waking:
339  // IRQA, IRQB, IRQC, IRQD
340  // SleepTMR CMPA, CMPB, Wrap
341  // WAKE_CORE (DebugIsr)
342  //
343  //check for IRQA interrupt and if IRQA (PB0) is wake source
344  if((INT_PENDSET&INT_IRQA) &&
345  (GPIO_PBWAKE&PB0) &&
346  (WAKE_SEL&GPIO_WAKE)) {
347  skipSleep = TRUE;
348  //log IRQA as a wake event
349  halInternalWakeEvent |= BIT(PORTB_PIN(0));
350 
351 
352 
353  }
354  //check for IRQB interrupt and if IRQB (PB6) is wake source
355  if((INT_PENDSET&INT_IRQB) &&
356  (GPIO_PBWAKE&PB6) &&
357  (WAKE_SEL&GPIO_WAKE)) {
358  skipSleep = TRUE;
359  //log IRQB as a wake event
360  halInternalWakeEvent |= BIT(PORTB_PIN(6));
361 
362 
363 
364  }
365  //check for IRQC interrupt and if IRQC (GPIO_IRQCSEL) is wake source
366  if((INT_PENDSET&INT_IRQC) &&
367  (gpioWakeSel&BIT(GPIO_IRQCSEL)) &&
368  (WAKE_SEL&GPIO_WAKE)) {
369  skipSleep = TRUE;
370  //log IRQC as a wake event
371  halInternalWakeEvent |= BIT(GPIO_IRQCSEL);
372 
373 
374 
375  }
376  //check for IRQD interrupt and if IRQD (GPIO_IRQDSEL) is wake source
377  if((INT_PENDSET&INT_IRQD) &&
378  (gpioWakeSel&BIT(GPIO_IRQDSEL)) &&
379  ((WAKE_SEL&GPIO_WAKE) ||
380  (WAKE_SEL&WAKE_IRQD))) {
381  skipSleep = TRUE;
382  //log IRQD as a wake event
383  halInternalWakeEvent |= BIT(GPIO_IRQDSEL);
384 
385 
386 
387  }
388  //check for SleepTMR CMPA interrupt and if SleepTMR CMPA is wake source
389  if((INT_SLEEPTMR&INT_SLEEPTMRCMPA) && (WAKE_SEL&WAKE_SLEEPTMRCMPA)) {
390  skipSleep = TRUE;
391  //log SleepTMR CMPA as a wake event
392  halInternalWakeEvent |= BIT32(CMPA_INTERNAL_WAKE_EVENT_BIT);
393 
394 
395 
396  }
397  //check for SleepTMR CMPB interrupt and if SleepTMR CMPB is wake source
398  if((INT_SLEEPTMR&INT_SLEEPTMRCMPB) && (WAKE_SEL&WAKE_SLEEPTMRCMPB)) {
399  skipSleep = TRUE;
400  //log SleepTMR CMPB as a wake event
401  halInternalWakeEvent |= BIT32(CMPB_INTERNAL_WAKE_EVENT_BIT);
402 
403 
404 
405  }
406  //check for SleepTMR WRAP interrupt and if SleepTMR WRAP is wake source
407  if((INT_SLEEPTMR&INT_SLEEPTMRWRAP) && (WAKE_SEL&WAKE_SLEEPTMRWRAP)) {
408  skipSleep = TRUE;
409  //log SleepTMR WRAP as a wake event
410  halInternalWakeEvent |= BIT32(WRAP_INTERNAL_WAKE_EVENT_BIT);
411 
412 
413 
414  }
415  //check for Debug interrupt and if WAKE_CORE is wake source
416  if((INT_PENDSET&INT_DEBUG) && (WAKE_SEL&WAKE_WAKE_CORE)) {
417  skipSleep = TRUE;
418  //log WAKE_CORE as a wake event
419  halInternalWakeEvent |= BIT32(WAKE_CORE_INTERNAL_WAKE_EVENT_BIT);
420 
421 
422 
423  }
424 
425  //only propagate across deep sleep the interrupts that are both
426  //enabled and possible wake sources
427  {
428  uint32_t wakeSourceInterruptMask = 0;
429 
430  if(GPIO_PBWAKE&PB0) {
431  wakeSourceInterruptMask |= INT_IRQA;
432 
433 
434 
435  }
436  if(GPIO_PBWAKE&PB6) {
437  wakeSourceInterruptMask |= INT_IRQB;
438 
439 
440 
441  }
442  if(gpioWakeSel&BIT(GPIO_IRQCSEL)) {
443  wakeSourceInterruptMask |= INT_IRQC;
444 
445 
446 
447  }
448  if(gpioWakeSel&BIT(GPIO_IRQDSEL)) {
449  wakeSourceInterruptMask |= INT_IRQD;
450 
451 
452 
453  }
454  if( (WAKE_SEL&WAKE_SLEEPTMRCMPA) ||
455  (WAKE_SEL&WAKE_SLEEPTMRCMPB) ||
456  (WAKE_SEL&WAKE_SLEEPTMRWRAP) ) {
457  wakeSourceInterruptMask |= INT_SLEEPTMR;
458 
459 
460 
461  }
462  if(WAKE_SEL&WAKE_WAKE_CORE) {
463  wakeSourceInterruptMask |= INT_DEBUG;
464 
465 
466 
467  }
468 
469  INT_CFGSET_SAVED &= wakeSourceInterruptMask;
470  }
471 
472 
473 
474 
475 
476 
477 
478 
479 
480 
481 
482 
483 
484 
485 
486 
487 
488  //disable watchdog while sleeping (since we can't reset it asleep)
490 
491  //The chip is not allowed to enter a deep sleep mode (which could
492  //cause a core reset cycle) while CSYSPWRUPREQ is set. CSYSPWRUPREQ
493  //indicates that the debugger is trying to access sections of the
494  //chip that would get reset during deep sleep. Therefore, a reset
495  //cycle could very easily cause the debugger to error and we don't
496  //want that. While the power management state machine will stall
497  //if CSYSPWRUPREQ is set (to avoid the situation just described),
498  //in this stalled state the chip will not be responsive to wake
499  //events. To be sensitive to wake events, we must handle them in
500  //software instead. To accomplish this, we request that the
501  //CSYSPWRUPACK be inhibited (which will indicate the debugger is not
502  //connected). But, we cannot induce deep sleep until CSYSPWRUPREQ/ACK
503  //go low and these are under the debuggers control, so we must stall
504  //and wait here. If there is a wake event during this time, break
505  //out and wake like normal. If the ACK eventually clears,
506  //we can proceed into deep sleep. The CSYSPWRUPACK_INHIBIT
507  //functionality will hold off the debugger (by holding off the ACK)
508  //until we are safely past and out of deep sleep. The power management
509  //state machine then becomes responsible for clearing
510  //CSYSPWRUPACK_INHIBIT and responding to a CSYSPWRUPREQ with a
511  //CSYSPWRUPACK at the right/safe time.
512  CSYSPWRUPACK_INHIBIT = CSYSPWRUPACK_INHIBIT_CSYSPWRUPACK_INHIBIT;
513  {
514  //Use a local copy of WAKE_SEL to avoid warnings from the compiler
515  //about order of volatile accesses
516  uint32_t wakeSel = WAKE_SEL;
517  //stall until a wake event or CSYSPWRUPREQ/ACK clears
518  while( (CSYSPWRUPACK_STATUS) && (!(PWRUP_EVENT&wakeSel)) ) {}
519  //if there was a wake event, allow CSYSPWRUPACK and skip sleep
520  if(PWRUP_EVENT&wakeSel) {
521  CSYSPWRUPACK_INHIBIT = CSYSPWRUPACK_INHIBIT_RESET;
522  skipSleep = TRUE;
523  }
524  }
525 
526 
527 
528 
529 
530  if(!skipSleep) {
531 
532 
533 
534  //FogBugz 7283 states that we must switch to the OSCHF when entering
535  //deep sleep since using the 24MHz XTAL could result in RAM
536  //corruption. This switch must occur at least 2*24MHz cycles before
537  //sleeping.
538  //FogBugz 8858 states that we cannot go into deep-sleep when the
539  //chip is clocked with the 24MHz XTAL with a duty cycle as low as
540  //70/30 since this causes power_down generation timing to fail.
541  OSC24M_CTRL &= ~OSC24M_CTRL_OSC24M_SEL;
542  //If DS12 needs to be forced regardless of state, clear
543  //REGEN_DSLEEP here. This is hugely dangerous and
544  //should only be done in very controlled chip tests.
545  SCS_SCR |= SCS_SCR_SLEEPDEEP; //enable deep sleep
546  extern volatile boolean halPendSvSaveContext;
547  halPendSvSaveContext = 1; //1 means save context
548  //The INTERRUPTS_OFF used at the beginning of this function set
549  //BASEPRI such that the only interrupts that will fire are faults
550  //and PendSV. Trigger PendSV now to induce a context save.
551  SCS_ICSR |= SCS_ICSR_PENDSVSET; //pend the context save and Dsleep
552  //Since the interrupt will not fire immediately it is possible to
553  //execute a few lines of code. To stay halted in this spot until the
554  //WFI instruction, spin on the context flag (which will get cleared
555  //during the startup sequence when restoring context).
556  while(halPendSvSaveContext) {}
557  //I AM ASLEEP. WHEN EXECUTION RESUMES, CSTARTUP WILL RESTORE TO HERE
558  } else {
559  //Record the fact that we skipped sleep
560  halInternalWakeEvent |= BIT32(SLEEPSKIPPED_INTERNAL_WAKE_EVENT_BIT);
561  //If this was a true deep sleep, we would have executed cstartup and
562  //PRIMASK would be set right now. If we skipped sleep, PRIMASK is not
563  //set so we explicitely set it to guarantee the powerup sequence
564  //works cleanly and consistently with respect to interrupt
565  //dispatching and enabling.
566  _setPriMask();
567  }
568 
569 
570 
571 
572 
573 
574 
575 
576  //Clear the interrupt flags for all wake sources. This
577  //is necessary because if we don't execute an actual deep sleep cycle
578  //the interrupt flags will never be cleared. By clearing the flags,
579  //we always mimick a real deep sleep as closely as possible and
580  //guard against any accidental interrupt triggering coming out
581  //of deep sleep. (The interrupt dispatch code coming out of sleep
582  //is responsible for translating wake events into interrupt events,
583  //and if we don't clear interrupt flags here it's possible for an
584  //interrupt to trigger even if it wasn't the true wake event.)
585  INT_SLEEPTMRFLAG = (INT_SLEEPTMRCMPA |
586  INT_SLEEPTMRCMPB |
587  INT_SLEEPTMRWRAP);
588  INT_GPIOFLAG = (INT_IRQAFLAG |
589  INT_IRQBFLAG |
590  INT_IRQCFLAG |
591  INT_IRQDFLAG);
592 
593  //immediately restore the registers we saved before sleeping
594  //so IRQ and SleepTMR capture can be reenabled as quickly as possible
595  //this is safe because our global interrupts are still disabled
596  //other registers will be restored later
597 
598 
599 
600 
601 
602 
603 
604  SLEEPTMR_CLKEN_REG = SLEEPTMR_CLKEN_SAVED;
605  INT_SLEEPTMRCFG_REG = INT_SLEEPTMRCFG_SAVED;
606  INT_MGMTCFG_REG = INT_MGMTCFG_SAVED;
607  GPIO_INTCFGA_REG = GPIO_INTCFGA_SAVED;
608  GPIO_INTCFGB_REG = GPIO_INTCFGB_SAVED;
609  GPIO_INTCFGC_REG = GPIO_INTCFGC_SAVED;
610  GPIO_INTCFGD_REG = GPIO_INTCFGD_SAVED;
611  OSC24M_BIASTRIM_REG = OSC24M_BIASTRIM_SAVED;
612  OSCHF_TUNE_REG = OSCHF_TUNE_SAVED;
613  DITHER_DIS_REG = DITHER_DIS_SAVED;
614  PCTRACE_SEL_REG = PCTRACE_SEL_SAVED;
615  MEM_PROT_0_REG = MEM_PROT_0_SAVED;
616  MEM_PROT_1_REG = MEM_PROT_1_SAVED;
617  MEM_PROT_2_REG = MEM_PROT_2_SAVED;
618  MEM_PROT_3_REG = MEM_PROT_3_SAVED;
619  MEM_PROT_4_REG = MEM_PROT_4_SAVED;
620  MEM_PROT_5_REG = MEM_PROT_5_SAVED;
621  MEM_PROT_6_REG = MEM_PROT_6_SAVED;
622  MEM_PROT_7_REG = MEM_PROT_7_SAVED;
623  MEM_PROT_EN_REG = MEM_PROT_EN_SAVED;
624  INT_CFGSET_REG = INT_CFGSET_SAVED;
625  SCS_VTOR_REG = SCS_VTOR_SAVED;
626 
627  //WAKE_CORE/INT_DEBUG and INT_IRQx is cleared by INT_PENDCLR below
628  INT_PENDCLR = 0xFFFFFFFF;
629 
630  //Now that we're awake, normal interrupts are operational again
631  //Take a snapshot of the new GPIO state and the EVENT register to
632  //record our wake event
633  uint32_t GPIO_IN_NEW = GPIO_PAIN;
634  GPIO_IN_NEW |= (GPIO_PBIN<<8);
635  GPIO_IN_NEW |= (GPIO_PCIN<<16);
636  //Only operate on power up events that are also wake events. Power
637  //up events will always trigger like an interrupt flag, so we have
638  //to check them against events that are enabled for waking. (This is
639  //a two step process because we're accessing two volatile values.)
640  uint32_t powerUpEvents = PWRUP_EVENT;
641  powerUpEvents &= WAKE_SEL;
642  halInternalWakeEvent |= ((GPIO_IN_SAVED^GPIO_IN_NEW)&gpioWakeSel);
643  //PWRUP_SC1 is PB2 which is bit 10
644  halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_SC1))<<((1*8)+2);
645  //PWRUP_SC2 is PA2 which is bit 2
646  halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_SC2))<<((0*8)+2);
647  //PWRUP_IRQD is chosen by GPIO_IRQDSEL
648  halInternalWakeEvent |= (!!(powerUpEvents&PWRUP_IRQD))<<(GPIO_IRQDSEL);
649  halInternalWakeEvent |= ((powerUpEvents &
650  (PWRUP_CSYSPWRUPREQ_MASK |
651  PWRUP_CDBGPWRUPREQ_MASK |
652  PWRUP_WAKECORE_MASK |
653  PWRUP_SLEEPTMRWRAP_MASK |
654  PWRUP_SLEEPTMRCOMPB_MASK |
655  PWRUP_SLEEPTMRCOMPA_MASK ))
656  <<INTERNAL_WAKE_EVENT_BIT_SHIFT);
657  //at this point wake events are fully captured and interrupts have
658  //taken over handling all new events
659 
660 
661 
662 
663 
664 
665  //Bring limited interrupts back online. INTERRUPTS_OFF will use
666  //BASEPRI to disable all interrupts except fault handlers and PendSV.
667  //PRIMASK is still set though (global interrupt disable) so we need
668  //to clear that next.
669  INTERRUPTS_OFF();
670 
671 
672 
673 
674 
675  //Now that BASEPRI has taken control of interrupt enable/disable,
676  //we can clear PRIMASK to reenable global interrupt operation.
677  _clearPriMask();
678 
679 
680 
681 
682 
683  //wake events are saved and interrupts are back on track,
684  //disable gpio freeze
685  EVENT_CTRL = EVENT_CTRL_RESET;
686 
687  //restart watchdog if it was running when we entered sleep
688  //do this before dispatching interrupts while we still have tight
689  //control of code execution
690  if(restoreWatchdog) {
692  }
693 
694 
695 
696 
697 
698  //Pend any interrupts associated with deep sleep wake sources. The
699  //restoration of INT_CFGSET above and the changing of BASEPRI below
700  //is responsible for proper dispatching of interrupts at the end of
701  //halSleepWithOptions.
702  //
703  //
704  //The WAKE_CORE wake source triggers a Debug Interrupt. If INT_DEBUG
705  //interrupt is enabled and WAKE_CORE is a wake event, then pend the
706  //Debug interrupt (using the wake_core bit).
707  if( (INT_CFGSET&INT_DEBUG) &&
708  (halInternalWakeEvent&BIT(WAKE_CORE_INTERNAL_WAKE_EVENT_BIT)) ) {
709  WAKE_CORE = WAKE_CORE_FIELD;
710 
711 
712 
713  }
714  //
715  //
716  //The SleepTMR CMPA is linked to a real ISR. If the SleepTMR CMPA
717  //interrupt is enabled and CMPA is a wake event, then pend the CMPA
718  //interrupt (force the second level interrupt).
719  if( (INT_SLEEPTMRCFG&INT_SLEEPTMRCMPA) &&
720  (halInternalWakeEvent&BIT(CMPA_INTERNAL_WAKE_EVENT_BIT)) ) {
721  INT_SLEEPTMRFORCE = INT_SLEEPTMRCMPA;
722 
723 
724 
725  }
726  //
727  //The SleepTMR CMPB is linked to a real ISR. If the SleepTMR CMPB
728  //interrupt is enabled and CMPB is a wake event, then pend the CMPB
729  //interrupt (force the second level interrupt).
730  if( (INT_SLEEPTMRCFG&INT_SLEEPTMRCMPB) &&
731  (halInternalWakeEvent&BIT(CMPB_INTERNAL_WAKE_EVENT_BIT)) ) {
732  INT_SLEEPTMRFORCE = INT_SLEEPTMRCMPB;
733 
734 
735 
736  }
737  //
738  //The SleepTMR WRAP is linked to a real ISR. If the SleepTMR WRAP
739  //interrupt is enabled and WRAP is a wake event, then pend the WRAP
740  //interrupt (force the second level interrupt).
741  if( (INT_SLEEPTMRCFG&INT_SLEEPTMRWRAP) &&
742  (halInternalWakeEvent&BIT(WRAP_INTERNAL_WAKE_EVENT_BIT)) ) {
743  INT_SLEEPTMRFORCE = INT_SLEEPTMRWRAP;
744 
745 
746 
747  }
748  //
749  //
750  //The four IRQs are linked to a real ISR. If any of the four IRQs
751  //triggered, then pend their ISR
752  //
753  //If the IRQA interrupt mode is enabled and IRQA (PB0) is wake
754  //event, then pend the interrupt.
755  if( ((GPIO_INTCFGA&GPIO_INTMOD)!=0) &&
756  (halInternalWakeEvent&BIT(PORTB_PIN(0))) ) {
757  INT_PENDSET = INT_IRQA;
758 
759 
760 
761  }
762  //If the IRQB interrupt mode is enabled and IRQB (PB6) is wake
763  //event, then pend the interrupt.
764  if( ((GPIO_INTCFGB&GPIO_INTMOD)!=0) &&
765  (halInternalWakeEvent&BIT(PORTB_PIN(6))) ) {
766  INT_PENDSET = INT_IRQB;
767 
768 
769 
770  }
771  //If the IRQC interrupt mode is enabled and IRQC (GPIO_IRQCSEL) is wake
772  //event, then pend the interrupt.
773  if( ((GPIO_INTCFGC&GPIO_INTMOD)!=0) &&
774  (halInternalWakeEvent&BIT(GPIO_IRQCSEL)) ) {
775  INT_PENDSET = INT_IRQC;
776 
777 
778 
779  }
780  //If the IRQD interrupt mode is enabled and IRQD (GPIO_IRQDSEL) is wake
781  //event, then pend the interrupt.
782  if( ((GPIO_INTCFGD&GPIO_INTMOD)!=0) &&
783  (halInternalWakeEvent&BIT(GPIO_IRQDSEL)) ) {
784  INT_PENDSET = INT_IRQD;
785 
786 
787 
788  }
789  }
790 
791 
792 
793 
794 
795 
796  //Mark the wake events valid just before exiting
797  halInternalWakeEvent |= BIT32(WAKEINFOVALID_INTERNAL_WAKE_EVENT_BIT);
798 
799  //We are now reconfigured, appropriate ISRs are pended, and ready to go,
800  //so enable interrupts!
801  INTERRUPTS_ON();
802 
803 
804 
805 
806 
807  break; //and deep sleeping is done!
808 
809  case SLEEPMODE_IDLE:
810  //Only the CPU is idled. The rest of the chip continues runing
811  //normally. The chip will wake from any interrupt.
812  {
813  boolean restoreWatchdog = halInternalWatchDogEnabled();
814  //disable watchdog while sleeping (since we can't reset it asleep)
816  //Normal ATOMIC/INTERRUPTS_OFF/INTERRUPTS_ON uses the BASEPRI mask
817  //to juggle priority levels so that the fault handlers can always
818  //be serviced. But, the WFI instruction is only capable of
819  //working with the PRIMASK bit. Therefore, we have to switch from
820  //using BASEPRI to PRIMASK to keep interrupts disabled so that the
821  //WFI can return on an interrupt
822  //Globally disable interrupts with PRIMASK
823  _setPriMask();
824  //Bring the BASEPRI up to 0 to allow interrupts (but still disabled
825  //with PRIMASK)
826  INTERRUPTS_ON();
827  //an internal function call is made here instead of injecting the
828  //"WFI" assembly instruction because injecting assembly code will
829  //cause the compiler's optimizer to reduce efficiency.
831  //The WFI instruction does not actually clear the PRIMASK bit, it
832  //only allows the PRIMASK bit to be bypassed. Therefore, we must
833  //manually clear PRIMASK to reenable all interrupts.
834  _clearPriMask();
835  //restart watchdog if it was running when we entered sleep
836  if(restoreWatchdog)
838  }
839  break;
840 
841  default:
842  //Oops! Invalid sleepMode parameter.
843  assert(0);
844  }
845 }
846 
847 
848 void halSleepWithOptions(SleepModes sleepMode, uint32_t gpioWakeBitMask)
849 {
850  //configure all GPIO wake sources
851  GPIO_PAWAKE = (gpioWakeBitMask>>0)&0xFF;
852  GPIO_PBWAKE = (gpioWakeBitMask>>8)&0xFF;
853  GPIO_PCWAKE = (gpioWakeBitMask>>16)&0xFF;
854 
855  //use the defines found in the board file to choose our wakeup source(s)
856  WAKE_SEL = 0; //start with no wake sources
857 
858  //if any of the GPIO wakeup monitor bits are set, enable the top level
859  //GPIO wakeup monitor
860  if((GPIO_PAWAKE)||(GPIO_PBWAKE)||(GPIO_PCWAKE)) {
861  WAKE_SEL |= GPIO_WAKE;
862  }
863  //always wakeup when the debugger is connected
864  WAKE_SEL |= WAKE_CDBGPWRUPREQ;
865  //always wakeup when the debugger attempts to access the chip
866  WAKE_SEL |= WAKE_CSYSPWRUPREQ;
867  //always wakeup when the debug channel attempts to access the chip
868  WAKE_SEL |= WAKE_WAKE_CORE;
869  //the timer wakeup sources are enabled below in POWERSAVE, if needed
870 
871  //wake sources are configured so do the actual sleeping
872  halInternalSleep(sleepMode);
873 }
void halSleepWithOptions(SleepModes sleepMode, uint32_t gpioWakeBitMask)
Puts the microcontroller to sleep in a specified mode, allows the GPIO wake sources to be determined ...
Definition: sleep.c:848
void halInternalIdleSleep(void)
Provides access to assembly code which triggers idle sleep.
boolean halInternalWatchDogEnabled(void)
Determines whether the watchdog has been enabled or disabled.
Definition: micro-common.c:39
void halInternalEnableWatchDog(void)
Enables the watchdog timer.
Definition: micro-common.c:17
Utility and convenience functions for STM32W108 microcontroller, common to both the full and minimal ...
#define BIT32(x)
Useful to reference a single bit of an uint32_t type.
void halInternalDisableWatchDog(uint8_t magicKey)
Disables the watchdog timer.
Definition: micro-common.c:31
void halInternalSleep(SleepModes sleepMode)
Puts the microcontroller to sleep in a specified mode.
Definition: sleep.c:127
uint32_t halGetWakeInfo(void)
Obtains the events that caused the last wake from sleep.
Definition: sleep.c:122
#define BIT(x)
Useful to reference a single bit of a byte.
#define TRUE
An alias for one, used for clarity.
Minimal Hal functions common across all microcontroller-specific files.
#define INTERRUPTS_OFF()
Disable global interrupts without regard to the current or previous state.
Definition: gnu.h:438
#define MICRO_DISABLE_WATCH_DOG_KEY
The value that must be passed as the single parameter to halInternalDisableWatchDog() in order to suc...
Definition: micro-common.h:52
#define INTERRUPTS_ON()
Enable global interrupts without regard to the current or previous state.
Definition: gnu.h:428
#define FALSE
An alias for zero, used for clarity.
#define PORTB_PIN(y)
Some registers and variables require indentifying GPIO by a single number instead of the port and pin...
Definition: micro-common.h:42