EFR32 Mighty Gecko 13 Software Documentation  efr32mg13-doc-5.1.2
sleep.c
Go to the documentation of this file.
1 /***************************************************************************/
32 /* Chip specific header file(s). */
33 #include "em_device.h"
34 #include "em_assert.h"
35 #include "em_core.h"
36 #include "em_rmu.h"
37 #include "em_emu.h"
38 
39 /* Module header file(s). */
40 #include "sleep.h"
41 
42 /* stdlib is needed for NULL definition */
43 #include <stdlib.h>
44 
45 /***************************************************************************/
50 /***************************************************************************/
64 /*******************************************************************************
65  ******************************* MACROS ************************************
66  ******************************************************************************/
67 
70 /* Number of low energy modes (EM2 and EM3). Note: EM4 sleep/wakeup is handled
71  * differently therefore it is not part of the list! */
72 #define SLEEP_NUMOF_LOW_ENERGY_MODES 2U
73 
74 /*******************************************************************************
75  ****************************** TYPEDEFS ***********************************
76  ******************************************************************************/
77 
78 /*******************************************************************************
79  ****************************** CONSTANTS **********************************
80  ******************************************************************************/
81 
82 /*******************************************************************************
83  ******************************* STATICS ***********************************
84  ******************************************************************************/
85 
86 /* Callback functions to call before and after sleep. */
87 static SLEEP_CbFuncPtr_t sleepCallback = NULL;
88 static SLEEP_CbFuncPtr_t wakeUpCallback = NULL;
89 
90 /* Sleep block counter array representing the nested sleep blocks for the low
91  * energy modes (EM2/EM3). Array index 0 corresponds to EM2 and index 1
92  * to EM3.
93  *
94  * Note:
95  * - EM4 sleep/wakeup is handled differently therefore it is not part of the
96  * list!
97  * - Max. number of sleep block nesting is 255. */
98 static uint8_t sleepBlockCnt[SLEEP_NUMOF_LOW_ENERGY_MODES];
99 
100 /*******************************************************************************
101  ****************************** PROTOTYPES *********************************
102  ******************************************************************************/
103 
104 static void enterEMx(SLEEP_EnergyMode_t eMode);
105 
108 /*******************************************************************************
109  *************************** GLOBAL FUNCTIONS ******************************
110  ******************************************************************************/
111 
112 /***************************************************************************/
132 {
133  /* Initialize callback functions. */
134  sleepCallback = pSleepCb;
135  wakeUpCallback = pWakeUpCb;
136 
137  /* Reset sleep block counters. Note: not using for() saves code! */
138  sleepBlockCnt[0U] = 0U;
139  sleepBlockCnt[1U] = 0U;
140 
141 #if (SLEEP_EM4_WAKEUP_CALLBACK_ENABLED == true) \
142  && (defined(RMU_RSTCAUSE_EM4WURST) || defined(RMU_RSTCAUSE_EM4RST))
143  /* Check if the Init() happened after an EM4 reset. */
144 #if defined(RMU_RSTCAUSE_EM4WURST)
145  if (RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4WURST)
146 #elif defined(RMU_RSTCAUSE_EM4RST)
148 #endif
149  {
150  /* Clear the cause of the reset. */
152  /* Call wakeup callback with EM4 parameter. */
153  if (NULL != wakeUpCallback)
154  {
155  wakeUpCallback(sleepEM4);
156  }
157  }
158 #endif
159 }
160 
161 /***************************************************************************/
180 {
182  SLEEP_EnergyMode_t allowedEM;
183 
184  /* Critical section to allow sleep blocks in ISRs. */
186  allowedEM = SLEEP_LowestEnergyModeGet();
187 
188  if ((allowedEM >= sleepEM1) && (allowedEM <= sleepEM3))
189  {
190  enterEMx(allowedEM);
191  }
192  else
193  {
194  allowedEM = sleepEM0;
195  }
197 
198  return allowedEM;
199 }
200 
201 /***************************************************************************/
215 {
216 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
217  /* Unblock the EM2/EM3/EM4 block in the EMU. */
218  EMU_EM2UnBlock();
219 #endif
220 
221  /* Request entering to EM4. */
222  enterEMx(sleepEM4);
223 }
224 
225 /***************************************************************************/
250 {
251  EFM_ASSERT((eMode >= sleepEM2) && (eMode < sleepEM4));
252  EFM_ASSERT((sleepBlockCnt[eMode - 2U]) < 255U);
253 
254  if ((eMode == sleepEM2) || (eMode == sleepEM3))
255  {
256  /* Increase the sleep block counter of the selected energy mode. */
257  sleepBlockCnt[eMode - 2U]++;
258 
259 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
260  /* Block EM2/EM3 sleep if the EM2 block begins. */
261  if (eMode == sleepEM2)
262  {
263  EMU_EM2Block();
264  }
265 #endif
266  }
267 }
268 
269 /***************************************************************************/
296 {
297  EFM_ASSERT((eMode >= sleepEM2) && (eMode < sleepEM4));
298 
299  if ((eMode == sleepEM2) || (eMode == sleepEM3))
300  {
301  /* Decrease the sleep block counter of the selected energy mode. */
302  if (sleepBlockCnt[eMode - 2U] > 0U)
303  {
304  sleepBlockCnt[eMode - 2U]--;
305  }
306 
307 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
308  /* Check if the EM2/EM3 block should be unblocked in the EMU. */
309  if (0U == sleepBlockCnt[sleepEM2 - 2U])
310  {
311  EMU_EM2UnBlock();
312  }
313 #endif
314  }
315 }
316 
317 /***************************************************************************/
332 {
333  SLEEP_EnergyMode_t tmpLowestEM = sleepEM1;
334 
335  /* Check which is the lowest energy mode that the system can be set to. */
336  if (0U == sleepBlockCnt[sleepEM2 - 2U])
337  {
338  tmpLowestEM = sleepEM2;
339  if (0U == sleepBlockCnt[sleepEM3 - 2U])
340  {
341  tmpLowestEM = sleepEM3;
342  }
343  }
344 
345  /* Compare with the default lowest energy mode setting. */
346  if (SLEEP_LOWEST_ENERGY_MODE_DEFAULT < tmpLowestEM)
347  {
348  tmpLowestEM = SLEEP_LOWEST_ENERGY_MODE_DEFAULT;
349  }
350 
351  return tmpLowestEM;
352 }
353 
356 /***************************************************************************/
372 static void enterEMx(SLEEP_EnergyMode_t eMode)
373 {
374  EFM_ASSERT((eMode > sleepEM0) && (eMode <= sleepEM4));
375 
376  /* Call sleepCallback() before going to sleep. */
377  if (NULL != sleepCallback)
378  {
379  /* Call the callback before going to sleep. */
380  sleepCallback(eMode);
381  }
382 
383  /* Enter the requested energy mode. */
384  switch (eMode)
385  {
386  case sleepEM1:
387  EMU_EnterEM1();
388  break;
389 
390  case sleepEM2:
391  EMU_EnterEM2(true);
392  break;
393 
394  case sleepEM3:
395  EMU_EnterEM3(true);
396  break;
397 
398  case sleepEM4:
399  EMU_EnterEM4();
400  break;
401 
402  default:
403  /* Don't do anything, stay in EM0. */
404  break;
405  }
406 
407  /* Call the callback after waking up from sleep. */
408  if (NULL != wakeUpCallback)
409  {
410  wakeUpCallback(eMode);
411  }
412 }
void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode)
End sleep block in the requested energy mode.
Definition: sleep.c:295
uint32_t RMU_ResetCauseGet(void)
Get the cause of the last reset.
Definition: em_rmu.c:291
#define CORE_DECLARE_IRQ_STATE
Definition: em_core.h:85
Emlib peripheral API "assert" implementation.
void EMU_EnterEM4(void)
Enter energy mode 4 (EM4).
Definition: em_emu.c:705
void EMU_EnterEM3(bool restore)
Enter energy mode 3 (EM3).
Definition: em_emu.c:597
void EMU_EnterEM2(bool restore)
Enter energy mode 2 (EM2).
Definition: em_emu.c:480
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
void SLEEP_SleepBlockBegin(SLEEP_EnergyMode_t eMode)
Begin sleep block in the requested energy mode.
Definition: sleep.c:249
#define SLEEP_LOWEST_ENERGY_MODE_DEFAULT
Definition: sleep.h:90
void SLEEP_Init(SLEEP_CbFuncPtr_t pSleepCb, SLEEP_CbFuncPtr_t pWakeUpCb)
Initialize the Sleep module.
Definition: sleep.c:131
SLEEP_EnergyMode_t
Definition: sleep.h:98
__STATIC_INLINE void EMU_EnterEM1(void)
Enter energy mode 1 (EM1).
Definition: em_emu.h:713
__STATIC_INLINE void EMU_EM2UnBlock(void)
Unblock entering EM2 or higher number energy modes.
Definition: em_emu.h:969
Core interrupt handling API.
SLEEP_EnergyMode_t SLEEP_Sleep(void)
Sets the system to sleep into the lowest possible energy mode.
Definition: sleep.c:179
#define RMU_RSTCAUSE_EM4RST
Reset Management Unit (RMU) peripheral API.
Energy management unit (EMU) peripheral API.
#define CORE_EXIT_CRITICAL()
Definition: em_core.h:110
void(* SLEEP_CbFuncPtr_t)(SLEEP_EnergyMode_t)
Definition: sleep.h:117
#define CORE_ENTER_CRITICAL()
Definition: em_core.h:106
void SLEEP_ForceSleepInEM4(void)
Force the device to go to EM4 without doing any checks.
Definition: sleep.c:214
void RMU_ResetCauseClear(void)
Clear the reset cause register.
Definition: em_rmu.c:249
SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void)
Gets the lowest energy mode that the system is allowed to be set to.
Definition: sleep.c:331
__STATIC_INLINE void EMU_EM2Block(void)
Block entering EM2 or higher number energy modes.
Definition: em_emu.h:960
Energy Modes management driver.