sleep.c

Go to the documentation of this file.
00001 /***************************************************************************/
00052 /* Chip specific header file(s). */
00053 #include "em_device.h"
00054 #include "em_assert.h"
00055 #include "em_int.h"
00056 #include "em_rmu.h"
00057 #include "em_emu.h"
00058 
00059 /* Module header file(s). */
00060 #include "sleep.h"
00061 
00062 /* stdlib is needed for NULL definition */
00063 #include <stdlib.h>
00064 
00065 /***************************************************************************/
00070 /***************************************************************************/
00084 /*******************************************************************************
00085  *******************************   MACROS   ************************************
00086  ******************************************************************************/
00087 
00090 /* Number of low energy modes (EM1, EM2, EM3). Note: EM4 sleep/wakeup is handled
00091  * differently therefore it is not part of the list! */
00092 #define SLEEP_NUMOF_LOW_ENERGY_MODES    3U
00093 
00094 
00095 
00096 /*******************************************************************************
00097  ******************************   TYPEDEFS   ***********************************
00098  ******************************************************************************/
00099 
00100 
00101 /*******************************************************************************
00102  ******************************   CONSTANTS   **********************************
00103  ******************************************************************************/
00104 
00105 
00106 /*******************************************************************************
00107  *******************************   STATICS   ***********************************
00108  ******************************************************************************/
00109 
00110 /* Callback functions to call before and after sleep. */
00111 static SLEEP_CbFuncPtr_t sleepCallback  = NULL;
00112 static SLEEP_CbFuncPtr_t wakeUpCallback = NULL;
00113 
00114 /* Sleep block counter array representing the nested sleep blocks for the low
00115  * energy modes (EM1/EM2/EM3). Array index 0 corresponds to EM1, 1 to EM2 and 2
00116  * to EM3 accordingly.
00117  *
00118  * Note:
00119  * - EM4 sleep/wakeup is handled differently therefore it is not part of the
00120  *   list!
00121  * - Max. number of sleep block nesting is 255. */
00122 static uint8_t sleepBlockCnt[SLEEP_NUMOF_LOW_ENERGY_MODES];
00123 
00124 /*******************************************************************************
00125  ******************************   PROTOTYPES   *********************************
00126  ******************************************************************************/
00127 
00128 static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode);
00129 static SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void);
00130 
00133 /*******************************************************************************
00134  ***************************   GLOBAL FUNCTIONS   ******************************
00135  ******************************************************************************/
00136 
00137 /***************************************************************************/
00156 void SLEEP_Init(SLEEP_CbFuncPtr_t pSleepCb, SLEEP_CbFuncPtr_t pWakeUpCb)
00157 {
00158   /* Initialize callback functions. */
00159   sleepCallback  = pSleepCb;
00160   wakeUpCallback = pWakeUpCb;
00161 
00162   /* Reset sleep block counters. Note: not using for() saves code! */
00163   sleepBlockCnt[0U] = 0U;
00164   sleepBlockCnt[1U] = 0U;
00165   sleepBlockCnt[2U] = 0U;
00166 
00167 #if (SLEEP_EM4_WAKEUP_CALLBACK_ENABLED == true) && defined(RMU_RSTCAUSE_EM4WURST)
00168   /* Check if the Init() happened after an EM4 reset. */
00169   if (RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4WURST)
00170   {
00171     /* Clear the cause of the reset. */
00172     RMU_ResetCauseClear();
00173     /* Call wakeup callback with EM4 parameter. */
00174     if (NULL != wakeUpCallback)
00175     {
00176       wakeUpCallback(sleepEM4);
00177     }
00178   }
00179 #endif
00180 }
00181 
00182 
00183 /***************************************************************************/
00202 SLEEP_EnergyMode_t SLEEP_Sleep(void)
00203 {
00204   SLEEP_EnergyMode_t allowedEM;
00205 
00206   INT_Disable();
00207 
00208   allowedEM = SLEEP_LowestEnergyModeGet();
00209 
00210   if ((allowedEM >= sleepEM1) && (allowedEM <= sleepEM3))
00211   {
00212     SLEEP_EnterEMx(allowedEM);
00213   }
00214   else
00215   {
00216     allowedEM = sleepEM0;
00217   }
00218 
00219   INT_Enable();
00220 
00221   return(allowedEM);
00222 }
00223 
00224 
00225 /***************************************************************************/
00238 void SLEEP_ForceSleepInEM4(void)
00239 {
00240 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
00241   /* Unblock the EM2/EM3/EM4 block in the EMU. */
00242   EMU_EM2UnBlock();
00243 #endif
00244 
00245   /* Request entering to EM4. */
00246   SLEEP_EnterEMx(sleepEM4);
00247 }
00248 
00249 /***************************************************************************/
00274 void SLEEP_SleepBlockBegin(SLEEP_EnergyMode_t eMode)
00275 {
00276   EFM_ASSERT((eMode >= sleepEM1) && (eMode < sleepEM4));
00277   EFM_ASSERT((sleepBlockCnt[(uint8_t) eMode - 1U]) < 255U);
00278 
00279   /* Increase the sleep block counter of the selected energy mode. */
00280   sleepBlockCnt[(uint8_t) eMode - 1U]++;
00281 
00282 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
00283   /* Block EM2/EM3 sleep if the EM2 block begins. */
00284   if (eMode == sleepEM2)
00285   {
00286     EMU_EM2Block();
00287   }
00288 #endif
00289 }
00290 
00291 /***************************************************************************/
00318 void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode)
00319 {
00320   EFM_ASSERT((eMode >= sleepEM1) && (eMode < sleepEM4));
00321 
00322   /* Decrease the sleep block counter of the selected energy mode. */
00323   if (sleepBlockCnt[(uint8_t) eMode - 1U] > 0U)
00324   {
00325     sleepBlockCnt[(uint8_t) eMode - 1U]--;
00326   }
00327 
00328 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
00329   /* Check if the EM2/EM3 block should be unblocked in the EMU. */
00330   if (0U == sleepBlockCnt[(uint8_t) sleepEM2 - 1U])
00331   {
00332     EMU_EM2UnBlock();
00333   }
00334 #endif
00335 }
00336 
00339 /***************************************************************************/
00354 static SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void)
00355 {
00356   SLEEP_EnergyMode_t tmpLowestEM = sleepEM0;
00357 
00358   /* Check which is the lowest energy mode that the system can be set to. */
00359   if (0U == sleepBlockCnt[(uint8_t) sleepEM1 - 1U])
00360   {
00361     tmpLowestEM = sleepEM1;
00362     if (0U == sleepBlockCnt[(uint8_t) sleepEM2 - 1U])
00363     {
00364       tmpLowestEM = sleepEM2;
00365       if (0U == sleepBlockCnt[(uint8_t) sleepEM3 - 1U])
00366       {
00367         tmpLowestEM = sleepEM3;
00368       }
00369     }
00370   }
00371 
00372   /* Compare with the default lowest energy mode setting. */
00373   if (SLEEP_LOWEST_ENERGY_MODE_DEFAULT < tmpLowestEM)
00374   {
00375     tmpLowestEM = SLEEP_LOWEST_ENERGY_MODE_DEFAULT;
00376   }
00377 
00378   return tmpLowestEM;
00379 }
00380 
00381 
00382 /***************************************************************************/
00398 static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode)
00399 {
00400   EFM_ASSERT((eMode > sleepEM0) && (eMode <= sleepEM4));
00401 
00402   /* Call sleepCallback() before going to sleep. */
00403   if (NULL != sleepCallback)
00404   {
00405     /* Call the callback before going to sleep. */
00406     sleepCallback(eMode);
00407   }
00408 
00409   /* Enter the requested energy mode. */
00410   switch (eMode)
00411   {
00412   case sleepEM1:
00413   {
00414     EMU_EnterEM1();
00415   } break;
00416 
00417   case sleepEM2:
00418   {
00419     EMU_EnterEM2(true);
00420   } break;
00421 
00422   case sleepEM3:
00423   {
00424     EMU_EnterEM3(true);
00425   } break;
00426 
00427   case sleepEM4:
00428   {
00429     EMU_EnterEM4();
00430   } break;
00431 
00432   default:
00433   {
00434     /* Don't do anything, stay in EM0. */
00435   } break;
00436   }
00437 
00438   /* Call the callback after waking up from sleep. */
00439   if (NULL != wakeUpCallback)
00440   {
00441     wakeUpCallback(eMode);
00442   }
00443 }