em_emu.c

Go to the documentation of this file.
00001 /***************************************************************************/
00034 #include "em_emu.h"
00035 #if defined( EMU_PRESENT )
00036 
00037 #include "em_cmu.h"
00038 #include "em_system.h"
00039 #include "em_assert.h"
00040 
00041 /***************************************************************************/
00046 /***************************************************************************/
00052 /* Consistency check, since restoring assumes similar bitpositions in */
00053 /* CMU OSCENCMD and STATUS regs */
00054 #if (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
00055 #error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
00056 #endif
00057 #if (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)
00058 #error Conflict in HFXOENS and HFXOEN bitpositions
00059 #endif
00060 #if (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
00061 #error Conflict in LFRCOENS and LFRCOEN bitpositions
00062 #endif
00063 #if (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)
00064 #error Conflict in LFXOENS and LFXOEN bitpositions
00065 #endif
00066 
00067 
00069 /* Fix for errata EMU_E107 - non-WIC interrupt masks. */                              
00070 #if defined(_EFM32_GECKO_FAMILY) 
00071   #define ERRATA_FIX_EMU_E107_EN
00072   #define NON_WIC_INT_MASK_0    (~(0x0dfc0323U))
00073   #define NON_WIC_INT_MASK_1    (~(0x0U))     
00074 #elif defined(_EFM32_TINY_FAMILY) 
00075   #define ERRATA_FIX_EMU_E107_EN
00076   #define NON_WIC_INT_MASK_0    (~(0x001be323U))
00077   #define NON_WIC_INT_MASK_1    (~(0x0U))  
00078 #elif defined(_EFM32_GIANT_FAMILY)     
00079   #define ERRATA_FIX_EMU_E107_EN
00080   #define NON_WIC_INT_MASK_0    (~(0xff020e63U))
00081   #define NON_WIC_INT_MASK_1    (~(0x00000046U))
00082 #elif defined(_EFM32_WONDER_FAMILY)
00083   #define ERRATA_FIX_EMU_E107_EN
00084   #define NON_WIC_INT_MASK_0    (~(0xff020e63U))
00085   #define NON_WIC_INT_MASK_1    (~(0x00000046U))     
00086 #else
00087 /* Zero Gecko and future families are not affected by errata EMU_E107 */
00088 #endif
00089 
00091 /*******************************************************************************
00092  **************************   LOCAL VARIABLES   ********************************
00093  ******************************************************************************/
00094 
00105 static uint16_t cmuStatus;
00109 /*******************************************************************************
00110  **************************   LOCAL FUNCTIONS   ********************************
00111  ******************************************************************************/
00112 
00115 /***************************************************************************/
00119 static void EMU_Restore(void)
00120 {
00121   uint32_t cmuLocked;
00122 
00123   /* Although we could use the CMU API for most of the below handling, we */
00124   /* would like this function to be as efficient as possible. */
00125 
00126   /* CMU registers may be locked */
00127   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
00128   CMU_Unlock();
00129 
00130   /* AUXHFRCO was automatically disabled (except if using debugger). */
00131   /* HFXO was automatically disabled. */
00132   /* LFRCO/LFXO were possibly disabled by SW in EM3. */
00133   /* Restore according to status prior to entering EM. */
00134   CMU->OSCENCMD = cmuStatus & (CMU_STATUS_AUXHFRCOENS |
00135                                CMU_STATUS_HFXOENS |
00136                                CMU_STATUS_LFRCOENS |
00137                                CMU_STATUS_LFXOENS);
00138 
00139   /* Restore oscillator used for clocking core */
00140   switch (cmuStatus & (CMU_STATUS_HFXOSEL | CMU_STATUS_HFRCOSEL |
00141                        CMU_STATUS_LFXOSEL | CMU_STATUS_LFRCOSEL))
00142   {
00143   case CMU_STATUS_LFRCOSEL:
00144     /* Wait for LFRCO to stabilize */
00145     while (!(CMU->STATUS & CMU_STATUS_LFRCORDY))
00146       ;
00147     CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
00148     break;
00149 
00150   case CMU_STATUS_LFXOSEL:
00151     /* Wait for LFXO to stabilize */
00152     while (!(CMU->STATUS & CMU_STATUS_LFXORDY))
00153       ;
00154     CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
00155     break;
00156 
00157   case CMU_STATUS_HFXOSEL:
00158     /* Wait for HFXO to stabilize */
00159     while (!(CMU->STATUS & CMU_STATUS_HFXORDY))
00160       ;
00161     CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
00162     break;
00163 
00164   default: /* CMU_STATUS_HFRCOSEL */
00165     /* If core clock was HFRCO core clock, it is automatically restored to */
00166     /* state prior to entering energy mode. No need for further action. */
00167     break;
00168   }
00169 
00170   /* If HFRCO was disabled before entering Energy Mode, turn it off again */
00171   /* as it is automatically enabled by wake up */
00172   if ( ! (cmuStatus & CMU_STATUS_HFRCOENS) )
00173   {
00174     CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
00175   }
00176 
00177   /* Restore CMU register locking */
00178   if (cmuLocked)
00179   {
00180     CMU_Lock();
00181   }
00182 }
00183 
00184 
00185 /* Get enable conditions for errata EMU_E107 fix. */
00186 #if defined(ERRATA_FIX_EMU_E107_EN)  
00187 static __INLINE bool getErrataFixEmuE107En(void)
00188 {
00189   /* SYSTEM_ChipRevisionGet could have been used here, but we would like a faster implementation in this case. */
00190   uint16_t majorMinorRev;  
00191   
00192   /* CHIP MAJOR bit [3:0] */
00193   majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK) >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8);  
00194   /* CHIP MINOR bit [7:4] */
00195   majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK) >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);  
00196   /* CHIP MINOR bit [3:0] */
00197   majorMinorRev |=  ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK) >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
00198   
00199 #if defined(_EFM32_GECKO_FAMILY)
00200   return (majorMinorRev <= 0x0103);
00201 #elif defined(_EFM32_TINY_FAMILY)
00202   return (majorMinorRev <= 0x0102);
00203 #elif defined(_EFM32_GIANT_FAMILY)
00204   return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204);
00205 #elif defined(_EFM32_WONDER_FAMILY)
00206   return (majorMinorRev == 0x0100);
00207 #else
00208   /* Zero Gecko and future families are not affected by errata EMU_E107 */
00209   return false;
00210 #endif
00211 }
00212 #endif
00213 
00217 /*******************************************************************************
00218  **************************   GLOBAL FUNCTIONS   *******************************
00219  ******************************************************************************/
00220 
00221 /***************************************************************************/
00262 void EMU_EnterEM2(bool restore)
00263 { 
00264 #if defined(ERRATA_FIX_EMU_E107_EN)
00265   bool errataFixEmuE107En;
00266   uint32_t nonWicIntEn[2];  
00267 #endif
00268   
00269   /* Auto-update CMU status just in case before entering energy mode. */
00270   /* This variable is normally kept up-to-date by the CMU API. */
00271   cmuStatus = (uint16_t)(CMU->STATUS);
00272   
00273   /* Enter Cortex-M3 deep sleep mode */
00274   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00275   
00276   /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
00277      Disable the enabled non-WIC interrupts. */
00278 #if defined(ERRATA_FIX_EMU_E107_EN)
00279   errataFixEmuE107En = getErrataFixEmuE107En();
00280   if (errataFixEmuE107En)
00281   {
00282     nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;    
00283     NVIC->ICER[0] = nonWicIntEn[0];
00284 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))   
00285     nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
00286     NVIC->ICER[1] = nonWicIntEn[1];  
00287 #endif
00288   }
00289 #endif
00290 
00291   __WFI();
00292   
00293   /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
00294 #if defined(ERRATA_FIX_EMU_E107_EN)
00295   if (errataFixEmuE107En)
00296   {
00297     NVIC->ISER[0] = nonWicIntEn[0];
00298 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))   
00299     NVIC->ISER[1] = nonWicIntEn[1];
00300 #endif
00301   }
00302 #endif
00303   
00304   /* Restore oscillators/clocks if specified */
00305   if (restore)
00306   {
00307     EMU_Restore();
00308   }
00309   /* If not restoring, and original clock was not HFRCO, we have to */
00310   /* update CMSIS core clock variable since core clock has changed */
00311   /* to using HFRCO. */
00312   else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
00313   {
00314     SystemCoreClockUpdate();
00315   }
00316 }
00317 
00318 
00319 /***************************************************************************/
00361 void EMU_EnterEM3(bool restore)
00362 {
00363   uint32_t cmuLocked;
00364   
00365 #if defined(ERRATA_FIX_EMU_E107_EN)
00366   bool errataFixEmuE107En;
00367   uint32_t nonWicIntEn[2];
00368 #endif
00369 
00370   /* Auto-update CMU status just in case before entering energy mode. */
00371   /* This variable is normally kept up-to-date by the CMU API. */
00372   cmuStatus = (uint16_t)(CMU->STATUS);
00373 
00374   /* CMU registers may be locked */
00375   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
00376   CMU_Unlock();
00377 
00378   /* Disable LF oscillators */
00379   CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
00380 
00381   /* Restore CMU register locking */
00382   if (cmuLocked)
00383   {
00384     CMU_Lock();
00385   }
00386 
00387   /* Enter Cortex-M3 deep sleep mode */
00388   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00389   
00390   /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
00391      Disable the enabled non-WIC interrupts. */
00392 #if defined(ERRATA_FIX_EMU_E107_EN)
00393   errataFixEmuE107En = getErrataFixEmuE107En();
00394   if (errataFixEmuE107En)
00395   {
00396     nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;    
00397     NVIC->ICER[0] = nonWicIntEn[0];
00398 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))    
00399     nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
00400     NVIC->ICER[1] = nonWicIntEn[1];  
00401 #endif    
00402     
00403   }
00404 #endif
00405   
00406   __WFI();
00407   
00408   /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
00409 #if defined(ERRATA_FIX_EMU_E107_EN)
00410   if (errataFixEmuE107En)
00411   {
00412     NVIC->ISER[0] = nonWicIntEn[0];
00413 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))  
00414     NVIC->ISER[1] = nonWicIntEn[1];
00415 #endif
00416   }
00417 #endif
00418 
00419   /* Restore oscillators/clocks if specified */
00420   if (restore)
00421   {
00422     EMU_Restore();
00423   }
00424   /* If not restoring, and original clock was not HFRCO, we have to */
00425   /* update CMSIS core clock variable since core clock has changed */
00426   /* to using HFRCO. */
00427   else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
00428   {
00429     SystemCoreClockUpdate();
00430   }
00431 }
00432 
00433 
00434 /***************************************************************************/
00441 void EMU_EnterEM4(void)
00442 {
00443   int i;
00444 
00445   /* Make sure register write lock is disabled */
00446   EMU->LOCK = EMU_LOCK_LOCKKEY_UNLOCK;
00447 
00448   for (i = 0; i < 4; i++)
00449   {
00450     EMU->CTRL = (2 << _EMU_CTRL_EM4CTRL_SHIFT);
00451     EMU->CTRL = (3 << _EMU_CTRL_EM4CTRL_SHIFT);
00452   }
00453   EMU->CTRL = (2 << _EMU_CTRL_EM4CTRL_SHIFT);
00454 }
00455 
00456 
00457 /***************************************************************************/
00472 void EMU_MemPwrDown(uint32_t blocks)
00473 {
00474 #if defined(_EMU_MEMCTRL_RESETVALUE)
00475   EFM_ASSERT(blocks <= _EMU_MEMCTRL_MASK);
00476 
00477   EMU->MEMCTRL = blocks;
00478 #else
00479   (void)blocks;
00480 #endif
00481 }
00482 
00483 
00484 /***************************************************************************/
00503 void EMU_UpdateOscConfig(void)
00504 {
00505   /* Fetch current configuration */
00506   cmuStatus = (uint16_t)(CMU->STATUS);
00507 }
00508 
00509 
00510 #if defined( _EMU_EM4CONF_MASK )
00511 /***************************************************************************/
00518 void EMU_EM4Init(EMU_EM4Init_TypeDef *em4init)
00519 {
00520   uint32_t em4conf = EMU->EM4CONF;
00521 
00522   /* Clear fields that will be reconfigured */
00523   em4conf &= ~(
00524     _EMU_EM4CONF_LOCKCONF_MASK|
00525     _EMU_EM4CONF_OSC_MASK|
00526     _EMU_EM4CONF_BURTCWU_MASK|
00527     _EMU_EM4CONF_VREGEN_MASK);
00528 
00529   /* Configure new settings */
00530   em4conf |= (
00531     (em4init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)|
00532     (em4init->osc)|
00533     (em4init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)|
00534     (em4init->vreg << _EMU_EM4CONF_VREGEN_SHIFT));
00535 
00536   /* Apply configuration. Note that lock can be set after this stage. */
00537   EMU->EM4CONF = em4conf;
00538 }
00539 
00540 
00541 /***************************************************************************/
00548 void EMU_BUPDInit(EMU_BUPDInit_TypeDef *bupdInit)
00549 {
00550   uint32_t reg;
00551 
00552   /* Set power connection configuration */
00553   reg = EMU->PWRCONF & ~(
00554     _EMU_PWRCONF_PWRRES_MASK|
00555     _EMU_PWRCONF_VOUTSTRONG_MASK|
00556     _EMU_PWRCONF_VOUTMED_MASK|
00557     _EMU_PWRCONF_VOUTWEAK_MASK);
00558 
00559   reg |= (bupdInit->resistor|
00560          (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)|
00561          (bupdInit->voutMed    << _EMU_PWRCONF_VOUTMED_SHIFT)|
00562          (bupdInit->voutWeak   << _EMU_PWRCONF_VOUTWEAK_SHIFT));
00563 
00564   EMU->PWRCONF = reg;
00565 
00566   /* Set backup domain inactive mode configuration */
00567   reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
00568   reg |= (bupdInit->inactivePower);
00569   EMU->BUINACT = reg;
00570 
00571   /* Set backup domain active mode configuration */
00572   reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
00573   reg |= (bupdInit->activePower);
00574   EMU->BUACT = reg;
00575 
00576   /* Set power control configuration */
00577   reg = EMU->BUCTRL & ~(
00578     _EMU_BUCTRL_PROBE_MASK|
00579     _EMU_BUCTRL_BODCAL_MASK|
00580     _EMU_BUCTRL_STATEN_MASK|
00581     _EMU_BUCTRL_EN_MASK);
00582 
00583   /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and
00584      release reset */
00585   reg |= (bupdInit->probe|
00586          (bupdInit->bodCal          << _EMU_BUCTRL_BODCAL_SHIFT)|
00587          (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)|
00588          (bupdInit->enable          << _EMU_BUCTRL_EN_SHIFT));
00589 
00590   /* Enable configuration */
00591   EMU->BUCTRL = reg;
00592 
00593   /* If enable is true, enable BU_VIN input power pin, if not disable it  */
00594   EMU_BUPinEnable(bupdInit->enable);
00595 
00596   /* If enable is true, release BU reset, if not keep reset asserted */
00597   BITBAND_Peripheral(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
00598 }
00599 
00600 
00601 /***************************************************************************/
00609 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
00610 {
00611   EFM_ASSERT(value<=(_EMU_BUACT_BUEXTHRES_MASK>>_EMU_BUACT_BUEXTHRES_SHIFT));
00612 
00613   switch(mode)
00614   {
00615   case emuBODMode_Active:
00616     EMU->BUACT = (EMU->BUACT & ~(_EMU_BUACT_BUEXTHRES_MASK))|(value<<_EMU_BUACT_BUEXTHRES_SHIFT);
00617     break;
00618   case emuBODMode_Inactive:
00619     EMU->BUINACT = (EMU->BUINACT & ~(_EMU_BUINACT_BUENTHRES_MASK))|(value<<_EMU_BUINACT_BUENTHRES_SHIFT);
00620     break;
00621   }
00622 }
00623 
00624 
00625 /***************************************************************************/
00633 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
00634 {
00635   EFM_ASSERT(value<=(_EMU_BUACT_BUEXRANGE_MASK>>_EMU_BUACT_BUEXRANGE_SHIFT));
00636 
00637   switch(mode)
00638   {
00639   case emuBODMode_Active:
00640     EMU->BUACT = (EMU->BUACT & ~(_EMU_BUACT_BUEXRANGE_MASK))|(value<<_EMU_BUACT_BUEXRANGE_SHIFT);
00641     break;
00642   case emuBODMode_Inactive:
00643     EMU->BUINACT = (EMU->BUINACT & ~(_EMU_BUINACT_BUENRANGE_MASK))|(value<<_EMU_BUINACT_BUENRANGE_SHIFT);
00644     break;
00645   }
00646 }
00647 
00648 #endif
00649 
00650 
00653 #endif /* __EM_EMU_H */