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