sleep.c

Go to the documentation of this file.
00001 /***************************************************************************/
00033 /* Chip specific header file(s). */
00034 #include "em_device.h"
00035 #include "em_assert.h"
00036 #include "em_int.h"
00037 #include "em_rmu.h"
00038 #include "em_emu.h"
00039 
00040 /* Module header file(s). */
00041 #include "sleep.h"
00042 
00043 /* stdlib is needed for NULL definition */
00044 #include <stdlib.h>
00045 
00046 /***************************************************************************/
00051 /***************************************************************************/
00065 /*******************************************************************************
00066  *******************************   MACROS   ************************************
00067  ******************************************************************************/
00068 
00071 /* Number of low energy modes (EM1, EM2, EM3). Note: EM4 sleep/wakeup is handled
00072  * differently therefore it is not part of the list! */
00073 #define SLEEP_NUMOF_LOW_ENERGY_MODES    3U
00074 
00075 
00076 
00077 /*******************************************************************************
00078  ******************************   TYPEDEFS   ***********************************
00079  ******************************************************************************/
00080 
00081 
00082 /*******************************************************************************
00083  ******************************   CONSTANTS   **********************************
00084  ******************************************************************************/
00085 
00086 
00087 /*******************************************************************************
00088  *******************************   STATICS   ***********************************
00089  ******************************************************************************/
00090 
00091 /* Callback functions to call before and after sleep. */
00092 static SLEEP_CbFuncPtr_t sleepCallback  = NULL;
00093 static SLEEP_CbFuncPtr_t wakeUpCallback = NULL;
00094 
00095 /* Sleep block counter array representing the nested sleep blocks for the low
00096  * energy modes (EM1/EM2/EM3). Array index 0 corresponds to EM1, 1 to EM2 and 2
00097  * to EM3 accordingly.
00098  *
00099  * Note:
00100  * - EM4 sleep/wakeup is handled differently therefore it is not part of the
00101  *   list!
00102  * - Max. number of sleep block nesting is 255. */
00103 static uint8_t sleepBlockCnt[SLEEP_NUMOF_LOW_ENERGY_MODES];
00104 
00105 /*******************************************************************************
00106  ******************************   PROTOTYPES   *********************************
00107  ******************************************************************************/
00108 
00109 static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode);
00110 //static SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void);
00111 
00114 /*******************************************************************************
00115  ***************************   GLOBAL FUNCTIONS   ******************************
00116  ******************************************************************************/
00117 
00118 /***************************************************************************/
00137 void SLEEP_Init(SLEEP_CbFuncPtr_t pSleepCb, SLEEP_CbFuncPtr_t pWakeUpCb)
00138 {
00139   /* Initialize callback functions. */
00140   sleepCallback  = pSleepCb;
00141   wakeUpCallback = pWakeUpCb;
00142 
00143   /* Reset sleep block counters. Note: not using for() saves code! */
00144   sleepBlockCnt[0U] = 0U;
00145   sleepBlockCnt[1U] = 0U;
00146   sleepBlockCnt[2U] = 0U;
00147 
00148 #if (SLEEP_EM4_WAKEUP_CALLBACK_ENABLED == true) && defined(RMU_RSTCAUSE_EM4WURST)
00149   /* Check if the Init() happened after an EM4 reset. */
00150   if (RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4WURST)
00151   {
00152     /* Clear the cause of the reset. */
00153     RMU_ResetCauseClear();
00154     /* Call wakeup callback with EM4 parameter. */
00155     if (NULL != wakeUpCallback)
00156     {
00157       wakeUpCallback(sleepEM4);
00158     }
00159   }
00160 #endif
00161 }
00162 
00163 
00164 /***************************************************************************/
00183 SLEEP_EnergyMode_t SLEEP_Sleep(void)
00184 {
00185   SLEEP_EnergyMode_t allowedEM;
00186 
00187   INT_Disable();
00188 
00189   allowedEM = SLEEP_LowestEnergyModeGet();
00190 
00191   if ((allowedEM >= sleepEM1) && (allowedEM <= sleepEM3))
00192   {
00193     SLEEP_EnterEMx(allowedEM);
00194   }
00195   else
00196   {
00197     allowedEM = sleepEM0;
00198   }
00199 
00200   INT_Enable();
00201 
00202   return(allowedEM);
00203 }
00204 
00205 
00206 /***************************************************************************/
00219 void SLEEP_ForceSleepInEM4(void)
00220 {
00221 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
00222   /* Unblock the EM2/EM3/EM4 block in the EMU. */
00223   EMU_EM2UnBlock();
00224 #endif
00225 
00226   /* Request entering to EM4. */
00227   SLEEP_EnterEMx(sleepEM4);
00228 }
00229 
00230 /***************************************************************************/
00255 void SLEEP_SleepBlockBegin(SLEEP_EnergyMode_t eMode)
00256 {
00257   EFM_ASSERT((eMode >= sleepEM1) && (eMode < sleepEM4));
00258   EFM_ASSERT((sleepBlockCnt[(uint8_t) eMode - 1U]) < 255U);
00259 
00260   /* Increase the sleep block counter of the selected energy mode. */
00261   sleepBlockCnt[(uint8_t) eMode - 1U]++;
00262 
00263 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
00264   /* Block EM2/EM3 sleep if the EM2 block begins. */
00265   if (eMode == sleepEM2)
00266   {
00267     EMU_EM2Block();
00268   }
00269 #endif
00270 }
00271 
00272 /***************************************************************************/
00299 void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode)
00300 {
00301   EFM_ASSERT((eMode >= sleepEM1) && (eMode < sleepEM4));
00302 
00303   /* Decrease the sleep block counter of the selected energy mode. */
00304   if (sleepBlockCnt[(uint8_t) eMode - 1U] > 0U)
00305   {
00306     sleepBlockCnt[(uint8_t) eMode - 1U]--;
00307   }
00308 
00309 #if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true)
00310   /* Check if the EM2/EM3 block should be unblocked in the EMU. */
00311   if (0U == sleepBlockCnt[(uint8_t) sleepEM2 - 1U])
00312   {
00313     EMU_EM2UnBlock();
00314   }
00315 #endif
00316 }
00317 
00318 /***************************************************************************/
00333 SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void)
00334 {
00335   SLEEP_EnergyMode_t tmpLowestEM = sleepEM0;
00336 
00337   /* Check which is the lowest energy mode that the system can be set to. */
00338   if (0U == sleepBlockCnt[(uint8_t) sleepEM1 - 1U])
00339   {
00340     tmpLowestEM = sleepEM1;
00341     if (0U == sleepBlockCnt[(uint8_t) sleepEM2 - 1U])
00342     {
00343       tmpLowestEM = sleepEM2;
00344       if (0U == sleepBlockCnt[(uint8_t) sleepEM3 - 1U])
00345       {
00346         tmpLowestEM = sleepEM3;
00347       }
00348     }
00349   }
00350 
00351   /* Compare with the default lowest energy mode setting. */
00352   if (SLEEP_LOWEST_ENERGY_MODE_DEFAULT < tmpLowestEM)
00353   {
00354     tmpLowestEM = SLEEP_LOWEST_ENERGY_MODE_DEFAULT;
00355   }
00356 
00357   return tmpLowestEM;
00358 }
00359 
00362 /***************************************************************************/
00378 static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode)
00379 {
00380   EFM_ASSERT((eMode > sleepEM0) && (eMode <= sleepEM4));
00381 
00382   /* Call sleepCallback() before going to sleep. */
00383   if (NULL != sleepCallback)
00384   {
00385     /* Call the callback before going to sleep. */
00386     sleepCallback(eMode);
00387   }
00388 
00389   /* Enter the requested energy mode. */
00390   switch (eMode)
00391   {
00392   case sleepEM1:
00393   {
00394     EMU_EnterEM1();
00395   } break;
00396 
00397   case sleepEM2:
00398   {
00399     EMU_EnterEM2(true);
00400   } break;
00401 
00402   case sleepEM3:
00403   {
00404     EMU_EnterEM3(true);
00405   } break;
00406 
00407   case sleepEM4:
00408   {
00409     EMU_EnterEM4();
00410   } break;
00411 
00412   default:
00413   {
00414     /* Don't do anything, stay in EM0. */
00415   } break;
00416   }
00417 
00418   /* Call the callback after waking up from sleep. */
00419   if (NULL != wakeUpCallback)
00420   {
00421     wakeUpCallback(eMode);
00422   }
00423 }