em_emu.c

Go to the documentation of this file.
00001 /***************************************************************************/
00034 #include "em_emu.h"
00035 #if defined( EMU_PRESENT ) && ( EMU_COUNT > 0 )
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 
00090 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
00091 #if defined(_EFM32_HAPPY_FAMILY)
00092 #define ERRATA_FIX_EMU_E108_EN
00093 #endif
00094 
00096 /*******************************************************************************
00097  **************************   LOCAL VARIABLES   ********************************
00098  ******************************************************************************/
00099 
00110 static uint32_t cmuStatus;
00114 /*******************************************************************************
00115  **************************   LOCAL FUNCTIONS   ********************************
00116  ******************************************************************************/
00117 
00120 /***************************************************************************/
00124 static void EMU_Restore(void)
00125 {
00126   uint32_t oscEnCmd;
00127   uint32_t cmuLocked;
00128   uint32_t statusClkSelMask;
00129 
00130   /* Although we could use the CMU API for most of the below handling, we */
00131   /* would like this function to be as efficient as possible. */
00132 
00133   /* CMU registers may be locked */
00134   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
00135   CMU_Unlock();
00136 
00137   /* AUXHFRCO are automatically disabled (except if using debugger). */
00138   /* HFRCO, USHFRCO and HFXO are automatically disabled. */
00139   /* LFRCO/LFXO may be disabled by SW in EM3. */
00140   /* Restore according to status prior to entering energy mode. */
00141   oscEnCmd = 0;
00142   oscEnCmd |= ((cmuStatus & CMU_STATUS_HFRCOENS)    ? CMU_OSCENCMD_HFRCOEN : 0);
00143   oscEnCmd |= ((cmuStatus & CMU_STATUS_AUXHFRCOENS) ? CMU_OSCENCMD_AUXHFRCOEN : 0);
00144   oscEnCmd |= ((cmuStatus & CMU_STATUS_LFRCOENS)    ? CMU_OSCENCMD_LFRCOEN : 0);
00145   oscEnCmd |= ((cmuStatus & CMU_STATUS_HFXOENS)     ? CMU_OSCENCMD_HFXOEN : 0);
00146   oscEnCmd |= ((cmuStatus & CMU_STATUS_LFXOENS)     ? CMU_OSCENCMD_LFXOEN : 0);
00147 #if defined( _CMU_STATUS_USHFRCOENS_MASK )
00148   oscEnCmd |= ((cmuStatus & CMU_STATUS_USHFRCOENS)  ? CMU_OSCENCMD_USHFRCOEN : 0);
00149 #endif
00150   CMU->OSCENCMD = oscEnCmd;
00151 
00152   statusClkSelMask =
00153     (CMU_STATUS_HFRCOSEL |
00154      CMU_STATUS_HFXOSEL |
00155      CMU_STATUS_LFRCOSEL |
00156 #if defined( CMU_STATUS_USHFRCODIV2SEL )
00157      CMU_STATUS_USHFRCODIV2SEL |
00158 #endif
00159      CMU_STATUS_LFXOSEL);
00160 
00161   /* Restore oscillator used for clocking core */
00162   switch (cmuStatus & statusClkSelMask)
00163   {
00164   case CMU_STATUS_LFRCOSEL:
00165     /* Wait for LFRCO to stabilize */
00166     while (!(CMU->STATUS & CMU_STATUS_LFRCORDY))
00167       ;
00168     CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
00169     break;
00170 
00171   case CMU_STATUS_LFXOSEL:
00172     /* Wait for LFXO to stabilize */
00173     while (!(CMU->STATUS & CMU_STATUS_LFXORDY))
00174       ;
00175     CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
00176     break;
00177 
00178   case CMU_STATUS_HFXOSEL:
00179     /* Wait for HFXO to stabilize */
00180     while (!(CMU->STATUS & CMU_STATUS_HFXORDY))
00181       ;
00182     CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
00183     break;
00184 
00185 #if defined( CMU_STATUS_USHFRCODIV2SEL )
00186   case CMU_STATUS_USHFRCODIV2SEL:
00187     /* Wait for USHFRCO to stabilize */
00188     while (!(CMU->STATUS & CMU_STATUS_USHFRCORDY))
00189       ;
00190     CMU->CMD = _CMU_CMD_HFCLKSEL_USHFRCODIV2;
00191     break;
00192 #endif
00193 
00194   default: /* CMU_STATUS_HFRCOSEL */
00195     /* If core clock was HFRCO core clock, it is automatically restored to */
00196     /* state prior to entering energy mode. No need for further action. */
00197     break;
00198   }
00199 
00200   /* If HFRCO was disabled before entering Energy Mode, turn it off again */
00201   /* as it is automatically enabled by wake up */
00202   if ( ! (cmuStatus & CMU_STATUS_HFRCOENS) )
00203   {
00204     CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
00205   }
00206 
00207   /* Restore CMU register locking */
00208   if (cmuLocked)
00209   {
00210     CMU_Lock();
00211   }
00212 }
00213 
00214 
00215 /* Get enable conditions for errata EMU_E107 fix. */
00216 #if defined(ERRATA_FIX_EMU_E107_EN)
00217 static __INLINE bool getErrataFixEmuE107En(void)
00218 {
00219   /* SYSTEM_ChipRevisionGet could have been used here, but we would like a faster implementation in this case. */
00220   uint16_t majorMinorRev;
00221 
00222   /* CHIP MAJOR bit [3:0] */
00223   majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK) >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8);
00224   /* CHIP MINOR bit [7:4] */
00225   majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK) >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);
00226   /* CHIP MINOR bit [3:0] */
00227   majorMinorRev |=  ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK) >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
00228 
00229 #if defined(_EFM32_GECKO_FAMILY)
00230   return (majorMinorRev <= 0x0103);
00231 #elif defined(_EFM32_TINY_FAMILY)
00232   return (majorMinorRev <= 0x0102);
00233 #elif defined(_EFM32_GIANT_FAMILY)
00234   return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204);
00235 #elif defined(_EFM32_WONDER_FAMILY)
00236   return (majorMinorRev == 0x0100);
00237 #else
00238   /* Zero Gecko and future families are not affected by errata EMU_E107 */
00239   return false;
00240 #endif
00241 }
00242 #endif
00243 
00247 /*******************************************************************************
00248  **************************   GLOBAL FUNCTIONS   *******************************
00249  ******************************************************************************/
00250 
00251 /***************************************************************************/
00292 void EMU_EnterEM2(bool restore)
00293 {
00294 #if defined(ERRATA_FIX_EMU_E107_EN)
00295   bool errataFixEmuE107En;
00296   uint32_t nonWicIntEn[2];
00297 #endif
00298 
00299   /* Auto-update CMU status just in case before entering energy mode. */
00300   /* This variable is normally kept up-to-date by the CMU API. */
00301   cmuStatus = CMU->STATUS;
00302 
00303   /* Enter Cortex-M3 deep sleep mode */
00304   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00305 
00306   /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
00307      Disable the enabled non-WIC interrupts. */
00308 #if defined(ERRATA_FIX_EMU_E107_EN)
00309   errataFixEmuE107En = getErrataFixEmuE107En();
00310   if (errataFixEmuE107En)
00311   {
00312     nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
00313     NVIC->ICER[0] = nonWicIntEn[0];
00314 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
00315     nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
00316     NVIC->ICER[1] = nonWicIntEn[1];
00317 #endif
00318   }
00319 #endif
00320 
00321   __WFI();
00322 
00323   /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
00324 #if defined(ERRATA_FIX_EMU_E107_EN)
00325   if (errataFixEmuE107En)
00326   {
00327     NVIC->ISER[0] = nonWicIntEn[0];
00328 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
00329     NVIC->ISER[1] = nonWicIntEn[1];
00330 #endif
00331   }
00332 #endif
00333 
00334   /* Restore oscillators/clocks if specified */
00335   if (restore)
00336   {
00337     EMU_Restore();
00338   }
00339   /* If not restoring, and original clock was not HFRCO, we have to */
00340   /* update CMSIS core clock variable since core clock has changed */
00341   /* to using HFRCO. */
00342   else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
00343   {
00344     SystemCoreClockUpdate();
00345   }
00346 }
00347 
00348 
00349 /***************************************************************************/
00391 void EMU_EnterEM3(bool restore)
00392 {
00393   uint32_t cmuLocked;
00394 
00395 #if defined(ERRATA_FIX_EMU_E107_EN)
00396   bool errataFixEmuE107En;
00397   uint32_t nonWicIntEn[2];
00398 #endif
00399 
00400   /* Auto-update CMU status just in case before entering energy mode. */
00401   /* This variable is normally kept up-to-date by the CMU API. */
00402   cmuStatus = CMU->STATUS;
00403 
00404   /* CMU registers may be locked */
00405   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
00406   CMU_Unlock();
00407 
00408   /* Disable LF oscillators */
00409   CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
00410 
00411   /* Restore CMU register locking */
00412   if (cmuLocked)
00413   {
00414     CMU_Lock();
00415   }
00416 
00417   /* Enter Cortex-M3 deep sleep mode */
00418   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00419 
00420   /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
00421      Disable the enabled non-WIC interrupts. */
00422 #if defined(ERRATA_FIX_EMU_E107_EN)
00423   errataFixEmuE107En = getErrataFixEmuE107En();
00424   if (errataFixEmuE107En)
00425   {
00426     nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
00427     NVIC->ICER[0] = nonWicIntEn[0];
00428 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
00429     nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
00430     NVIC->ICER[1] = nonWicIntEn[1];
00431 #endif
00432 
00433   }
00434 #endif
00435 
00436   __WFI();
00437 
00438   /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
00439 #if defined(ERRATA_FIX_EMU_E107_EN)
00440   if (errataFixEmuE107En)
00441   {
00442     NVIC->ISER[0] = nonWicIntEn[0];
00443 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
00444     NVIC->ISER[1] = nonWicIntEn[1];
00445 #endif
00446   }
00447 #endif
00448 
00449   /* Restore oscillators/clocks if specified */
00450   if (restore)
00451   {
00452     EMU_Restore();
00453   }
00454   /* If not restoring, and original clock was not HFRCO, we have to */
00455   /* update CMSIS core clock variable since core clock has changed */
00456   /* to using HFRCO. */
00457   else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
00458   {
00459     SystemCoreClockUpdate();
00460   }
00461 }
00462 
00463 
00464 /***************************************************************************/
00471 void EMU_EnterEM4(void)
00472 {
00473   int i;
00474   uint32_t em4seq2;
00475   uint32_t em4seq3;
00476 
00477   em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK) | (2 << _EMU_CTRL_EM4CTRL_SHIFT);
00478   em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK) | (3 << _EMU_CTRL_EM4CTRL_SHIFT);
00479 
00480   /* Make sure register write lock is disabled */
00481   EMU_Unlock();
00482 
00483 #if defined(ERRATA_FIX_EMU_E108_EN)
00484   /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
00485   __disable_irq();
00486   *(volatile uint32_t *)0x400C80E4 = 0;
00487 #endif
00488 
00489   for (i = 0; i < 4; i++)
00490   {
00491     EMU->CTRL = em4seq2;
00492     EMU->CTRL = em4seq3;
00493   }
00494   EMU->CTRL = em4seq2;
00495 }
00496 
00497 
00498 /***************************************************************************/
00513 void EMU_MemPwrDown(uint32_t blocks)
00514 {
00515 #if defined(_EMU_MEMCTRL_RESETVALUE)
00516   EFM_ASSERT(blocks <= _EMU_MEMCTRL_MASK);
00517 
00518   EMU->MEMCTRL = blocks;
00519 #else
00520   (void)blocks;
00521 #endif
00522 }
00523 
00524 
00525 /***************************************************************************/
00544 void EMU_UpdateOscConfig(void)
00545 {
00546   /* Fetch current configuration */
00547   cmuStatus = CMU->STATUS;
00548 }
00549 
00550 
00551 #if defined( _EMU_CTRL_EMVREG_MASK ) || defined( _EMU_CTRL_EM23VREG_MASK )
00552 /***************************************************************************/
00559 void EMU_EM23Init(EMU_EM23Init_TypeDef *em23Init)
00560 {
00561 #if defined( _EMU_CTRL_EMVREG_MASK )
00562   EMU->CTRL = em23Init->em23Vreg ? (EMU->CTRL | EMU_CTRL_EMVREG) : (EMU->CTRL & ~EMU_CTRL_EMVREG);
00563 #elif defined( _EMU_CTRL_EM23VREG_MASK )
00564   EMU->CTRL = em23Init->em23Vreg ? (EMU->CTRL | EMU_CTRL_EM23VREG) : (EMU->CTRL & ~EMU_CTRL_EM23VREG);
00565 #endif
00566 }
00567 #endif
00568 
00569 
00570 #if defined( _EMU_EM4CONF_MASK )
00571 /***************************************************************************/
00578 void EMU_EM4Init(EMU_EM4Init_TypeDef *em4Init)
00579 {
00580   uint32_t em4conf = EMU->EM4CONF;
00581 
00582   /* Clear fields that will be reconfigured */
00583   em4conf &= ~(
00584     _EMU_EM4CONF_LOCKCONF_MASK |
00585     _EMU_EM4CONF_OSC_MASK |
00586     _EMU_EM4CONF_BURTCWU_MASK |
00587     _EMU_EM4CONF_VREGEN_MASK);
00588 
00589   /* Configure new settings */
00590   em4conf |= (
00591     (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT) |
00592     (em4Init->osc) |
00593     (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT) |
00594     (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT));
00595 
00596   /* Apply configuration. Note that lock can be set after this stage. */
00597   EMU->EM4CONF = em4conf;
00598 }
00599 #endif
00600 
00601 
00602 #if defined( BU_PRESENT )
00603 
00604 /***************************************************************************/
00611 void EMU_BUPDInit(EMU_BUPDInit_TypeDef *bupdInit)
00612 {
00613   uint32_t reg;
00614 
00615   /* Set power connection configuration */
00616   reg = EMU->PWRCONF & ~(
00617     _EMU_PWRCONF_PWRRES_MASK|
00618     _EMU_PWRCONF_VOUTSTRONG_MASK|
00619     _EMU_PWRCONF_VOUTMED_MASK|
00620     _EMU_PWRCONF_VOUTWEAK_MASK);
00621 
00622   reg |= (bupdInit->resistor|
00623          (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)|
00624          (bupdInit->voutMed    << _EMU_PWRCONF_VOUTMED_SHIFT)|
00625          (bupdInit->voutWeak   << _EMU_PWRCONF_VOUTWEAK_SHIFT));
00626 
00627   EMU->PWRCONF = reg;
00628 
00629   /* Set backup domain inactive mode configuration */
00630   reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
00631   reg |= (bupdInit->inactivePower);
00632   EMU->BUINACT = reg;
00633 
00634   /* Set backup domain active mode configuration */
00635   reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
00636   reg |= (bupdInit->activePower);
00637   EMU->BUACT = reg;
00638 
00639   /* Set power control configuration */
00640   reg = EMU->BUCTRL & ~(
00641     _EMU_BUCTRL_PROBE_MASK|
00642     _EMU_BUCTRL_BODCAL_MASK|
00643     _EMU_BUCTRL_STATEN_MASK|
00644     _EMU_BUCTRL_EN_MASK);
00645 
00646   /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and
00647      release reset */
00648   reg |= (bupdInit->probe|
00649          (bupdInit->bodCal          << _EMU_BUCTRL_BODCAL_SHIFT)|
00650          (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)|
00651          (bupdInit->enable          << _EMU_BUCTRL_EN_SHIFT));
00652 
00653   /* Enable configuration */
00654   EMU->BUCTRL = reg;
00655 
00656   /* If enable is true, enable BU_VIN input power pin, if not disable it  */
00657   EMU_BUPinEnable(bupdInit->enable);
00658 
00659   /* If enable is true, release BU reset, if not keep reset asserted */
00660   BITBAND_Peripheral(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
00661 }
00662 
00663 
00664 /***************************************************************************/
00672 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
00673 {
00674   EFM_ASSERT(value<=(_EMU_BUACT_BUEXTHRES_MASK>>_EMU_BUACT_BUEXTHRES_SHIFT));
00675 
00676   switch(mode)
00677   {
00678   case emuBODMode_Active:
00679     EMU->BUACT = (EMU->BUACT & ~(_EMU_BUACT_BUEXTHRES_MASK))|(value<<_EMU_BUACT_BUEXTHRES_SHIFT);
00680     break;
00681   case emuBODMode_Inactive:
00682     EMU->BUINACT = (EMU->BUINACT & ~(_EMU_BUINACT_BUENTHRES_MASK))|(value<<_EMU_BUINACT_BUENTHRES_SHIFT);
00683     break;
00684   }
00685 }
00686 
00687 
00688 /***************************************************************************/
00696 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
00697 {
00698   EFM_ASSERT(value<=(_EMU_BUACT_BUEXRANGE_MASK>>_EMU_BUACT_BUEXRANGE_SHIFT));
00699 
00700   switch(mode)
00701   {
00702   case emuBODMode_Active:
00703     EMU->BUACT = (EMU->BUACT & ~(_EMU_BUACT_BUEXRANGE_MASK))|(value<<_EMU_BUACT_BUEXRANGE_SHIFT);
00704     break;
00705   case emuBODMode_Inactive:
00706     EMU->BUINACT = (EMU->BUINACT & ~(_EMU_BUINACT_BUENRANGE_MASK))|(value<<_EMU_BUINACT_BUENRANGE_SHIFT);
00707     break;
00708   }
00709 }
00710 
00711 #endif
00712 
00713 
00716 #endif /* __EM_EMU_H */