1 /***************************************************************************//**
2  * @file
3  * @brief Low Energy Timer (LETIMER) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_letimer.h"
32 #if defined(LETIMER_COUNT) && (LETIMER_COUNT > 0)
33 #include "em_cmu.h"
34 #include "em_assert.h"
35 
36 /***************************************************************************//**
37  * @addtogroup letimer LETIMER - Low Energy Timer
38  * @brief Low Energy Timer (LETIMER) Peripheral API
39  * @details
40  *  This module contains functions to control the LETIMER peripheral of Silicon
41  *  Labs 32-bit MCUs and SoCs. The LETIMER is a down-counter that can keep track
42  *  of time and output configurable waveforms.
43  * @{
44  ******************************************************************************/
45 
46 /*******************************************************************************
47  *******************************   DEFINES   ***********************************
48  ******************************************************************************/
49 
50 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
51 
52 /** A validation of the valid comparator register for assert statements. */
53 #define LETIMER_COMP_REG_VALID(reg)    (((reg) <= 1))
54 
55 /** A validation of the LETIMER register block pointer reference for assert statements. */
56 #if (LETIMER_COUNT == 1)
57 #define LETIMER_REF_VALID(ref)         ((ref) == LETIMER0)
58 #elif (LETIMER_COUNT == 2)
59 #define LETIMER_REF_VALID(ref)         (((ref) == LETIMER0) ||  ((ref) == LETIMER1))
60 #else
61 #error Undefined number of analog comparators (ACMP).
62 #endif
63 
64 /** A validation of the valid repeat counter register for assert statements. */
65 #define LETIMER_REP_REG_VALID(reg)     (((reg) <= 1))
66 
67 /** @endcond */
68 
69 /*******************************************************************************
70  **************************   LOCAL FUNCTIONS   ********************************
71  ******************************************************************************/
72 
73 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
74 
75 /***************************************************************************//**
76  * @brief
77  *   Wait for an ongoing sync of register(s) to the low-frequency domain to complete.
78  *
79  * @note
80  *   See the reference manual chapter about Access to Low Energy Peripherals
81  *   (Asynchronos Registers) for details.
82  *
83  * @param[in] letimer
84  *   A pointer to the LETIMER peripheral register block.
85  *
86  * @param[in] mask
87  *   A bitmask corresponding to SYNCBUSY register defined bits, indicating
88  *   registers that must complete any ongoing synchronization.
89  ******************************************************************************/
regSync(LETIMER_TypeDef * letimer,uint32_t mask)90 __STATIC_INLINE void regSync(LETIMER_TypeDef *letimer, uint32_t mask)
91 {
92 #if defined(_LETIMER_FREEZE_MASK)
93   /* Avoid a deadlock if modifying the same register twice when freeze mode is */
94   /* activated. */
95   if (letimer->FREEZE & LETIMER_FREEZE_REGFREEZE) {
96     return;
97   }
98 #endif
99 
100   /* Wait for any pending write operation to complete. */
101   while (letimer->SYNCBUSY & mask) {
102   }
103 }
104 
105 /** @endcond */
106 
107 /*******************************************************************************
108  **************************   GLOBAL FUNCTIONS   *******************************
109  ******************************************************************************/
110 
111 /***************************************************************************//**
112  * @brief
113  *   Get the LETIMER compare register value.
114  *
115  * @param[in] letimer
116  *   A pointer to the LETIMER peripheral register block.
117  *
118  * @param[in] comp
119  *   A compare register to get, either 0 or 1.
120  *
121  * @return
122  *   A compare register value, 0 if invalid register selected.
123  ******************************************************************************/
LETIMER_CompareGet(LETIMER_TypeDef * letimer,unsigned int comp)124 uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp)
125 {
126   uint32_t ret;
127 
128   EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_COMP_REG_VALID(comp));
129 
130   /* Initialize the selected compare value. */
131   switch (comp) {
132     case 0:
133 #if defined(LETIMER_SYNCBUSY_COMP0)
134       regSync(letimer, LETIMER_SYNCBUSY_COMP0);
135 #endif
136       ret = letimer->COMP0;
137       break;
138 
139     case 1:
140 #if defined(LETIMER_SYNCBUSY_COMP1)
141       regSync(letimer, LETIMER_SYNCBUSY_COMP1);
142 #endif
143       ret = letimer->COMP1;
144       break;
145 
146     default:
147       /* An unknown compare register selected. */
148       ret = 0;
149       break;
150   }
151 
152   return ret;
153 }
154 
155 /***************************************************************************//**
156  * @brief
157  *   Get LETIMER counter value.
158  *
159  * @param[in] letimer
160  *   Pointer to the LETIMER peripheral register block.
161  *
162  * @return
163  *   Current LETIMER counter value.
164  ******************************************************************************/
LETIMER_CounterGet(LETIMER_TypeDef * letimer)165 uint32_t LETIMER_CounterGet(LETIMER_TypeDef *letimer)
166 {
167 #if defined(LETIMER_SYNCBUSY_CNT)
168   regSync(letimer, LETIMER_SYNCBUSY_CNT);
169 #endif
170   return letimer->CNT;
171 }
172 
173 #if !defined(_EFM32_GECKO_FAMILY)
174 /***************************************************************************//**
175  * @brief
176  *   Set LETIMER counter value.
177  *
178  * @param[in] letimer
179  *   Pointer to the LETIMER peripheral register block.
180  *
181  * @param[in] value
182  *   New counter value.
183  ******************************************************************************/
LETIMER_CounterSet(LETIMER_TypeDef * letimer,uint32_t value)184 void LETIMER_CounterSet(LETIMER_TypeDef *letimer, uint32_t value)
185 {
186 #if defined(LETIMER_SYNCBUSY_CNT)
187   regSync(letimer, LETIMER_SYNCBUSY_CNT);
188 #endif
189   letimer->CNT = value;
190 }
191 #endif
192 
193 /***************************************************************************//**
194  * @brief
195  *   Set the LETIMER compare register value.
196  *
197  * @note
198  *   The setting of a compare register requires synchronization into the
199  *   low frequency domain. If the same register is modified before a previous
200  *   update has completed, this function will stall until the previous
201  *   synchronization has completed. This only applies to the Gecko Family. See
202  *   comments in the LETIMER_Sync() internal function call.
203  *
204  * @param[in] letimer
205  *   A pointer to the LETIMER peripheral register block.
206  *
207  * @param[in] comp
208  *   A compare register to set, either 0 or 1.
209  *
210  * @param[in] value
211  *   An initialization value (<= 0x0000ffff).
212  ******************************************************************************/
LETIMER_CompareSet(LETIMER_TypeDef * letimer,unsigned int comp,uint32_t value)213 void LETIMER_CompareSet(LETIMER_TypeDef *letimer,
214                         unsigned int comp,
215                         uint32_t value)
216 {
217   volatile uint32_t *compReg;
218 
219   EFM_ASSERT(LETIMER_REF_VALID(letimer)
220              && LETIMER_COMP_REG_VALID(comp)
221              && ((value & ~(_LETIMER_COMP0_COMP0_MASK
222                             >> _LETIMER_COMP0_COMP0_SHIFT))
223                  == 0));
224 
225   /* Initialize the selected compare value. */
226   switch (comp) {
227     case 0:
228       compReg  = &letimer->COMP0;
229 #if defined(LETIMER_SYNCBUSY_COMP0)
230       regSync(letimer, LETIMER_SYNCBUSY_COMP0);
231 #endif
232       break;
233 
234     case 1:
235       compReg  = &letimer->COMP1;
236 #if defined(LETIMER_SYNCBUSY_COMP1)
237       regSync(letimer, LETIMER_SYNCBUSY_COMP1);
238 #endif
239       break;
240 
241     default:
242       /* An unknown compare register selected, abort. */
243       return;
244   }
245 
246   *compReg = value;
247 }
248 
249 /***************************************************************************//**
250  * @brief
251  *   Start/stop LETIMER.
252  *
253  * @note
254  *   The enabling/disabling of the LETIMER modifies the LETIMER CMD register
255  *   which requires synchronization into the low-frequency domain. If this
256  *   register is modified before a previous update to the same register has
257  *   completed, this function will stall until the previous synchronization has
258  *   completed. This only applies to the Gecko Family. See comments in the
259  *   LETIMER_Sync() internal function call.
260  *
261  * @param[in] letimer
262  *   A pointer to the LETIMER peripheral register block.
263  *
264  * @param[in] enable
265  *   True to enable counting, false to disable.
266  ******************************************************************************/
LETIMER_Enable(LETIMER_TypeDef * letimer,bool enable)267 void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable)
268 {
269   EFM_ASSERT(LETIMER_REF_VALID(letimer));
270 
271 #if defined(LETIMER_SYNCBUSY_CMD)
272   regSync(letimer, LETIMER_SYNCBUSY_CMD);
273 #elif defined (LETIMER_SYNCBUSY_START) && defined (LETIMER_SYNCBUSY_STOP)
274   regSync(letimer, LETIMER_SYNCBUSY_STOP | LETIMER_SYNCBUSY_START);
275 #endif
276 
277   if (enable) {
278     letimer->CMD = LETIMER_CMD_START;
279   } else {
280     letimer->CMD = LETIMER_CMD_STOP;
281   }
282 }
283 
284 #if defined(_LETIMER_FREEZE_MASK)
285 /***************************************************************************//**
286  * @brief
287  *   LETIMER register synchronization freeze control.
288  *
289  * @details
290  *   Some LETIMER registers require synchronization into the low-frequency (LF)
291  *   domain. The freeze feature allows for several such registers to be
292  *   modified before passing them to the LF domain simultaneously (which
293  *   takes place when the freeze mode is disabled).
294  *
295  * @note
296  *   When enabling freeze mode, this function will wait for all current
297  *   ongoing LETIMER synchronization to the LF domain to complete (Normally
298  *   synchronization will not be in progress.) However, for this reason, when
299  *   using freeze mode, modifications of registers requiring the LF synchronization
300  *   should be done within one freeze enable/disable block to avoid unecessary
301  *   stalling.
302  *
303  * @param[in] letimer
304  *   A pointer to the LETIMER peripheral register block.
305  *
306  * @param[in] enable
307  *   @li True - enable freeze, modified registers are not propagated to the
308  *       LF domain
309  *   @li False - disables freeze, modified registers are propagated to the LF
310  *       domain
311  ******************************************************************************/
LETIMER_FreezeEnable(LETIMER_TypeDef * letimer,bool enable)312 void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable)
313 {
314   if (enable) {
315     /*
316      * Wait for any ongoing LF synchronization to complete to
317      * protect against the rare case when a user
318      * - modifies a register requiring LF sync
319      * - then enables freeze before LF sync completed
320      * - then modifies the same register again
321      * since modifying a register while it is in sync progress should be
322      * avoided.
323      */
324     while (letimer->SYNCBUSY) {
325     }
326 
327     letimer->FREEZE = LETIMER_FREEZE_REGFREEZE;
328   } else {
329     letimer->FREEZE = 0;
330   }
331 }
332 #endif /* defined(_LETIMER_FREEZE_MASK) */
333 
334 /***************************************************************************//**
335  * @brief
336  *   Initialize LETIMER.
337  *
338  * @details
339  *   Note that the compare/repeat values must be set separately with
340  *   LETIMER_CompareSet() and LETIMER_RepeatSet(). That should probably be done
341  *   prior using this function if configuring the LETIMER to start when
342  *   initialization is complete.
343  *
344  * @note
345  *   The initialization of the LETIMER modifies the LETIMER CTRL/CMD registers
346  *   which require synchronization into the low-frequency domain. If any of those
347  *   registers are modified before a previous update to the same register has
348  *   completed, this function will stall until the previous synchronization has
349  *   completed. This only applies to the Gecko Family. See comments in the
350  *   LETIMER_Sync() internal function call.
351  *
352  * @param[in] letimer
353  *   A pointer to the LETIMER peripheral register block.
354  *
355  * @param[in] init
356  *   A pointer to the LETIMER initialization structure.
357  ******************************************************************************/
LETIMER_Init(LETIMER_TypeDef * letimer,const LETIMER_Init_TypeDef * init)358 void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init)
359 {
360   uint32_t tmp = 0;
361 
362   EFM_ASSERT(LETIMER_REF_VALID(letimer));
363 
364 #if defined (LETIMER_EN_EN)
365   letimer->EN_SET = LETIMER_EN_EN;
366 #endif
367 
368   /* Stop the timer if specified to be disabled and running. */
369   if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING)) {
370 #if defined(LETIMER_SYNCBUSY_CMD)
371     regSync(letimer, LETIMER_SYNCBUSY_CMD);
372 #elif defined(LETIMER_SYNCBUSY_STOP)
373     regSync(letimer, LETIMER_SYNCBUSY_STOP);
374 #endif
375     letimer->CMD = LETIMER_CMD_STOP;
376   }
377 
378   /* Configure the DEBUGRUN flag, which sets whether or not the counter should be
379    * updated when the debugger is active. */
380   if (init->debugRun) {
381     tmp |= LETIMER_CTRL_DEBUGRUN;
382   }
383 
384 #if defined(LETIMER_CTRL_RTCC0TEN)
385   if (init->rtcComp0Enable) {
386     tmp |= LETIMER_CTRL_RTCC0TEN;
387   }
388 
389   if (init->rtcComp1Enable) {
390     tmp |= LETIMER_CTRL_RTCC1TEN;
391   }
392 #endif
393 
394   if ((init->comp0Top) || (init->topValue != 0U)) {
395 #if defined (LETIMER_CTRL_COMP0TOP)
396     tmp |= LETIMER_CTRL_COMP0TOP;
397     if (init->topValue != 0U) {
398       letimer->COMP0 = init->topValue;
399     }
400 #elif defined (LETIMER_CTRL_CNTTOPEN)
401     tmp |= LETIMER_CTRL_CNTTOPEN;
402     if (init->topValue != 0U) {
403       letimer->TOP = init->topValue;
404     }
405 #endif
406   }
407 
408   if (init->bufTop) {
409     tmp |= LETIMER_CTRL_BUFTOP;
410   }
411 
412   if (init->out0Pol) {
413     tmp |= LETIMER_CTRL_OPOL0;
414   }
415 
416   if (init->out1Pol) {
417     tmp |= LETIMER_CTRL_OPOL1;
418   }
419 
420   tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT;
421   tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT;
422   tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT;
423 
424 #if defined(LETIMER_SYNCBUSY_CTRL)
425   /* LF register about to be modified requires sync; busy check. */
426   regSync(letimer, LETIMER_SYNCBUSY_CTRL);
427 #endif
428   letimer->CTRL = tmp;
429 
430   /* Start the timer if specified to be enabled and not already running. */
431   if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING)) {
432 #if defined(LETIMER_SYNCBUSY_CMD)
433     regSync(letimer, LETIMER_SYNCBUSY_CMD);
434 #elif defined(LETIMER_SYNCBUSY_START)
435     regSync(letimer, LETIMER_SYNCBUSY_START);
436 #endif
437     letimer->CMD = LETIMER_CMD_START;
438   }
439 }
440 
441 /***************************************************************************//**
442  * @brief
443  *   Get the LETIMER repeat register value.
444  *
445  * @param[in] letimer
446  *   A pointer to the LETIMER peripheral register block.
447  *
448  * @param[in] rep
449  *   Repeat register to get, either 0 or 1.
450  *
451  * @return
452  *   Repeat register value, 0 if invalid register selected.
453  ******************************************************************************/
LETIMER_RepeatGet(LETIMER_TypeDef * letimer,unsigned int rep)454 uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep)
455 {
456   uint32_t ret;
457 
458   EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_REP_REG_VALID(rep));
459 
460   /* Initialize the selected compare value. */
461   switch (rep) {
462     case 0:
463 #if defined(LETIMER_SYNCBUSY_REP0)
464       /* Wait for sync to complete to read the potentially pending value. */
465       regSync(letimer, LETIMER_SYNCBUSY_REP0);
466 #endif
467       ret = letimer->REP0;
468       break;
469 
470     case 1:
471 #if defined(LETIMER_SYNCBUSY_REP1)
472       regSync(letimer, LETIMER_SYNCBUSY_REP1);
473 #endif
474       ret = letimer->REP1;
475       break;
476 
477     default:
478       /* An unknown compare register selected. */
479       ret = 0;
480       break;
481   }
482 
483   return ret;
484 }
485 
486 /***************************************************************************//**
487  * @brief
488  *   Set the LETIMER repeat counter register value.
489  *
490  * @note
491  *   The setting of a repeat counter register requires synchronization into the
492  *   low-frequency domain. If the same register is modified before a previous
493  *   update has completed, this function will stall until the previous
494  *   synchronization has completed. This only applies to the Gecko Family. See
495  *   comments in the LETIMER_Sync() internal function call.
496  *
497  * @param[in] letimer
498  *   A pointer to the LETIMER peripheral register block.
499  *
500  * @param[in] rep
501  *   Repeat counter register to set, either 0 or 1.
502  *
503  * @param[in] value
504  *   An initialization value (<= 0x0000ffff).
505  ******************************************************************************/
LETIMER_RepeatSet(LETIMER_TypeDef * letimer,unsigned int rep,uint32_t value)506 void LETIMER_RepeatSet(LETIMER_TypeDef *letimer,
507                        unsigned int rep,
508                        uint32_t value)
509 {
510   volatile uint32_t *repReg;
511   EFM_ASSERT(LETIMER_REF_VALID(letimer)
512              && LETIMER_REP_REG_VALID(rep)
513              && ((value & ~(_LETIMER_REP0_REP0_MASK
514                             >> _LETIMER_REP0_REP0_SHIFT))
515                  == 0));
516 
517   /* Initialize the selected compare value. */
518   switch (rep) {
519     case 0:
520       repReg = &(letimer->REP0);
521 #if defined(LETIMER_SYNCBUSY_REP0)
522       regSync(letimer, LETIMER_SYNCBUSY_REP0);
523 #endif
524       break;
525 
526     case 1:
527       repReg = &(letimer->REP1);
528 #if defined(LETIMER_SYNCBUSY_REP1)
529       regSync(letimer, LETIMER_SYNCBUSY_REP1);
530 #endif
531       break;
532 
533     default:
534       /* An unknown compare register selected, abort. */
535       return;
536   }
537 
538   *repReg = value;
539 }
540 
541 /***************************************************************************//**
542  * @brief
543  *   Reset LETIMER to the same state that it was in after a hardware reset.
544  *
545  * @note
546  *   The ROUTE register is NOT reset by this function to allow for
547  *   a centralized setup of this feature.
548  *
549  * @param[in] letimer
550  *   A pointer to the LETIMER peripheral register block.
551  ******************************************************************************/
LETIMER_Reset(LETIMER_TypeDef * letimer)552 void LETIMER_Reset(LETIMER_TypeDef *letimer)
553 {
554 #if defined (LETIMER_EN_EN)
555   letimer->EN_SET = LETIMER_EN_EN;
556 #endif
557   LETIMER_SyncWait(letimer);
558 
559 #ifdef LETIMER_SWRST_SWRST
560 
561   letimer->SWRST_SET = LETIMER_SWRST_SWRST;
562   while (letimer->SWRST & _LETIMER_SWRST_RESETTING_MASK) ;
563 
564 #else
565 
566 #if defined(_LETIMER_FREEZE_MASK)
567   /* Freeze registers to avoid stalling for LF synchronization. */
568   LETIMER_FreezeEnable(letimer, true);
569 #endif
570 
571   /* Make sure disabled first, before resetting other registers. */
572   letimer->CMD = LETIMER_CMD_STOP | LETIMER_CMD_CLEAR
573                  | LETIMER_CMD_CTO0 | LETIMER_CMD_CTO1;
574   letimer->CTRL  = _LETIMER_CTRL_RESETVALUE;
575   letimer->COMP0 = _LETIMER_COMP0_RESETVALUE;
576   letimer->COMP1 = _LETIMER_COMP1_RESETVALUE;
577   letimer->REP0  = _LETIMER_REP0_RESETVALUE;
578   letimer->REP1  = _LETIMER_REP1_RESETVALUE;
579   letimer->IEN   = _LETIMER_IEN_RESETVALUE;
580   LETIMER_IntClear(letimer, _LETIMER_IF_MASK);
581 
582 #if defined(_LETIMER_FREEZE_MASK)
583   /* Unfreeze registers and pass new settings to LETIMER. */
584   LETIMER_FreezeEnable(letimer, false);
585 #endif
586 
587   LETIMER_SyncWait(letimer);
588 
589 #if defined (LETIMER_EN_EN)
590   letimer->EN_CLR = LETIMER_EN_EN;
591 #if defined(_LETIMER_EN_DISABLING_MASK)
592   /*
593    * Currently, there are no chips without SWRST and with LETIMER_EN_DISABLING
594    * so this code should never be reached, but that way the same pattern of
595    * checking the disabling bit is spread across emlib, and code is slightly
596    * more resilient to feature addition/removal.
597    */
598   while (letimer->EN & _LETIMER_EN_DISABLING_MASK) {
599   }
600 #endif
601 #endif
602 #endif
603 }
604 
605 /***************************************************************************//**
606  * @brief
607  *   Wait for the LETIMER to complete all synchronization of register changes
608  *   and commands.
609  *
610  * @param[in] letimer
611  *   A pointer to the LETIMER peripheral register block.
612  ******************************************************************************/
LETIMER_SyncWait(LETIMER_TypeDef * letimer)613 void LETIMER_SyncWait(LETIMER_TypeDef *letimer)
614 {
615 #if defined(_SILICON_LABS_32B_SERIES_2)
616   while ((letimer->EN != 0U) && (letimer->SYNCBUSY != 0U)) {
617     /* Wait for previous synchronization to finish */
618   }
619 #else
620   while (letimer->SYNCBUSY != 0U) {
621     /* Wait for previous synchronization to finish */
622   }
623 #endif
624 }
625 
626 /***************************************************************************//**
627  * @brief
628  *   Set the LETIMER top value.
629  *
630  * @note
631  *   The LETIMER is a down-counter, so when the counter reaches 0 then the top
632  *   value will be loaded into the counter. This function can be used to set
633  *   the top value.
634  *
635  *   If the LETIMER is not already configured to use a top value then this
636  *   function will enable that functionality for the user.
637  *
638  * @param[in] letimer
639  *   A pointer to the LETIMER peripheral register block.
640  *
641  * @param[in] value
642  *   The top value. This can be a 16 bit value on series-0 and series-1 devices
643  *   and a 24 bit value on series-2 devices.
644  ******************************************************************************/
LETIMER_TopSet(LETIMER_TypeDef * letimer,uint32_t value)645 void LETIMER_TopSet(LETIMER_TypeDef *letimer, uint32_t value)
646 {
647 #if defined(LETIMER_SYNCBUSY_CTRL)
648   regSync(letimer, LETIMER_SYNCBUSY_CTRL);
649 #elif defined(LETIMER_SYNCBUSY_TOP)
650   regSync(letimer, LETIMER_SYNCBUSY_TOP);
651 #endif
652 
653 #if defined(_LETIMER_TOP_MASK)
654   /* Make sure TOP value is enabled. */
655   if ((letimer->CTRL & LETIMER_CTRL_CNTTOPEN) == 0U) {
656     letimer->CTRL_SET = LETIMER_CTRL_CNTTOPEN;
657   }
658   letimer->TOP = value;
659 #else
660   /* Make sure TOP value is enabled. */
661   if ((letimer->CTRL & LETIMER_CTRL_COMP0TOP) == 0U) {
662     letimer->CTRL |= LETIMER_CTRL_COMP0TOP;
663   }
664   LETIMER_CompareSet(letimer, 0, value);
665 #endif
666 }
667 
668 /***************************************************************************//**
669  * @brief
670  *   Get the current LETIMER top value.
671  *
672  * @param[in] letimer
673  *   A pointer to the LETIMER peripheral register block.
674  *
675  * @return
676  *   The top value. This will be a 16 bit value on series-0 and series-1
677  *   devices and a 24 bit value on series-2 devices.
678  ******************************************************************************/
LETIMER_TopGet(LETIMER_TypeDef * letimer)679 uint32_t LETIMER_TopGet(LETIMER_TypeDef *letimer)
680 {
681 #if defined(_LETIMER_TOP_MASK)
682   regSync(letimer, LETIMER_SYNCBUSY_TOP);
683   return letimer->TOP;
684 #else
685 #if defined(LETIMER_SYNCBUSY_COMP0)
686   regSync(letimer, LETIMER_SYNCBUSY_COMP0);
687 #endif
688   return letimer->COMP0;
689 #endif
690 }
691 
692 /** @} (end addtogroup letimer) */
693 #endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */
694