EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
em_letimer.c
Go to the documentation of this file.
1 /***************************************************************************/
33 #include "em_letimer.h"
34 #if defined(LETIMER_COUNT) && (LETIMER_COUNT > 0)
35 #include "em_cmu.h"
36 #include "em_assert.h"
37 
38 /***************************************************************************/
43 /***************************************************************************/
53 /*******************************************************************************
54  ******************************* DEFINES ***********************************
55  ******************************************************************************/
56 
60 #define LETIMER_COMP_REG_VALID(reg) (((reg) <= 1))
61 
63 #define LETIMER_REF_VALID(ref) ((ref) == LETIMER0)
64 
66 #define LETIMER_REP_REG_VALID(reg) (((reg) <= 1))
67 
71 /*******************************************************************************
72  ************************** LOCAL FUNCTIONS ********************************
73  ******************************************************************************/
74 
77 #if defined(_EFM32_GECKO_FAMILY)
78 /***************************************************************************/
94 __STATIC_INLINE void regSync(LETIMER_TypeDef *letimer, uint32_t mask)
95 {
96 #if defined(_LETIMER_FREEZE_MASK)
97  /* Avoid deadlock if modifying the same register twice when freeze mode is */
98  /* activated. */
99  if (letimer->FREEZE & LETIMER_FREEZE_REGFREEZE)
100  return;
101 #endif
102 
103  /* Wait for any pending previous write operation to have been completed */
104  /* in low frequency domain, only required for Gecko Family of devices */
105  while (letimer->SYNCBUSY & mask)
106  ;
107 }
108 #endif
109 
112 /*******************************************************************************
113  ************************** GLOBAL FUNCTIONS *******************************
114  ******************************************************************************/
115 
116 /***************************************************************************/
129 uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp)
130 {
131  uint32_t ret;
132 
133  EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_COMP_REG_VALID(comp));
134 
135  /* Initialize selected compare value */
136  switch (comp)
137  {
138  case 0:
139  ret = letimer->COMP0;
140  break;
141 
142  case 1:
143  ret = letimer->COMP1;
144  break;
145 
146  default:
147  /* Unknown compare register selected */
148  ret = 0;
149  break;
150  }
151 
152  return(ret);
153 }
154 
155 
156 /***************************************************************************/
176 void LETIMER_CompareSet(LETIMER_TypeDef *letimer,
177  unsigned int comp,
178  uint32_t value)
179 {
180  volatile uint32_t *compReg;
181 
182  EFM_ASSERT(LETIMER_REF_VALID(letimer)
183  && LETIMER_COMP_REG_VALID(comp)
184  && ((value & ~(_LETIMER_COMP0_COMP0_MASK
185  >> _LETIMER_COMP0_COMP0_SHIFT))
186  == 0));
187 
188  /* Initialize selected compare value */
189  switch (comp)
190  {
191  case 0:
192  compReg = &(letimer->COMP0);
193  break;
194 
195  case 1:
196  compReg = &(letimer->COMP1);
197  break;
198 
199  default:
200  /* Unknown compare register selected, abort */
201  return;
202  }
203 
204 #if defined(_EFM32_GECKO_FAMILY)
205  /* LF register about to be modified require sync. busy check */
206  regSync(letimer, comp ? LETIMER_SYNCBUSY_COMP1 : LETIMER_SYNCBUSY_COMP0);
207 #endif
208 
209  *compReg = value;
210 }
211 
212 
213 /***************************************************************************/
231 void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable)
232 {
233  EFM_ASSERT(LETIMER_REF_VALID(letimer));
234 
235 #if defined(_EFM32_GECKO_FAMILY)
236  /* LF register about to be modified require sync. busy check */
237  regSync(letimer, LETIMER_SYNCBUSY_CMD);
238 #endif
239 
240  if (enable)
241  {
242  letimer->CMD = LETIMER_CMD_START;
243  }
244  else
245  {
246  letimer->CMD = LETIMER_CMD_STOP;
247  }
248 }
249 
250 #if defined(_LETIMER_FREEZE_MASK)
251 /***************************************************************************/
278 void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable)
279 {
280  if (enable)
281  {
282  /*
283  * Wait for any ongoing LF synchronization to complete. This is just to
284  * protect against the rare case when a user
285  * - modifies a register requiring LF sync
286  * - then enables freeze before LF sync completed
287  * - then modifies the same register again
288  * since modifying a register while it is in sync progress should be
289  * avoided.
290  */
291  while (letimer->SYNCBUSY)
292  ;
293 
294  letimer->FREEZE = LETIMER_FREEZE_REGFREEZE;
295  }
296  else
297  {
298  letimer->FREEZE = 0;
299  }
300 }
301 #endif /* defined(_LETIMER_FREEZE_MASK) */
302 
303 /***************************************************************************/
327 void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init)
328 {
329  uint32_t tmp = 0;
330 
331  EFM_ASSERT(LETIMER_REF_VALID(letimer));
332 
333  /* Stop timer if specified to be disabled and running */
334  if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING))
335  {
336 #if defined(_EFM32_GECKO_FAMILY)
337  /* LF register about to be modified require sync. busy check */
338  regSync(letimer, LETIMER_SYNCBUSY_CMD);
339 #endif
340  letimer->CMD = LETIMER_CMD_STOP;
341  }
342 
343  /* Configure DEBUGRUN flag, sets whether or not counter should be
344  * updated when debugger is active */
345  if (init->debugRun)
346  {
347  tmp |= LETIMER_CTRL_DEBUGRUN;
348  }
349 
350 #if defined(LETIMER_CTRL_RTCC0TEN)
351  if (init->rtcComp0Enable)
352  {
353  tmp |= LETIMER_CTRL_RTCC0TEN;
354  }
355 
356  if (init->rtcComp1Enable)
357  {
358  tmp |= LETIMER_CTRL_RTCC1TEN;
359  }
360 #endif
361 
362  if (init->comp0Top)
363  {
364  tmp |= LETIMER_CTRL_COMP0TOP;
365  }
366 
367  if (init->bufTop)
368  {
369  tmp |= LETIMER_CTRL_BUFTOP;
370  }
371 
372  if (init->out0Pol)
373  {
374  tmp |= LETIMER_CTRL_OPOL0;
375  }
376 
377  if (init->out1Pol)
378  {
379  tmp |= LETIMER_CTRL_OPOL1;
380  }
381 
382  tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT;
383  tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT;
384  tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT;
385 
386 #if defined(_EFM32_GECKO_FAMILY)
387  /* LF register about to be modified require sync. busy check */
388  regSync(letimer, LETIMER_SYNCBUSY_CTRL);
389 #endif
390  letimer->CTRL = tmp;
391 
392  /* Start timer if specified to be enabled and not already running */
393  if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING))
394  {
395 #if defined(_EFM32_GECKO_FAMILY)
396  /* LF register about to be modified require sync. busy check */
397  regSync(letimer, LETIMER_SYNCBUSY_CMD);
398 #endif
399  letimer->CMD = LETIMER_CMD_START;
400  }
401 }
402 
403 
404 /***************************************************************************/
417 uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep)
418 {
419  uint32_t ret;
420 
421  EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_REP_REG_VALID(rep));
422 
423  /* Initialize selected compare value */
424  switch (rep)
425  {
426  case 0:
427  ret = letimer->REP0;
428  break;
429 
430  case 1:
431  ret = letimer->REP1;
432  break;
433 
434  default:
435  /* Unknown compare register selected */
436  ret = 0;
437  break;
438  }
439 
440  return(ret);
441 }
442 
443 
444 /***************************************************************************/
464 void LETIMER_RepeatSet(LETIMER_TypeDef *letimer,
465  unsigned int rep,
466  uint32_t value)
467 {
468  volatile uint32_t *repReg;
469 #if defined(_EFM32_GECKO_FAMILY)
470  uint32_t syncbusy;
471 #endif
472  EFM_ASSERT(LETIMER_REF_VALID(letimer)
473  && LETIMER_REP_REG_VALID(rep)
474  && ((value & ~(_LETIMER_REP0_REP0_MASK
475  >> _LETIMER_REP0_REP0_SHIFT))
476  == 0));
477 
478  /* Initialize selected compare value */
479  switch (rep)
480  {
481  case 0:
482  repReg = &(letimer->REP0);
483 #if defined(_EFM32_GECKO_FAMILY)
484  syncbusy = LETIMER_SYNCBUSY_REP0;
485 #endif
486  break;
487 
488  case 1:
489  repReg = &(letimer->REP1);
490 #if defined(_EFM32_GECKO_FAMILY)
491  syncbusy = LETIMER_SYNCBUSY_REP1;
492 #endif
493  break;
494 
495  default:
496  /* Unknown compare register selected, abort */
497  return;
498  }
499 
500 #if defined(_EFM32_GECKO_FAMILY)
501  /* LF register about to be modified require sync. busy check */
502  regSync(letimer, syncbusy);
503 #endif
504 
505  *repReg = value;
506 }
507 
508 
509 /***************************************************************************/
520 void LETIMER_Reset(LETIMER_TypeDef *letimer)
521 {
522 #if defined(_LETIMER_FREEZE_MASK)
523  /* Freeze registers to avoid stalling for LF synchronization */
524  LETIMER_FreezeEnable(letimer, true);
525 #endif
526 
527  /* Make sure disabled first, before resetting other registers */
528  letimer->CMD = LETIMER_CMD_STOP | LETIMER_CMD_CLEAR
529  | LETIMER_CMD_CTO0 | LETIMER_CMD_CTO1;
530  letimer->CTRL = _LETIMER_CTRL_RESETVALUE;
531  letimer->COMP0 = _LETIMER_COMP0_RESETVALUE;
532  letimer->COMP1 = _LETIMER_COMP1_RESETVALUE;
533  letimer->REP0 = _LETIMER_REP0_RESETVALUE;
534  letimer->REP1 = _LETIMER_REP1_RESETVALUE;
535  letimer->IEN = _LETIMER_IEN_RESETVALUE;
536  letimer->IFC = _LETIMER_IFC_MASK;
537  /* Do not reset route register, setting should be done independently */
538 
539 #if defined(_LETIMER_FREEZE_MASK)
540  /* Unfreeze registers, pass new settings on to LETIMER */
541  LETIMER_FreezeEnable(letimer, false);
542 #endif
543 }
544 
545 
548 #endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */
Clock management unit (CMU) API.
Emlib peripheral API "assert" implementation.
Low Energy Timer (LETIMER) peripheral API.