1 /***************************************************************************//**
2  * @file
3  * @brief Timer/counter (TIMER) 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_timer.h"
32 #if defined(TIMER_COUNT) && (TIMER_COUNT > 0)
33 
34 #include "em_assert.h"
35 
36 /***************************************************************************//**
37  * @addtogroup timer TIMER - Timer/Counter
38  * @brief Timer/Counter (TIMER) Peripheral API
39  * @details
40  *   The timer module consists of three main parts:
41  *   @li General timer configuration and enable control.
42  *   @li Compare/capture control.
43  *   @li Dead time insertion control (may not be available for all timers).
44  * @{
45  ******************************************************************************/
46 
47 /*******************************************************************************
48  **************************   LOCAL FUNCTIONS   ********************************
49  ******************************************************************************/
50 
51 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
52 #if defined(_PRS_CONSUMER_TIMER0_CC0_MASK)
53 
54 /** Map TIMER reference to index of device. */
55 #if defined(TIMER4)
56 #define TIMER_DEVICE_ID(timer) ( \
57     (timer) == TIMER0   ? 0      \
58     : (timer) == TIMER1 ? 1      \
59     : (timer) == TIMER2 ? 2      \
60     : (timer) == TIMER3 ? 3      \
61     : (timer) == TIMER4 ? 4      \
62     : -1)
63 #else
64 #define TIMER_DEVICE_ID(timer) ( \
65     (timer) == TIMER0   ? 0      \
66     : (timer) == TIMER1 ? 1      \
67     : (timer) == TIMER2 ? 2      \
68     : (timer) == TIMER3 ? 3      \
69     : -1)
70 #endif
71 
72 #define TIMER_INPUT_CHANNEL_DTI     3UL
73 #define TIMER_INPUT_CHANNEL_DTIFS1  4UL
74 #define TIMER_INPUT_CHANNEL_DTIFS2  5UL
75 
76 /**
77  * TIMER PRS registers are moved into the PRS register space on series 2 devices.
78  * The PRS Consumer registers for a timer consist of 6 registers.
79  *
80  * [0] - CC0 PRS Consumer
81  * [1] - CC1 PRS Consumer
82  * [2] - CC2 PRS Consumer
83  * [3] - DTI PRS Consumer
84  * [4] - DTIFS1 PRS Consumer
85  * [5] - DTIFS2 PRS Consumer
86  */
87 typedef struct {
88   __IOM uint32_t CONSUMER_CH[6];         /**< TIMER PRS consumers. */
89 } PRS_TIMERn_Consumer_TypeDef;
90 
91 typedef struct {
92   PRS_TIMERn_Consumer_TypeDef TIMER_CONSUMER[TIMER_COUNT];
93 } PRS_TIMERn_TypeDef;
94 
95 /**
96  * @brief Configure a timer capture/compare channel to use a PRS channel as input.
97  *
98  * @param[in] timer
99  *
100  * @param[in] cc
101  *   Timer input channel. Valid input is 0-5.
102  *   0 - CC0
103  *   1 - CC1
104  *   2 - CC2
105  *   3 - DTI
106  *   4 - DTIFS1
107  *   5 - DTIFS2
108  *
109  * @param[in] prsCh
110  *   PRS channel number.
111  *
112  * @param[in] async
113  *   true for asynchronous PRS channel, false for synchronous PRS channel.
114  */
timerPrsConfig(TIMER_TypeDef * timer,unsigned int cc,unsigned int prsCh,bool async)115 static void timerPrsConfig(TIMER_TypeDef * timer, unsigned int cc, unsigned int prsCh, bool async)
116 {
117   int i = TIMER_DEVICE_ID(timer);
118   PRS_TIMERn_TypeDef * base = (PRS_TIMERn_TypeDef *) &PRS->CONSUMER_TIMER0_CC0;
119   EFM_ASSERT(i != -1);
120 
121   if (async) {
122     base->TIMER_CONSUMER[i].CONSUMER_CH[cc] = prsCh << _PRS_CONSUMER_TIMER0_CC0_PRSSEL_SHIFT;
123   } else {
124     base->TIMER_CONSUMER[i].CONSUMER_CH[cc] = prsCh << _PRS_CONSUMER_TIMER0_CC0_SPRSSEL_SHIFT;
125   }
126 }
127 #endif
128 
129 /** @endcond */
130 
131 /*******************************************************************************
132  **************************   GLOBAL FUNCTIONS   *******************************
133  ******************************************************************************/
134 
135 /***************************************************************************//**
136  * @brief
137  *   Initialize TIMER.
138  *
139  * @details
140  *   Notice that the counter top must be configured separately with, for instance
141  *   TIMER_TopSet(). In addition, compare/capture and dead-time insertion
142  *   initialization must be initialized separately if used, which should probably
143  *   be done prior to using this function if configuring the TIMER to
144  *   start when initialization is completed.
145  *
146  * @param[in] timer
147  *   A pointer to the TIMER peripheral register block.
148  *
149  * @param[in] init
150  *   A pointer to the TIMER initialization structure.
151  ******************************************************************************/
TIMER_Init(TIMER_TypeDef * timer,const TIMER_Init_TypeDef * init)152 void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init)
153 {
154   EFM_ASSERT(TIMER_REF_VALID(timer));
155   uint32_t ctrlRegVal = 0;
156 
157 #if defined (_TIMER_CFG_PRESC_SHIFT)
158   TIMER_SyncWait(timer);
159   timer->EN_CLR = TIMER_EN_EN;
160 #if defined(_TIMER_EN_DISABLING_MASK)
161   while (timer->EN & _TIMER_EN_DISABLING_MASK) {
162   }
163 #endif
164   timer->CFG = ((uint32_t)init->prescale << _TIMER_CFG_PRESC_SHIFT)
165                | ((uint32_t)init->clkSel << _TIMER_CFG_CLKSEL_SHIFT)
166                | ((uint32_t)init->mode   << _TIMER_CFG_MODE_SHIFT)
167                | (init->debugRun         ?   TIMER_CFG_DEBUGRUN  : 0)
168                | (init->dmaClrAct        ?   TIMER_CFG_DMACLRACT : 0)
169                | (init->quadModeX4       ?   TIMER_CFG_QDM_X4    : 0)
170                | (init->oneShot          ?   TIMER_CFG_OSMEN     : 0)
171                | (init->sync             ?   TIMER_CFG_SYNC      : 0)
172                | (init->ati              ?   TIMER_CFG_ATI       : 0);
173   timer->EN_SET = TIMER_EN_EN;
174 #endif
175 
176   /* Stop the timer if specified to be disabled (doesn't hurt if already stopped). */
177   if (!(init->enable)) {
178     timer->CMD = TIMER_CMD_STOP;
179   }
180 
181   /* Reset the counter. */
182   timer->CNT = _TIMER_CNT_RESETVALUE;
183 
184 #if defined(_SILICON_LABS_32B_SERIES_2)
185   ctrlRegVal = ((uint32_t)init->fallAction   << _TIMER_CTRL_FALLA_SHIFT)
186                | ((uint32_t)init->riseAction << _TIMER_CTRL_RISEA_SHIFT)
187                | (init->count2x              ?   TIMER_CTRL_X2CNT     : 0);
188 #else
189   ctrlRegVal = ((uint32_t)init->prescale     << _TIMER_CTRL_PRESC_SHIFT)
190                | ((uint32_t)init->clkSel     << _TIMER_CTRL_CLKSEL_SHIFT)
191                | ((uint32_t)init->fallAction << _TIMER_CTRL_FALLA_SHIFT)
192                | ((uint32_t)init->riseAction << _TIMER_CTRL_RISEA_SHIFT)
193                | ((uint32_t)init->mode       << _TIMER_CTRL_MODE_SHIFT)
194                | (init->debugRun             ?   TIMER_CTRL_DEBUGRUN  : 0)
195                | (init->dmaClrAct            ?   TIMER_CTRL_DMACLRACT : 0)
196                | (init->quadModeX4           ?   TIMER_CTRL_QDM_X4    : 0)
197                | (init->oneShot              ?   TIMER_CTRL_OSMEN     : 0)
198                | (init->sync                 ?   TIMER_CTRL_SYNC      : 0);
199 #if defined(TIMER_CTRL_X2CNT) && defined(TIMER_CTRL_ATI)
200   ctrlRegVal |= (init->count2x              ?   TIMER_CTRL_X2CNT     : 0)
201                 | (init->ati                ?   TIMER_CTRL_ATI       : 0);
202 #endif
203 #endif
204 
205   timer->CTRL = ctrlRegVal;
206 
207   /* Start the timer if specified to be enabled (doesn't hurt if already started). */
208   if (init->enable) {
209     timer->CMD = TIMER_CMD_START;
210   }
211 }
212 
213 /***************************************************************************//**
214  * @brief
215  *   Initialize the TIMER compare/capture channel.
216  *
217  * @details
218  *   Notice that if operating the channel in compare mode, the CCV and CCVB register
219  *   must be set separately, as required.
220  *
221  * @param[in] timer
222  *   A pointer to the TIMER peripheral register block.
223  *
224  * @param[in] ch
225  *   A compare/capture channel to initialize for.
226  *
227  * @param[in] init
228  *   A pointer to the TIMER initialization structure.
229  ******************************************************************************/
TIMER_InitCC(TIMER_TypeDef * timer,unsigned int ch,const TIMER_InitCC_TypeDef * init)230 void TIMER_InitCC(TIMER_TypeDef *timer,
231                   unsigned int ch,
232                   const TIMER_InitCC_TypeDef *init)
233 {
234   EFM_ASSERT(TIMER_REF_VALID(timer));
235 #if !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
236   EFM_ASSERT(TIMER_CH_VALID(ch));
237 #endif
238 
239 #if defined (_TIMER_CC_CFG_MASK)
240   TIMER_SyncWait(timer);
241   timer->EN_CLR = TIMER_EN_EN;
242 #if defined(_TIMER_EN_DISABLING_MASK)
243   while (timer->EN & _TIMER_EN_DISABLING_MASK) {
244   }
245 #endif
246   timer->CC[ch].CFG =
247     ((uint32_t)init->mode        << _TIMER_CC_CFG_MODE_SHIFT)
248     | (init->filter              ?   TIMER_CC_CFG_FILT_ENABLE : 0)
249     | (init->coist               ?   TIMER_CC_CFG_COIST       : 0)
250     | ((uint32_t)init->prsOutput << _TIMER_CC_CFG_PRSCONF_SHIFT);
251 
252   if (init->prsInput) {
253     timer->CC[ch].CFG |= (uint32_t)init->prsInputType << _TIMER_CC_CFG_INSEL_SHIFT;
254     bool async = (init->prsInputType != timerPrsInputSync);
255     timerPrsConfig(timer, ch, init->prsSel, async);
256   } else {
257     timer->CC[ch].CFG |= TIMER_CC_CFG_INSEL_PIN;
258   }
259   timer->EN_SET = TIMER_EN_EN;
260 
261   timer->CC[ch].CTRL =
262     ((uint32_t)init->eventCtrl << _TIMER_CC_CTRL_ICEVCTRL_SHIFT)
263     | ((uint32_t)init->edge    << _TIMER_CC_CTRL_ICEDGE_SHIFT)
264     | ((uint32_t)init->cufoa   << _TIMER_CC_CTRL_CUFOA_SHIFT)
265     | ((uint32_t)init->cofoa   << _TIMER_CC_CTRL_COFOA_SHIFT)
266     | ((uint32_t)init->cmoa    << _TIMER_CC_CTRL_CMOA_SHIFT)
267     | (init->outInvert         ?   TIMER_CC_CTRL_OUTINV : 0);
268 #else
269   timer->CC[ch].CTRL =
270     ((uint32_t)init->eventCtrl   << _TIMER_CC_CTRL_ICEVCTRL_SHIFT)
271     | ((uint32_t)init->edge      << _TIMER_CC_CTRL_ICEDGE_SHIFT)
272     | ((uint32_t)init->prsSel    << _TIMER_CC_CTRL_PRSSEL_SHIFT)
273     | ((uint32_t)init->cufoa     << _TIMER_CC_CTRL_CUFOA_SHIFT)
274     | ((uint32_t)init->cofoa     << _TIMER_CC_CTRL_COFOA_SHIFT)
275     | ((uint32_t)init->cmoa      << _TIMER_CC_CTRL_CMOA_SHIFT)
276     | ((uint32_t)init->mode      << _TIMER_CC_CTRL_MODE_SHIFT)
277     | (init->filter              ?   TIMER_CC_CTRL_FILT_ENABLE : 0)
278     | (init->prsInput            ?   TIMER_CC_CTRL_INSEL_PRS   : 0)
279     | (init->coist               ?   TIMER_CC_CTRL_COIST       : 0)
280     | (init->outInvert           ?   TIMER_CC_CTRL_OUTINV      : 0)
281 #if defined(_TIMER_CC_CTRL_PRSCONF_MASK)
282     | ((uint32_t)init->prsOutput << _TIMER_CC_CTRL_PRSCONF_SHIFT)
283 #endif
284   ;
285 #endif
286 }
287 
288 #if defined(_TIMER_DTCTRL_MASK)
289 /***************************************************************************//**
290  * @brief
291  *   Initialize the TIMER DTI unit.
292  *
293  * @param[in] timer
294  *   A pointer to the TIMER peripheral register block.
295  *
296  * @param[in] init
297  *   A pointer to the TIMER DTI initialization structure.
298  ******************************************************************************/
TIMER_InitDTI(TIMER_TypeDef * timer,const TIMER_InitDTI_TypeDef * init)299 void TIMER_InitDTI(TIMER_TypeDef *timer, const TIMER_InitDTI_TypeDef *init)
300 {
301   EFM_ASSERT(TIMER_SupportsDTI(timer));
302 
303   /* Make sure the DTI unit is disabled while initializing. */
304   TIMER_EnableDTI(timer, false);
305 
306 #if defined (_TIMER_DTCFG_MASK)
307   TIMER_SyncWait(timer);
308   timer->EN_CLR = TIMER_EN_EN;
309 #if defined(_TIMER_EN_DISABLING_MASK)
310   while (timer->EN & _TIMER_EN_DISABLING_MASK) {
311   }
312 #endif
313   timer->DTCFG = (init->autoRestart       ?   TIMER_DTCFG_DTDAS   : 0)
314                  | (init->enablePrsSource ?   TIMER_DTCFG_DTPRSEN : 0);
315   if (init->enablePrsSource) {
316     timerPrsConfig(timer, TIMER_INPUT_CHANNEL_DTI, init->prsSel, true);
317   }
318 
319   timer->DTTIMECFG =
320     ((uint32_t)init->prescale   << _TIMER_DTTIMECFG_DTPRESC_SHIFT)
321     | ((uint32_t)init->riseTime << _TIMER_DTTIMECFG_DTRISET_SHIFT)
322     | ((uint32_t)init->fallTime << _TIMER_DTTIMECFG_DTFALLT_SHIFT);
323 
324   timer->DTFCFG =
325     (init->enableFaultSourceCoreLockup ?   TIMER_DTFCFG_DTLOCKUPFEN : 0)
326     | (init->enableFaultSourceDebugger ?   TIMER_DTFCFG_DTDBGFEN    : 0)
327     | (init->enableFaultSourcePrsSel0  ?   TIMER_DTFCFG_DTPRS0FEN   : 0)
328     | (init->enableFaultSourcePrsSel1  ?   TIMER_DTFCFG_DTPRS1FEN   : 0)
329     | ((uint32_t)(init->faultAction)   << _TIMER_DTFCFG_DTFA_SHIFT);
330 
331   if (init->enableFaultSourcePrsSel0) {
332     timerPrsConfig(timer, TIMER_INPUT_CHANNEL_DTIFS1, init->faultSourcePrsSel0, true);
333   }
334   if (init->enableFaultSourcePrsSel1) {
335     timerPrsConfig(timer, TIMER_INPUT_CHANNEL_DTIFS2, init->faultSourcePrsSel1, true);
336   }
337 
338   timer->EN_SET = TIMER_EN_EN;
339 #endif
340 
341 #if defined(TIMER_DTCTRL_DTDAS)
342   /* Set up the DTCTRL register.
343      The enable bit will be set at the end of the function if specified. */
344   timer->DTCTRL =
345     (init->autoRestart              ?   TIMER_DTCTRL_DTDAS   : 0)
346     | (init->activeLowOut           ?   TIMER_DTCTRL_DTIPOL  : 0)
347     | (init->invertComplementaryOut ?   TIMER_DTCTRL_DTCINV  : 0)
348     | (init->enablePrsSource        ?   TIMER_DTCTRL_DTPRSEN : 0)
349     | ((uint32_t)(init->prsSel)     << _TIMER_DTCTRL_DTPRSSEL_SHIFT);
350 #endif
351 
352 #if defined (TIMER_DTCFG_DTDAS)
353   timer->DTCTRL = (init->activeLowOut             ? TIMER_DTCTRL_DTIPOL  : 0)
354                   | (init->invertComplementaryOut ? TIMER_DTCTRL_DTCINV  : 0);
355 #endif
356 
357 #if defined (_TIMER_DTTIME_DTPRESC_SHIFT)
358   /* Set up the DTTIME register. */
359   timer->DTTIME = ((uint32_t)init->prescale   << _TIMER_DTTIME_DTPRESC_SHIFT)
360                   | ((uint32_t)init->riseTime << _TIMER_DTTIME_DTRISET_SHIFT)
361                   | ((uint32_t)init->fallTime << _TIMER_DTTIME_DTFALLT_SHIFT);
362 #endif
363 
364 #if defined (TIMER_DTFC_DTLOCKUPFEN)
365   /* Set up the DTFC register. */
366   timer->DTFC =
367     (init->enableFaultSourceCoreLockup    ?   TIMER_DTFC_DTLOCKUPFEN : 0)
368     | (init->enableFaultSourceDebugger    ?   TIMER_DTFC_DTDBGFEN    : 0)
369     | (init->enableFaultSourcePrsSel0     ?   TIMER_DTFC_DTPRS0FEN   : 0)
370     | (init->enableFaultSourcePrsSel1     ?   TIMER_DTFC_DTPRS1FEN   : 0)
371     | ((uint32_t)init->faultAction        << _TIMER_DTFC_DTFA_SHIFT)
372     | ((uint32_t)init->faultSourcePrsSel0 << _TIMER_DTFC_DTPRS0FSEL_SHIFT)
373     | ((uint32_t)init->faultSourcePrsSel1 << _TIMER_DTFC_DTPRS1FSEL_SHIFT);
374 #endif
375 
376   /* Set up the DTOGEN register. */
377   timer->DTOGEN = init->outputsEnableMask;
378 
379   /* Clear any previous DTI faults.  */
380   TIMER_ClearDTIFault(timer, TIMER_GetDTIFault(timer));
381 
382   /* Enable/disable before returning. */
383   TIMER_EnableDTI(timer, init->enable);
384 }
385 #endif
386 
387 /***************************************************************************//**
388  * @brief
389  *   Reset the TIMER to the same state that it was in after a hardware reset.
390  *
391  * @note
392  *   The ROUTE register is NOT reset by this function to allow for
393  *   a centralized setup of this feature.
394  *
395  * @param[in] timer
396  *   A pointer to the TIMER peripheral register block.
397  ******************************************************************************/
TIMER_Reset(TIMER_TypeDef * timer)398 void TIMER_Reset(TIMER_TypeDef *timer)
399 {
400   int i;
401 
402   EFM_ASSERT(TIMER_REF_VALID(timer));
403 
404 #if defined(TIMER_EN_EN)
405   timer->EN_SET = TIMER_EN_EN;
406 #endif
407 
408   /* Make sure disabled first, before resetting other registers. */
409   timer->CMD = TIMER_CMD_STOP;
410 
411   timer->CTRL = _TIMER_CTRL_RESETVALUE;
412   timer->IEN  = _TIMER_IEN_RESETVALUE;
413 #if defined (TIMER_HAS_SET_CLEAR)
414   timer->IF_CLR = _TIMER_IF_MASK;
415 #else
416   timer->IFC  = _TIMER_IFC_MASK;
417 #endif
418   timer->TOPB = _TIMER_TOPB_RESETVALUE;
419   /* Write TOP after TOPB to invalidate TOPB (clear TIMER_STATUS_TOPBV). */
420   timer->TOP  = _TIMER_TOP_RESETVALUE;
421   timer->CNT  = _TIMER_CNT_RESETVALUE;
422   /* Do not reset the route register, setting should be done independently. */
423   /* Note: The ROUTE register may be locked by the DTLOCK register. */
424 
425 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
426   for (i = 0; TIMER_REF_CH_VALID(timer, i); i++) {
427 #else
428   for (i = 0; TIMER_CH_VALID(i); i++) {
429 #endif
430     timer->CC[i].CTRL = _TIMER_CC_CTRL_RESETVALUE;
431 #if defined (_TIMER_CC_CCV_RESETVALUE) && defined (_TIMER_CC_CCVB_RESETVALUE)
432     timer->CC[i].CCV  = _TIMER_CC_CCV_RESETVALUE;
433     timer->CC[i].CCVB = _TIMER_CC_CCVB_RESETVALUE;
434 #endif
435 #if defined (_TIMER_CC_OC_RESETVALUE) && defined (_TIMER_CC_OCB_RESETVALUE) \
436     && defined (_TIMER_CC_ICF_RESETVALUE) && defined (_TIMER_CC_ICOF_RESETVALUE)
437     timer->CC[i].OC     = _TIMER_CC_OC_RESETVALUE;
438     timer->CC[i].OCB    = _TIMER_CC_OCB_RESETVALUE;
439 #endif
440   }
441 
442   /* Reset dead time insertion module, which has no effect on timers without DTI. */
443 #if defined(_TIMER_DTCFG_MASK)
444   timer->DTLOCK   = TIMER_DTLOCK_DTILOCKKEY_UNLOCK;
445   timer->DTCTRL   = _TIMER_DTCTRL_RESETVALUE;
446   timer->DTOGEN   = _TIMER_DTOGEN_RESETVALUE;
447   timer->DTFAULTC = _TIMER_DTFAULTC_MASK;
448 #elif defined(TIMER_DTLOCK_LOCKKEY_UNLOCK)
449   /* Unlock DTI registers first if locked. */
450   timer->DTLOCK   = TIMER_DTLOCK_LOCKKEY_UNLOCK;
451   timer->DTCTRL   = _TIMER_DTCTRL_RESETVALUE;
452   timer->DTTIME   = _TIMER_DTTIME_RESETVALUE;
453   timer->DTFC     = _TIMER_DTFC_RESETVALUE;
454   timer->DTOGEN   = _TIMER_DTOGEN_RESETVALUE;
455   timer->DTFAULTC = _TIMER_DTFAULTC_MASK;
456 #endif
457 
458 #if defined(_TIMER_CFG_MASK)
459   TIMER_SyncWait(timer);
460   /* CFG registers must be reset after the timer is disabled */
461   timer->EN_CLR = TIMER_EN_EN;
462 #if defined(_TIMER_EN_DISABLING_MASK)
463   while (timer->EN & _TIMER_EN_DISABLING_MASK) {
464   }
465 #endif
466   timer->CFG = _TIMER_CFG_RESETVALUE;
467   for (i = 0; TIMER_CH_VALID(i); i++) {
468     timer->CC[i].CFG = _TIMER_CC_CFG_RESETVALUE;
469   }
470   timer->DTCFG = _TIMER_DTCFG_RESETVALUE;
471   timer->DTFCFG = _TIMER_DTFCFG_RESETVALUE;
472   timer->DTTIMECFG = _TIMER_DTTIMECFG_RESETVALUE;
473 #endif
474 }
475 
476 #if defined(TIMER_STATUS_SYNCBUSY)
477 /**
478  * @brief Wait for pending synchronization to finish
479  *
480  * @param[in] timer
481  */
482 void TIMER_SyncWait(TIMER_TypeDef * timer)
483 {
484   while (((timer->EN & TIMER_EN_EN) != 0U)
485          && ((timer->STATUS & TIMER_STATUS_SYNCBUSY) != 0U)) {
486     /* Wait for synchronization to complete */
487   }
488 }
489 #endif
490 
491 /** @} (end addtogroup timer) */
492 #endif /* defined(TIMER_COUNT) && (TIMER_COUNT > 0) */
493