em_letimer.c

Go to the documentation of this file.
00001 /***************************************************************************/
00034 #include "em_letimer.h"
00035 #if defined(LETIMER_COUNT) && (LETIMER_COUNT > 0)
00036 #include "em_cmu.h"
00037 #include "em_assert.h"
00038 
00039 /***************************************************************************/
00044 /***************************************************************************/
00050 /*******************************************************************************
00051  *******************************   DEFINES   ***********************************
00052  ******************************************************************************/
00053 
00057 #define LETIMER_COMP_REG_VALID(reg)    (((reg) <= 1))
00058 
00060 #define LETIMER_REF_VALID(ref)         ((ref) == LETIMER0)
00061 
00063 #define LETIMER_REP_REG_VALID(reg)     (((reg) <= 1))
00064 
00068 /*******************************************************************************
00069  **************************   LOCAL FUNCTIONS   ********************************
00070  ******************************************************************************/
00071 
00074 #if defined(_EFM32_GECKO_FAMILY)
00075 /***************************************************************************/
00091 __STATIC_INLINE void LETIMER_Sync(LETIMER_TypeDef *letimer, uint32_t mask)
00092 {
00093   /* Avoid deadlock if modifying the same register twice when freeze mode is */
00094   /* activated. */
00095   if (letimer->FREEZE & LETIMER_FREEZE_REGFREEZE)
00096     return;
00097 
00098   /* Wait for any pending previous write operation to have been completed */
00099   /* in low frequency domain, only required for Gecko Family of devices  */
00100   while (letimer->SYNCBUSY & mask)
00101     ;
00102 }
00103 #endif
00104 
00107 /*******************************************************************************
00108  **************************   GLOBAL FUNCTIONS   *******************************
00109  ******************************************************************************/
00110 
00111 /***************************************************************************/
00124 uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp)
00125 {
00126   uint32_t ret;
00127 
00128   EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_COMP_REG_VALID(comp));
00129 
00130   /* Initialize selected compare value */
00131   switch (comp)
00132   {
00133   case 0:
00134     ret = letimer->COMP0;
00135     break;
00136 
00137   case 1:
00138     ret = letimer->COMP1;
00139     break;
00140 
00141   default:
00142     /* Unknown compare register selected */
00143     ret = 0;
00144     break;
00145   }
00146 
00147   return(ret);
00148 }
00149 
00150 
00151 /***************************************************************************/
00171 void LETIMER_CompareSet(LETIMER_TypeDef *letimer,
00172                         unsigned int comp,
00173                         uint32_t value)
00174 {
00175   volatile uint32_t *compReg;
00176 
00177   EFM_ASSERT(LETIMER_REF_VALID(letimer) &&
00178              LETIMER_COMP_REG_VALID(comp) &&
00179              ((value & ~(_LETIMER_COMP0_COMP0_MASK >> _LETIMER_COMP0_COMP0_SHIFT)) == 0));
00180 
00181   /* Initialize selected compare value */
00182   switch (comp)
00183   {
00184   case 0:
00185     compReg  = &(letimer->COMP0);
00186     break;
00187 
00188   case 1:
00189     compReg  = &(letimer->COMP1);
00190     break;
00191 
00192   default:
00193     /* Unknown compare register selected, abort */
00194     return;
00195   }
00196 
00197 #if defined(_EFM32_GECKO_FAMILY)
00198   /* LF register about to be modified require sync. busy check */
00199   LETIMER_Sync(letimer, comp ? LETIMER_SYNCBUSY_COMP1 : LETIMER_SYNCBUSY_COMP0);
00200 #endif
00201 
00202   *compReg = value;
00203 }
00204 
00205 
00206 /***************************************************************************/
00224 void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable)
00225 {
00226   EFM_ASSERT(LETIMER_REF_VALID(letimer));
00227 
00228 #if defined(_EFM32_GECKO_FAMILY)
00229   /* LF register about to be modified require sync. busy check */
00230   LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CMD);
00231 #endif
00232 
00233   if (enable)
00234   {
00235     letimer->CMD = LETIMER_CMD_START;
00236   }
00237   else
00238   {
00239     letimer->CMD = LETIMER_CMD_STOP;
00240   }
00241 }
00242 
00243 
00244 /***************************************************************************/
00271 void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable)
00272 {
00273   if (enable)
00274   {
00275     /*
00276      * Wait for any ongoing LF synchronization to complete. This is just to
00277      * protect against the rare case when a user
00278      * - modifies a register requiring LF sync
00279      * - then enables freeze before LF sync completed
00280      * - then modifies the same register again
00281      * since modifying a register while it is in sync progress should be
00282      * avoided.
00283      */
00284     while (letimer->SYNCBUSY)
00285       ;
00286 
00287     letimer->FREEZE = LETIMER_FREEZE_REGFREEZE;
00288   }
00289   else
00290   {
00291     letimer->FREEZE = 0;
00292   }
00293 }
00294 
00295 
00296 /***************************************************************************/
00320 void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init)
00321 {
00322   uint32_t tmp = 0;
00323 
00324   EFM_ASSERT(LETIMER_REF_VALID(letimer));
00325 
00326   /* Stop timer if specified to be disabled and running */
00327   if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING))
00328   {
00329 #if defined(_EFM32_GECKO_FAMILY)
00330     /* LF register about to be modified require sync. busy check */
00331     LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CMD);
00332 #endif
00333     letimer->CMD = LETIMER_CMD_STOP;
00334   }
00335 
00336   /* Configure DEBUGRUN flag, sets whether or not counter should be
00337    * updated when debugger is active */
00338   if (init->debugRun)
00339   {
00340     tmp |= LETIMER_CTRL_DEBUGRUN;
00341   }
00342 
00343   if (init->rtcComp0Enable)
00344   {
00345     tmp |= LETIMER_CTRL_RTCC0TEN;
00346   }
00347 
00348   if (init->rtcComp1Enable)
00349   {
00350     tmp |= LETIMER_CTRL_RTCC1TEN;
00351   }
00352 
00353   if (init->comp0Top)
00354   {
00355     tmp |= LETIMER_CTRL_COMP0TOP;
00356   }
00357 
00358   if (init->bufTop)
00359   {
00360     tmp |= LETIMER_CTRL_BUFTOP;
00361   }
00362 
00363   if (init->out0Pol)
00364   {
00365     tmp |= LETIMER_CTRL_OPOL0;
00366   }
00367 
00368   if (init->out1Pol)
00369   {
00370     tmp |= LETIMER_CTRL_OPOL1;
00371   }
00372 
00373   tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT;
00374   tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT;
00375   tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT;
00376 
00377 #if defined(_EFM32_GECKO_FAMILY)
00378   /* LF register about to be modified require sync. busy check */
00379   LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CTRL);
00380 #endif
00381   letimer->CTRL = tmp;
00382 
00383   /* Start timer if specified to be enabled and not already running */
00384   if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING))
00385   {
00386 #if defined(_EFM32_GECKO_FAMILY)
00387     /* LF register about to be modified require sync. busy check */
00388     LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CMD);
00389 #endif
00390     letimer->CMD = LETIMER_CMD_START;
00391   }
00392 }
00393 
00394 
00395 /***************************************************************************/
00408 uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep)
00409 {
00410   uint32_t ret;
00411 
00412   EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_REP_REG_VALID(rep));
00413 
00414   /* Initialize selected compare value */
00415   switch (rep)
00416   {
00417   case 0:
00418     ret = letimer->REP0;
00419     break;
00420 
00421   case 1:
00422     ret = letimer->REP1;
00423     break;
00424 
00425   default:
00426     /* Unknown compare register selected */
00427     ret = 0;
00428     break;
00429   }
00430 
00431   return(ret);
00432 }
00433 
00434 
00435 /***************************************************************************/
00455 void LETIMER_RepeatSet(LETIMER_TypeDef *letimer,
00456                        unsigned int rep,
00457                        uint32_t value)
00458 {
00459   volatile uint32_t *repReg;
00460 #if defined(_EFM32_GECKO_FAMILY)
00461   uint32_t          syncbusy;
00462 #endif
00463   EFM_ASSERT(LETIMER_REF_VALID(letimer) &&
00464              LETIMER_REP_REG_VALID(rep) &&
00465              ((value & ~(_LETIMER_REP0_REP0_MASK >> _LETIMER_REP0_REP0_SHIFT)) == 0));
00466 
00467   /* Initialize selected compare value */
00468   switch (rep)
00469   {
00470   case 0:
00471     repReg = &(letimer->REP0);
00472 #if defined(_EFM32_GECKO_FAMILY)
00473     syncbusy = LETIMER_SYNCBUSY_REP0;
00474 #endif
00475     break;
00476 
00477   case 1:
00478     repReg = &(letimer->REP1);
00479 #if defined(_EFM32_GECKO_FAMILY)
00480     syncbusy = LETIMER_SYNCBUSY_REP1;
00481 #endif
00482     break;
00483 
00484   default:
00485     /* Unknown compare register selected, abort */
00486     return;
00487   }
00488 
00489 #if defined(_EFM32_GECKO_FAMILY)
00490   /* LF register about to be modified require sync. busy check */
00491   LETIMER_Sync(letimer, syncbusy);
00492 #endif
00493 
00494   *repReg = value;
00495 }
00496 
00497 
00498 /***************************************************************************/
00509 void LETIMER_Reset(LETIMER_TypeDef *letimer)
00510 {
00511   /* Freeze registers to avoid stalling for LF synchronization */
00512   LETIMER_FreezeEnable(letimer, true);
00513 
00514   /* Make sure disabled first, before resetting other registers */
00515   letimer->CMD = LETIMER_CMD_STOP | LETIMER_CMD_CLEAR |
00516                  LETIMER_CMD_CTO0 | LETIMER_CMD_CTO1;
00517   letimer->CTRL  = _LETIMER_CTRL_RESETVALUE;
00518   letimer->COMP0 = _LETIMER_COMP0_RESETVALUE;
00519   letimer->COMP1 = _LETIMER_COMP1_RESETVALUE;
00520   letimer->REP0  = _LETIMER_REP0_RESETVALUE;
00521   letimer->REP1  = _LETIMER_REP1_RESETVALUE;
00522   letimer->IEN   = _LETIMER_IEN_RESETVALUE;
00523   letimer->IFC   = _LETIMER_IFC_MASK;
00524   /* Do not reset route register, setting should be done independently */
00525 
00526   /* Unfreeze registers, pass new settings on to LETIMER */
00527   LETIMER_FreezeEnable(letimer, false);
00528 }
00529 
00530 
00533 #endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */