em_burtc.c

Go to the documentation of this file.
00001 /***************************************************************************/
00034 #include "em_device.h"
00035 #if defined(BURTC_PRESENT)
00036 #include "em_burtc.h"
00037 
00038 #include "em_assert.h"
00039 #include "em_bitband.h"
00040 
00041 /***************************************************************************/
00046 /***************************************************************************/
00052 /*******************************************************************************
00053  *******************************   DEFINES   ***********************************
00054  ******************************************************************************/
00055 
00056 /*******************************************************************************
00057  **************************   LOCAL FUNCTIONS   ********************************
00058  ******************************************************************************/
00059 
00060 /***************************************************************************/
00066 __STATIC_INLINE uint32_t BURTC_DivToLog2(uint32_t div)
00067 {
00068   uint32_t log2;
00069 
00070   /* Prescaler accepts an argument of 128 or less, valid values being 2^n */
00071   EFM_ASSERT((div > 0) && (div <= 32768));
00072 
00073   /* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic */
00074   log2 = (31 - __CLZ(div));
00075 
00076   return log2;
00077 }
00078 
00079 
00080 /***************************************************************************/
00088 __STATIC_INLINE void BURTC_Sync(uint32_t mask)
00089 {
00090   /* Avoid deadlock if modifying the same register twice when freeze mode is */
00091   /* activated. */
00092   if (BURTC->FREEZE & BURTC_FREEZE_REGFREEZE)
00093     return;
00094 
00095   /* Wait for any pending previous write operation to have been completed */
00096   /* in low frequency domain. This is only required for the Gecko Family */
00097   while (BURTC->SYNCBUSY & mask)
00098     ;
00099 }
00100 
00101 
00102 /*******************************************************************************
00103  **************************   GLOBAL FUNCTIONS   *******************************
00104  ******************************************************************************/
00105 
00106 /***************************************************************************/
00124 void BURTC_Init(const BURTC_Init_TypeDef *burtcInit)
00125 {
00126   uint32_t ctrl;
00127   uint32_t presc;
00128 
00129   /* Check initializer structure integrity */
00130   EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0);
00131   /* Clock divider must be between 1 and 128, really on the form 2^n */
00132   EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128));
00133   /* Ignored compare bits during low power operation must be less than 7 */
00134   /* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7 */
00135   EFM_ASSERT(burtcInit->lowPowerComp <= 6);
00136   /* You cannot enable the BURTC if mode is set to disabled */
00137   EFM_ASSERT((burtcInit->enable == false) ||
00138              ((burtcInit->enable == true) && (burtcInit->mode != burtcModeDisable)));
00139   /* Low power mode is only available with LFRCO or LFXO as clock source */
00140   EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO) ||
00141              ((burtcInit->clkSel == burtcClkSelULFRCO) && (burtcInit->lowPowerMode == burtcLPDisable)));
00142 
00143   /* Calculate prescaler value from clock divider input */
00144   /* Note! If clock select (clkSel) is ULFRCO, a clock divisor (clkDiv) of
00145      value 1 will select a 2kHz ULFRCO clock, while any other value will
00146      select a 1kHz ULFRCO clock source. */
00147   presc = BURTC_DivToLog2(burtcInit->clkDiv);
00148 
00149   /* Make sure all registers are updated simultaneously */
00150   if (burtcInit->enable)
00151   {
00152     BURTC_FreezeEnable(true);
00153   }
00154 
00155   /* Modification of LPMODE register requires sync with potential ongoing
00156    * register updates in LF domain. */
00157   BURTC_Sync(BURTC_SYNCBUSY_LPMODE);
00158 
00159   /* Configure low power mode */
00160   BURTC->LPMODE = (uint32_t) (burtcInit->lowPowerMode);
00161 
00162   /* New configuration */
00163   ctrl = ((BURTC_CTRL_RSTEN) |
00164           (burtcInit->mode) |
00165           (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT) |
00166           (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT) |
00167           (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT) |
00168           (presc << _BURTC_CTRL_PRESC_SHIFT) |
00169           (burtcInit->clkSel) |
00170           (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT));
00171 
00172   /* Clear interrupts */
00173   BURTC->IFC = 0xFFFFFFFF;
00174 
00175   /* Set new configuration */
00176   BURTC->CTRL = ctrl;
00177 
00178   /* Enable BURTC and counter */
00179   if (burtcInit->enable)
00180   {
00181     /* To enable BURTC counter, we need to disable reset */
00182     BURTC_Enable(true);
00183 
00184     /* Clear freeze */
00185     BURTC_FreezeEnable(false);
00186   }
00187 }
00188 
00189 
00190 /***************************************************************************/
00197 void BURTC_CompareSet(unsigned int comp, uint32_t value)
00198 {
00199   (void) comp;  /* Unused parameter when EFM_ASSERT is undefined. */
00200 
00201   EFM_ASSERT(comp == 0);
00202 
00203   /* Modification of COMP0 register requires sync with potential ongoing
00204    * register updates in LF domain. */
00205   BURTC_Sync(BURTC_SYNCBUSY_COMP0);
00206 
00207   /* Configure compare channel 0 */
00208   BURTC->COMP0 = value;
00209 }
00210 
00211 
00212 /***************************************************************************/
00219 uint32_t BURTC_CompareGet(unsigned int comp)
00220 {
00221   (void) comp;  /* Unused parameter when EFM_ASSERT is undefined. */
00222 
00223   EFM_ASSERT(comp == 0);
00224 
00225   return BURTC->COMP0;
00226 }
00227 
00228 
00229 /***************************************************************************/
00232 void BURTC_CounterReset(void)
00233 {
00234   /* Set and clear reset bit */
00235   BITBAND_Peripheral(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1);
00236   BITBAND_Peripheral(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 0);
00237 }
00238 
00239 
00240 /***************************************************************************/
00248 void BURTC_Reset(void)
00249 {
00250   /* Verify RMU BURSTEN is disabled */
00251   EFM_ASSERT((RMU->CTRL & RMU_CTRL_BURSTEN) == 0);
00252 
00253   /* Restore all essential BURTC registers to default config */
00254   BURTC->IEN      = _BURTC_IEN_RESETVALUE;
00255   /* Modification of LPMODE register requires sync with potential ongoing
00256    * register updates in LF domain. */
00257   BURTC_Sync(BURTC_SYNCBUSY_LPMODE);
00258   BURTC->LPMODE   = _BURTC_LPMODE_RESETVALUE;
00259   BURTC->LFXOFDET = _BURTC_LFXOFDET_RESETVALUE;
00260   /* Modification of COMP0 register requires sync with potential ongoing
00261    * register updates in LF domain. */
00262   BURTC_Sync(BURTC_SYNCBUSY_COMP0);
00263   BURTC->COMP0    = _BURTC_COMP0_RESETVALUE;
00264   BURTC->FREEZE   = _BURTC_FREEZE_RESETVALUE;
00265   /* We must wait for SYNCBUSY before resetting the CTRL register. */
00266   BURTC_Sync(BURTC_SYNCBUSY_LPMODE | BURTC_SYNCBUSY_COMP0);
00267   BURTC->CTRL     = _BURTC_CTRL_RESETVALUE;
00268 }
00269 
00270 
00271 /***************************************************************************/
00278 uint32_t BURTC_ClockFreqGet(void)
00279 {
00280   uint32_t clkSel;
00281   uint32_t clkDiv;
00282   uint32_t frequency;
00283 
00284   clkSel = BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK;
00285   clkDiv = (BURTC->CTRL & _BURTC_CTRL_PRESC_MASK) >> _BURTC_CTRL_PRESC_SHIFT;
00286 
00287   switch (clkSel)
00288   {
00290   case BURTC_CTRL_CLKSEL_ULFRCO:
00291     if (_BURTC_CTRL_PRESC_DIV1 == clkDiv)
00292     {
00293       frequency = 2000;     /* 2KHz when clock divisor is 1. */
00294     }
00295     else
00296     {
00297       frequency = SystemULFRCOClockGet();  /* 1KHz when divisor is different
00298                                               from 1. */
00299     }
00300     break;
00301 
00303   case BURTC_CTRL_CLKSEL_LFRCO:
00304     frequency = SystemLFRCOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */
00305     break;
00306 
00308   case BURTC_CTRL_CLKSEL_LFXO:
00309     frequency = SystemLFXOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */
00310     break;
00311 
00312   default:
00313     /* No clock selected for BURTC. */
00314     frequency = 0;
00315   }
00316 
00317   return frequency;
00318 }
00319 
00320 
00324 #endif /* BURTC_PRESENT */