EFM32 Pearl Gecko Software Documentation  efm32pg1-doc-4.2.1
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 /***************************************************************************/
49 /*******************************************************************************
50  ******************************* DEFINES ***********************************
51  ******************************************************************************/
52 
56 #define LETIMER_COMP_REG_VALID(reg) (((reg) <= 1))
57 
59 #define LETIMER_REF_VALID(ref) ((ref) == LETIMER0)
60 
62 #define LETIMER_REP_REG_VALID(reg) (((reg) <= 1))
63 
67 /*******************************************************************************
68  ************************** LOCAL FUNCTIONS ********************************
69  ******************************************************************************/
70 
73 #if defined(_EFM32_GECKO_FAMILY)
74 /***************************************************************************/
90 __STATIC_INLINE void regSync(LETIMER_TypeDef *letimer, uint32_t mask)
91 {
92 #if defined(_LETIMER_FREEZE_MASK)
93  /* Avoid deadlock if modifying the same register twice when freeze mode is */
94  /* activated. */
95  if (letimer->FREEZE & LETIMER_FREEZE_REGFREEZE)
96  return;
97 #endif
98 
99  /* Wait for any pending previous write operation to have been completed */
100  /* in low frequency domain, only required for Gecko Family of devices */
101  while (letimer->SYNCBUSY & mask)
102  ;
103 }
104 #endif
105 
108 /*******************************************************************************
109  ************************** GLOBAL FUNCTIONS *******************************
110  ******************************************************************************/
111 
112 /***************************************************************************/
125 uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp)
126 {
127  uint32_t ret;
128 
129  EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_COMP_REG_VALID(comp));
130 
131  /* Initialize selected compare value */
132  switch (comp)
133  {
134  case 0:
135  ret = letimer->COMP0;
136  break;
137 
138  case 1:
139  ret = letimer->COMP1;
140  break;
141 
142  default:
143  /* Unknown compare register selected */
144  ret = 0;
145  break;
146  }
147 
148  return(ret);
149 }
150 
151 
152 /***************************************************************************/
173  unsigned int comp,
174  uint32_t value)
175 {
176  volatile uint32_t *compReg;
177 
178  EFM_ASSERT(LETIMER_REF_VALID(letimer)
179  && LETIMER_COMP_REG_VALID(comp)
180  && ((value & ~(_LETIMER_COMP0_COMP0_MASK
182  == 0));
183 
184  /* Initialize selected compare value */
185  switch (comp)
186  {
187  case 0:
188  compReg = &(letimer->COMP0);
189  break;
190 
191  case 1:
192  compReg = &(letimer->COMP1);
193  break;
194 
195  default:
196  /* Unknown compare register selected, abort */
197  return;
198  }
199 
200 #if defined(_EFM32_GECKO_FAMILY)
201  /* LF register about to be modified require sync. busy check */
202  regSync(letimer, comp ? LETIMER_SYNCBUSY_COMP1 : LETIMER_SYNCBUSY_COMP0);
203 #endif
204 
205  *compReg = value;
206 }
207 
208 
209 /***************************************************************************/
227 void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable)
228 {
229  EFM_ASSERT(LETIMER_REF_VALID(letimer));
230 
231 #if defined(_EFM32_GECKO_FAMILY)
232  /* LF register about to be modified require sync. busy check */
233  regSync(letimer, LETIMER_SYNCBUSY_CMD);
234 #endif
235 
236  if (enable)
237  {
238  letimer->CMD = LETIMER_CMD_START;
239  }
240  else
241  {
242  letimer->CMD = LETIMER_CMD_STOP;
243  }
244 }
245 
246 #if defined(_LETIMER_FREEZE_MASK)
247 /***************************************************************************/
274 void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable)
275 {
276  if (enable)
277  {
278  /*
279  * Wait for any ongoing LF synchronization to complete. This is just to
280  * protect against the rare case when a user
281  * - modifies a register requiring LF sync
282  * - then enables freeze before LF sync completed
283  * - then modifies the same register again
284  * since modifying a register while it is in sync progress should be
285  * avoided.
286  */
287  while (letimer->SYNCBUSY)
288  ;
289 
290  letimer->FREEZE = LETIMER_FREEZE_REGFREEZE;
291  }
292  else
293  {
294  letimer->FREEZE = 0;
295  }
296 }
297 #endif /* defined(_LETIMER_FREEZE_MASK) */
298 
299 /***************************************************************************/
324 {
325  uint32_t tmp = 0;
326 
327  EFM_ASSERT(LETIMER_REF_VALID(letimer));
328 
329  /* Stop timer if specified to be disabled and running */
330  if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING))
331  {
332 #if defined(_EFM32_GECKO_FAMILY)
333  /* LF register about to be modified require sync. busy check */
334  regSync(letimer, LETIMER_SYNCBUSY_CMD);
335 #endif
336  letimer->CMD = LETIMER_CMD_STOP;
337  }
338 
339  /* Configure DEBUGRUN flag, sets whether or not counter should be
340  * updated when debugger is active */
341  if (init->debugRun)
342  {
343  tmp |= LETIMER_CTRL_DEBUGRUN;
344  }
345 
346 #if defined(LETIMER_CTRL_RTCC0TEN)
347  if (init->rtcComp0Enable)
348  {
349  tmp |= LETIMER_CTRL_RTCC0TEN;
350  }
351 
352  if (init->rtcComp1Enable)
353  {
354  tmp |= LETIMER_CTRL_RTCC1TEN;
355  }
356 #endif
357 
358  if (init->comp0Top)
359  {
360  tmp |= LETIMER_CTRL_COMP0TOP;
361  }
362 
363  if (init->bufTop)
364  {
365  tmp |= LETIMER_CTRL_BUFTOP;
366  }
367 
368  if (init->out0Pol)
369  {
370  tmp |= LETIMER_CTRL_OPOL0;
371  }
372 
373  if (init->out1Pol)
374  {
375  tmp |= LETIMER_CTRL_OPOL1;
376  }
377 
378  tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT;
379  tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT;
380  tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT;
381 
382 #if defined(_EFM32_GECKO_FAMILY)
383  /* LF register about to be modified require sync. busy check */
384  regSync(letimer, LETIMER_SYNCBUSY_CTRL);
385 #endif
386  letimer->CTRL = tmp;
387 
388  /* Start timer if specified to be enabled and not already running */
389  if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING))
390  {
391 #if defined(_EFM32_GECKO_FAMILY)
392  /* LF register about to be modified require sync. busy check */
393  regSync(letimer, LETIMER_SYNCBUSY_CMD);
394 #endif
395  letimer->CMD = LETIMER_CMD_START;
396  }
397 }
398 
399 
400 /***************************************************************************/
413 uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep)
414 {
415  uint32_t ret;
416 
417  EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_REP_REG_VALID(rep));
418 
419  /* Initialize selected compare value */
420  switch (rep)
421  {
422  case 0:
423  ret = letimer->REP0;
424  break;
425 
426  case 1:
427  ret = letimer->REP1;
428  break;
429 
430  default:
431  /* Unknown compare register selected */
432  ret = 0;
433  break;
434  }
435 
436  return(ret);
437 }
438 
439 
440 /***************************************************************************/
461  unsigned int rep,
462  uint32_t value)
463 {
464  volatile uint32_t *repReg;
465 #if defined(_EFM32_GECKO_FAMILY)
466  uint32_t syncbusy;
467 #endif
468  EFM_ASSERT(LETIMER_REF_VALID(letimer)
469  && LETIMER_REP_REG_VALID(rep)
470  && ((value & ~(_LETIMER_REP0_REP0_MASK
472  == 0));
473 
474  /* Initialize selected compare value */
475  switch (rep)
476  {
477  case 0:
478  repReg = &(letimer->REP0);
479 #if defined(_EFM32_GECKO_FAMILY)
480  syncbusy = LETIMER_SYNCBUSY_REP0;
481 #endif
482  break;
483 
484  case 1:
485  repReg = &(letimer->REP1);
486 #if defined(_EFM32_GECKO_FAMILY)
487  syncbusy = LETIMER_SYNCBUSY_REP1;
488 #endif
489  break;
490 
491  default:
492  /* Unknown compare register selected, abort */
493  return;
494  }
495 
496 #if defined(_EFM32_GECKO_FAMILY)
497  /* LF register about to be modified require sync. busy check */
498  regSync(letimer, syncbusy);
499 #endif
500 
501  *repReg = value;
502 }
503 
504 
505 /***************************************************************************/
517 {
518 #if defined(_LETIMER_FREEZE_MASK)
519  /* Freeze registers to avoid stalling for LF synchronization */
520  LETIMER_FreezeEnable(letimer, true);
521 #endif
522 
523  /* Make sure disabled first, before resetting other registers */
526  letimer->CTRL = _LETIMER_CTRL_RESETVALUE;
527  letimer->COMP0 = _LETIMER_COMP0_RESETVALUE;
528  letimer->COMP1 = _LETIMER_COMP1_RESETVALUE;
529  letimer->REP0 = _LETIMER_REP0_RESETVALUE;
530  letimer->REP1 = _LETIMER_REP1_RESETVALUE;
531  letimer->IEN = _LETIMER_IEN_RESETVALUE;
532  letimer->IFC = _LETIMER_IFC_MASK;
533  /* Do not reset route register, setting should be done independently */
534 
535 #if defined(_LETIMER_FREEZE_MASK)
536  /* Unfreeze registers, pass new settings on to LETIMER */
537  LETIMER_FreezeEnable(letimer, false);
538 #endif
539 }
540 
541 
544 #endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */
Clock management unit (CMU) API.
void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable)
Start/stop LETIMER.
Definition: em_letimer.c:227
void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init)
Initialize LETIMER.
Definition: em_letimer.c:323
uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp)
Get LETIMER compare register value.
Definition: em_letimer.c:125
Emlib peripheral API "assert" implementation.
#define LETIMER_CMD_START
#define LETIMER_CMD_CTO0
#define LETIMER_CMD_CLEAR
LETIMER_UFOA_TypeDef ufoa1
Definition: em_letimer.h:109
uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep)
Get LETIMER repeat register value.
Definition: em_letimer.c:413
Low Energy Timer (LETIMER) peripheral API.
#define LETIMER_STATUS_RUNNING
#define _LETIMER_CTRL_UFOA0_SHIFT
__IO uint32_t REP0
void LETIMER_Reset(LETIMER_TypeDef *letimer)
Reset LETIMER to same state as after a HW reset.
Definition: em_letimer.c:516
#define _LETIMER_REP1_RESETVALUE
void LETIMER_RepeatSet(LETIMER_TypeDef *letimer, unsigned int rep, uint32_t value)
Set LETIMER repeat counter register value.
Definition: em_letimer.c:460
LETIMER_UFOA_TypeDef ufoa0
Definition: em_letimer.h:108
__IO uint32_t COMP1
__IO uint32_t CTRL
#define LETIMER_CTRL_OPOL1
#define LETIMER_CMD_STOP
__IO uint32_t IFC
#define _LETIMER_COMP0_RESETVALUE
__I uint32_t SYNCBUSY
#define _LETIMER_REP0_REP0_MASK
#define LETIMER_CMD_CTO1
#define _LETIMER_COMP1_RESETVALUE
#define _LETIMER_REP0_RESETVALUE
__IO uint32_t REP1
__IO uint32_t CMD
#define _LETIMER_REP0_REP0_SHIFT
#define LETIMER_CTRL_COMP0TOP
void LETIMER_CompareSet(LETIMER_TypeDef *letimer, unsigned int comp, uint32_t value)
Set LETIMER compare register value.
Definition: em_letimer.c:172
LETIMER_RepeatMode_TypeDef repMode
Definition: em_letimer.h:110
#define _LETIMER_IEN_RESETVALUE
#define _LETIMER_COMP0_COMP0_MASK
#define LETIMER_CTRL_BUFTOP
__I uint32_t STATUS
__IO uint32_t IEN
#define _LETIMER_COMP0_COMP0_SHIFT
#define _LETIMER_IFC_MASK
#define _LETIMER_CTRL_RESETVALUE
#define LETIMER_CTRL_DEBUGRUN
#define LETIMER_SYNCBUSY_CMD
#define _LETIMER_CTRL_REPMODE_SHIFT
__IO uint32_t COMP0
#define LETIMER_CTRL_OPOL0
#define _LETIMER_CTRL_UFOA1_SHIFT