1 /***************************************************************************//**
2 * @file
3 * @brief Pulse Counter (PCNT) 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 #ifndef EM_PCNT_H
32 #define EM_PCNT_H
33
34 #include "em_device.h"
35 #if defined(PCNT_COUNT) && (PCNT_COUNT > 0)
36
37 #include <stdbool.h>
38
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42
43 /***************************************************************************//**
44 * @addtogroup pcnt
45 * @{
46 ******************************************************************************/
47
48 /*******************************************************************************
49 ******************************* DEFINES ***********************************
50 ******************************************************************************/
51 /** PCNT0 Counter register size. */
52 #if defined(_EFM32_GECKO_FAMILY)
53 #define PCNT0_CNT_SIZE (8) /**< PCNT0 counter is 8 bits. */
54 #else
55 #define PCNT0_CNT_SIZE (16) /**< PCNT0 counter is 16 bits. */
56 #endif
57
58 #ifdef PCNT1
59 /** PCNT1 Counter register size. */
60 #if defined(_SILICON_LABS_32B_SERIES_0)
61 #define PCNT1_CNT_SIZE (8) /**< PCNT1 counter is 8 bits. */
62 #else
63 #define PCNT1_CNT_SIZE (16) /**< PCNT1 counter is 16 bits. */
64 #endif
65 #endif
66
67 #ifdef PCNT2
68 /** PCNT2 Counter register size. */
69 #if defined(_SILICON_LABS_32B_SERIES_0)
70 #define PCNT2_CNT_SIZE (8) /**< PCNT2 counter is 8 bits. */
71 #else
72 #define PCNT2_CNT_SIZE (16) /**< PCNT2 counter is 16 bits. */
73 #endif
74 #endif
75
76 /* Define values that can be used in case some state/mode are not defined for some devices.*/
77 /** PCNT mode disable. */
78 #define PCNT_MODE_DISABLE 0xFF
79 /** PCNT count event is none. */
80 #define PCNT_CNT_EVENT_NONE 0xFF
81
82 /*******************************************************************************
83 ******************************** ENUMS ************************************
84 ******************************************************************************/
85
86 /** Mode selection. */
87 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
88 typedef enum {
89 /** Disable pulse counter. */
90 pcntModeDisable = _PCNT_CTRL_MODE_DISABLE,
91
92 /** Single input LFACLK oversampling mode (available in EM0-EM2). */
93 pcntModeOvsSingle = _PCNT_CTRL_MODE_OVSSINGLE,
94
95 /** Externally clocked single input counter mode (available in EM0-EM3). */
96 pcntModeExtSingle = _PCNT_CTRL_MODE_EXTCLKSINGLE,
97
98 /** Externally clocked quadrature decoder mode (available in EM0-EM3). */
99 pcntModeExtQuad = _PCNT_CTRL_MODE_EXTCLKQUAD,
100
101 #if defined(_PCNT_CTRL_MODE_OVSQUAD1X)
102 /** LFACLK oversampling quadrature decoder 1X mode (available in EM0-EM2). */
103 pcntModeOvsQuad1 = _PCNT_CTRL_MODE_OVSQUAD1X,
104
105 /** LFACLK oversampling quadrature decoder 2X mode (available in EM0-EM2). */
106 pcntModeOvsQuad2 = _PCNT_CTRL_MODE_OVSQUAD2X,
107
108 /** LFACLK oversampling quadrature decoder 4X mode (available in EM0-EM2). */
109 pcntModeOvsQuad4 = _PCNT_CTRL_MODE_OVSQUAD4X,
110 #endif
111 } PCNT_Mode_TypeDef;
112
113 #else
114 typedef enum {
115 /** Disable pulse counter. */
116 pcntModeDisable = PCNT_MODE_DISABLE,
117
118 /** Single input LFACLK oversampling mode (available in EM0-EM2). */
119 pcntModeOvsSingle = _PCNT_CFG_MODE_OVSSINGLE,
120
121 /** Externally clocked single input counter mode (available in EM0-EM3). */
122 pcntModeExtSingle = _PCNT_CFG_MODE_EXTCLKSINGLE,
123
124 /** Externally clocked quadrature decoder mode (available in EM0-EM3). */
125 pcntModeExtQuad = _PCNT_CFG_MODE_EXTCLKQUAD,
126
127 /** LFACLK oversampling quadrature decoder 1X mode (available in EM0-EM2). */
128 pcntModeOvsQuad1 = _PCNT_CFG_MODE_OVSQUAD1X,
129
130 /** LFACLK oversampling quadrature decoder 2X mode (available in EM0-EM2). */
131 pcntModeOvsQuad2 = _PCNT_CFG_MODE_OVSQUAD2X,
132
133 /** LFACLK oversampling quadrature decoder 4X mode (available in EM0-EM2). */
134 pcntModeOvsQuad4 = _PCNT_CFG_MODE_OVSQUAD4X,
135 } PCNT_Mode_TypeDef;
136 #endif
137
138 #if defined(_PCNT_CTRL_CNTEV_MASK)
139 /** Counter event selection.
140 * Note: unshifted values are being used for enumeration because multiple
141 * configuration structure members use this type definition. */
142 typedef enum {
143 /** Counts up on up-count and down on down-count events. */
144 pcntCntEventBoth = _PCNT_CTRL_CNTEV_BOTH,
145
146 /** Only counts up on up-count events. */
147 pcntCntEventUp = _PCNT_CTRL_CNTEV_UP,
148
149 /** Only counts down on down-count events. */
150 pcntCntEventDown = _PCNT_CTRL_CNTEV_DOWN,
151
152 /** Never counts. */
153 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
154 pcntCntEventNone = _PCNT_CTRL_CNTEV_NONE
155 #else
156 pcntCntEventNone = PCNT_CNT_EVENT_NONE
157 #endif
158 } PCNT_CntEvent_TypeDef;
159 #endif
160
161 /** PRS sources for @p s0PRS and @p s1PRS. */
162 #if defined(_PCNT_INPUT_MASK)
163 typedef enum {
164 pcntPRSCh0 = 0, /**< PRS channel 0. */
165 pcntPRSCh1 = 1, /**< PRS channel 1. */
166 pcntPRSCh2 = 2, /**< PRS channel 2. */
167 pcntPRSCh3 = 3, /**< PRS channel 3. */
168 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH4)
169 pcntPRSCh4 = 4, /**< PRS channel 4. */
170 #endif
171 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH5)
172 pcntPRSCh5 = 5, /**< PRS channel 5. */
173 #endif
174 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH6)
175 pcntPRSCh6 = 6, /**< PRS channel 6. */
176 #endif
177 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH7)
178 pcntPRSCh7 = 7, /**< PRS channel 7. */
179 #endif
180 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH8)
181 pcntPRSCh8 = 8, /**< PRS channel 8. */
182 #endif
183 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH9)
184 pcntPRSCh9 = 9, /**< PRS channel 9. */
185 #endif
186 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH10)
187 pcntPRSCh10 = 10, /**< PRS channel 10. */
188 #endif
189 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH11)
190 pcntPRSCh11 = 11, /**< PRS channel 11. */
191 #endif
192 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH12)
193 pcntPRSCh12 = 12, /**< PRS channel 12. */
194 #endif
195 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH13)
196 pcntPRSCh13 = 13, /**< PRS channel 13. */
197 #endif
198 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH14)
199 pcntPRSCh14 = 14, /**< PRS channel 14. */
200 #endif
201 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH15)
202 pcntPRSCh15 = 15, /**< PRS channel 15. */
203 #endif
204 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH16)
205 pcntPRSCh16 = 16, /**< PRS channel 16. */
206 #endif
207 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH17)
208 pcntPRSCh17 = 17, /**< PRS channel 17. */
209 #endif
210 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH18)
211 pcntPRSCh18 = 18, /**< PRS channel 18. */
212 #endif
213 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH19)
214 pcntPRSCh19 = 19, /**< PRS channel 19. */
215 #endif
216 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH20)
217 pcntPRSCh20 = 20, /**< PRS channel 20. */
218 #endif
219 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH21)
220 pcntPRSCh21 = 21, /**< PRS channel 21. */
221 #endif
222 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH22)
223 pcntPRSCh22 = 22, /**< PRS channel 22. */
224 #endif
225 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH23)
226 pcntPRSCh23 = 23, /**< PRS channel 23. */
227 #endif
228 } PCNT_PRSSel_TypeDef;
229 #elif defined(_SILICON_LABS_32B_SERIES_2)
230 typedef unsigned int PCNT_PRSSel_TypeDef;
231 #endif
232
233 #if defined(_PCNT_INPUT_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
234 /** PRS inputs of PCNT. */
235 typedef enum {
236 pcntPRSInputS0 = 0, /** PRS input 0. */
237 pcntPRSInputS1 = 1 /** PRS input 1. */
238 } PCNT_PRSInput_TypeDef;
239 #endif
240
241 /*******************************************************************************
242 ******************************* STRUCTS ***********************************
243 ******************************************************************************/
244
245 /** Initialization structure. */
246 typedef struct {
247 /** Mode to operate in. */
248 PCNT_Mode_TypeDef mode;
249
250 /** Initial counter value (refer to reference manual for max value allowed).
251 * Only used for #pcntModeOvsSingle (and possibly #pcntModeDisable) modes.
252 * If using #pcntModeExtSingle or #pcntModeExtQuad modes, counter
253 * value is reset to HW reset value. */
254 uint32_t counter;
255
256 /** Initial top value (refer to reference manual for max value allowed).
257 * Only used for #pcntModeOvsSingle (and possibly #pcntModeDisable) modes.
258 * If using #pcntModeExtSingle or #pcntModeExtQuad modes, top
259 * value is reset to HW reset value. */
260 uint32_t top;
261
262 /** Polarity of incoming edge.
263 * @li #pcntModeExtSingle mode - if false, positive edges are counted,
264 * otherwise negative edges.
265 * @li #pcntModeExtQuad mode - if true, counting direction is inverted. */
266 bool negEdge;
267
268 /** Counting direction, only applicable for #pcntModeOvsSingle and
269 * #pcntModeExtSingle modes. */
270 bool countDown;
271
272 /** Enable filter, only available in #pcntModeOvsSingle* mode. */
273 bool filter;
274
275 #if defined(_SILICON_LABS_32B_SERIES_2)
276 /** Enable/disable PCNT counting during debug halt. Only in OVSSINGLE and OVSQUAD modes. */
277 bool debugHalt;
278 #endif
279
280 #if defined(PCNT_CTRL_HYST) || defined(_SILICON_LABS_32B_SERIES_2)
281 /** Set to true to enable hysteresis. When enabled, PCNT will always
282 * overflow and underflow to TOP/2. */
283 bool hyst;
284 #endif
285
286 #if defined(PCNT_CTRL_S1CDIR)
287 /** Set to true to enable S1 to determine the direction of counting in
288 * OVSSINGLE or EXTCLKSINGLE modes. @n
289 * When S1 is high, the count direction is given by CNTDIR, and when S1 is
290 * low, the count direction is the opposite. */
291 bool s1CntDir;
292 #endif
293
294 #if defined(_PCNT_CTRL_CNTEV_SHIFT)
295 /** Selects whether the regular counter responds to up-count events,
296 * down-count events, both, or none. */
297 PCNT_CntEvent_TypeDef cntEvent;
298 #endif
299
300 #if defined(_PCNT_CTRL_AUXCNTEV_SHIFT)
301 /** Selects whether the auxiliary counter responds to up-count events,
302 * down-count events, both, or none. */
303 PCNT_CntEvent_TypeDef auxCntEvent;
304 #endif
305
306 #if defined(_PCNT_INPUT_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
307 /** Select PRS channel as input to S0IN in PCNTx_INPUT register. */
308 PCNT_PRSSel_TypeDef s0PRS;
309
310 /** Select PRS channel as input to S1IN in PCNTx_INPUT register. */
311 PCNT_PRSSel_TypeDef s1PRS;
312 #endif
313 } PCNT_Init_TypeDef;
314
315 /** Default Debug. */
316 #if defined(_SILICON_LABS_32B_SERIES_2)
317 #define DEFAULT_DEBUG_HALT true,
318 #else
319 #define DEFAULT_DEBUG_HALT
320 #endif
321
322 /** Default Mode. */
323 #define DEFAULT_MODE pcntModeDisable, /**< Disabled by default. */
324
325 /** Default Hysteresis. */
326 #if defined(PCNT_CTRL_HYST) || defined(_SILICON_LABS_32B_SERIES_2)
327 #define DEFAULT_HYST false, /**< Hysteresis disabled. */
328 #else
329 #define DEFAULT_HYST
330 #endif
331
332 /** Default counter direction*/
333 #if defined(PCNT_CTRL_S1CDIR)
334 #define DEFAULT_CDIR true, /**< Counter direction is given by CNTDIR. */
335 #else
336 #define DEFAULT_CDIR
337 #endif
338
339 /** Default count event*/
340 #if defined(_PCNT_CTRL_CNTEV_SHIFT)
341 #define DEFAULT_CNTEV pcntCntEventUp, /**< Regular counter counts up on upcount events. */
342 #else
343 #define DEFAULT_CNTEV
344 #endif
345
346 /** Default auxiliary count event. */
347 #if defined(_PCNT_CTRL_AUXCNTEV_SHIFT)
348 #define DEFAULT_AUXCNTEV pcntCntEventNone, /**< Auxiliary counter doesn't respond to events. */
349 #else
350 #define DEFAULT_AUXCNTEV
351 #endif
352
353 /** Default selected PRS channel as S0IN and S1IN. */
354 #if defined(_PCNT_INPUT_MASK)
355 #define DEFAULT_PRS_CH pcntPRSCh0, /**< PRS channel 0 selected as S0IN and as S1IN. */
356 #elif defined(_SILICON_LABS_32B_SERIES_2)
357 #define DEFAULT_PRS_CH 0u,
358 #else
359 #define DEFAULT_PRS_CH
360 #endif
361
362 /** Default configuration for PCNT initialization structure. */
363 #define PCNT_INIT_DEFAULT \
364 { \
365 DEFAULT_MODE /* Default mode. */ \
366 _PCNT_CNT_RESETVALUE, /* Default counter HW reset value. */ \
367 _PCNT_TOP_RESETVALUE, /* Default counter HW reset value. */ \
368 false, /* Use positive edge. */ \
369 false, /* Up-counting. */ \
370 false, /* Filter disabled. */ \
371 DEFAULT_DEBUG_HALT /* Debug Halt enabled. */ \
372 DEFAULT_HYST /* Default Hysteresis. */ \
373 DEFAULT_CDIR /* Default CNTDIR. */ \
374 DEFAULT_CNTEV /* Faults CNTEV. */ \
375 DEFAULT_AUXCNTEV /* Default AUXCNTEV. */ \
376 DEFAULT_PRS_CH /* PRS channel 0 selected as S0IN. */ \
377 DEFAULT_PRS_CH /* PRS channel 0 selected as S1IN. */ \
378 }
379
380 #if defined(PCNT_OVSCFG_FILTLEN_DEFAULT) || defined(_SILICON_LABS_32B_SERIES_2)
381 /** Filter initialization structure */
382 typedef struct {
383 /** Used only in OVSINGLE and OVSQUAD1X-4X modes. To use this, enable filter by
384 * setting filter to true during PCNT_Init(). Filter length = (filtLen + 5) LFACLK cycles. */
385 uint8_t filtLen;
386
387 /** When set, removes flutter from Quaddecoder inputs S0IN and S1IN.
388 * Available only in OVSQUAD1X-4X modes. */
389 bool flutterrm;
390 } PCNT_Filter_TypeDef;
391 #endif
392
393 /** Default configuration for PCNT initialization structure. */
394 #if defined(PCNT_OVSCFG_FILTLEN_DEFAULT) || defined(_SILICON_LABS_32B_SERIES_2)
395 #define PCNT_FILTER_DEFAULT \
396 { \
397 0, /* Default length is 5 LFACLK cycles. */ \
398 false /* No flutter removal. */ \
399 }
400 #endif
401
402 #if defined(PCNT_CTRL_TCCMODE_DEFAULT)
403
404 /** Modes for Triggered Compare and Clear module. */
405 typedef enum {
406 /** Triggered compare and clear not enabled. */
407 tccModeDisabled = _PCNT_CTRL_TCCMODE_DISABLED,
408
409 /** Compare and clear performed on each (optionally prescaled) LFA clock cycle. */
410 tccModeLFA = _PCNT_CTRL_TCCMODE_LFA,
411
412 /** Compare and clear performed on PRS edges. Polarity defined by prsPolarity. */
413 tccModePRS = _PCNT_CTRL_TCCMODE_PRS
414 } PCNT_TCCMode_TypeDef;
415
416 /** Prescaler values for LFA compare and clear events. Only has effect when TCC mode is LFA. */
417 typedef enum {
418 /** Compare and clear event each LFA cycle. */
419 tccPrescDiv1 = _PCNT_CTRL_TCCPRESC_DIV1,
420
421 /** Compare and clear event every other LFA cycle. */
422 tccPrescDiv2 = _PCNT_CTRL_TCCPRESC_DIV2,
423
424 /** Compare and clear event every 4th LFA cycle. */
425 tccPrescDiv4 = _PCNT_CTRL_TCCPRESC_DIV4,
426
427 /** Compare and clear event every 8th LFA cycle. */
428 tccPrescDiv8 = _PCNT_CTRL_TCCPRESC_DIV8
429 } PCNT_TCCPresc_Typedef;
430
431 /** Compare modes for TCC module. */
432 typedef enum {
433 /** Compare match if PCNT_CNT is less than, or equal to PCNT_TOP. */
434 tccCompLTOE = _PCNT_CTRL_TCCCOMP_LTOE,
435
436 /** Compare match if PCNT_CNT is greater than or equal to PCNT_TOP. */
437 tccCompGTOE = _PCNT_CTRL_TCCCOMP_GTOE,
438
439 /** Compare match if PCNT_CNT is less than, or equal to PCNT_TOP[15:8]], and greater
440 * than, or equal to PCNT_TOP[7:0]. */
441 tccCompRange = _PCNT_CTRL_TCCCOMP_RANGE
442 } PCNT_TCCComp_Typedef;
443
444 /** TCC initialization structure. */
445 typedef struct {
446 /** Mode to operate in. */
447 PCNT_TCCMode_TypeDef mode;
448
449 /** Prescaler value for LFACLK in LFA mode. */
450 PCNT_TCCPresc_Typedef prescaler;
451
452 /** Choose the event that will trigger a clear. */
453 PCNT_TCCComp_Typedef compare;
454
455 /** PRS input to TCC module, either for gating the PCNT clock, triggering the TCC comparison, or both. */
456 PCNT_PRSSel_TypeDef tccPRS;
457
458 /** TCC PRS input polarity. @n
459 * False = Rising edge for comparison trigger, and PCNT clock gated when PRS signal is high. @n
460 * True = Falling edge for comparison trigger, and PCNT clock gated when PRS signal is low. */
461 bool prsPolarity;
462
463 /** Enable gating PCNT input clock through TCC PRS signal.
464 * Polarity selection is done through prsPolarity. */
465 bool prsGateEnable;
466 } PCNT_TCC_TypeDef;
467
468 /** TCC Default. */
469 #define PCNT_TCC_DEFAULT \
470 { \
471 tccModeDisabled, /* Disabled by default. */ \
472 tccPrescDiv1, /* Do not prescale LFA clock in LFA mode. */ \
473 tccCompLTOE, /* Clear when CNT <= TOP. */ \
474 pcntPRSCh0, /* Select PRS channel 0 as input to TCC. */ \
475 false, /* PRS polarity is rising edge, and gate when 1. */ \
476 false /* Do not gate PCNT counter input. */ \
477 }
478
479 #endif
480 /* defined(PCNT_CTRL_TCCMODE_DEFAULT) */
481
482 /*******************************************************************************
483 ***************************** PROTOTYPES **********************************
484 ******************************************************************************/
485
486 /***************************************************************************//**
487 * @brief
488 * Get the pulse counter value.
489 *
490 * @param[in] pcnt
491 * Pointer to the PCNT peripheral register block.
492 *
493 * @return
494 * Current pulse counter value.
495 ******************************************************************************/
PCNT_CounterGet(PCNT_TypeDef * pcnt)496 __STATIC_INLINE uint32_t PCNT_CounterGet(PCNT_TypeDef *pcnt)
497 {
498 return pcnt->CNT;
499 }
500
501 #if defined(_PCNT_AUXCNT_MASK)
502 /***************************************************************************//**
503 * @brief
504 * Get the auxiliary counter value.
505 *
506 * @param[in] pcnt
507 * Pointer to the PCNT peripheral register block.
508 *
509 * @return
510 * Current auxiliary counter value.
511 ******************************************************************************/
PCNT_AuxCounterGet(PCNT_TypeDef * pcnt)512 __STATIC_INLINE uint32_t PCNT_AuxCounterGet(PCNT_TypeDef *pcnt)
513 {
514 return pcnt->AUXCNT;
515 }
516 #endif
517
518 void PCNT_CounterReset(PCNT_TypeDef *pcnt);
519 void PCNT_CounterTopSet(PCNT_TypeDef *pcnt, uint32_t count, uint32_t top);
520
521 /***************************************************************************//**
522 * @brief
523 * Set a counter value.
524 *
525 * @details
526 * Pulse counter is disabled while changing counter value and re-enabled
527 * (if originally enabled) when counter value has been set.
528 *
529 * @note
530 * This function will stall until synchronization to low-frequency domain is
531 * completed. For that reason, it should normally not be used when using
532 * an external clock to clock the PCNT module since stall time may be
533 * undefined in that case. The counter should normally only be set when
534 * operating in (or about to enable) #pcntModeOvsSingle mode.
535 *
536 * @param[in] pcnt
537 * Pointer to the PCNT peripheral register block.
538 *
539 * @param[in] count
540 * Value to set in counter register.
541 ******************************************************************************/
PCNT_CounterSet(PCNT_TypeDef * pcnt,uint32_t count)542 __STATIC_INLINE void PCNT_CounterSet(PCNT_TypeDef *pcnt, uint32_t count)
543 {
544 PCNT_CounterTopSet(pcnt, count, pcnt->TOP);
545 }
546
547 void PCNT_Enable(PCNT_TypeDef *pcnt, PCNT_Mode_TypeDef mode);
548 bool PCNT_IsEnabled(PCNT_TypeDef *pcnt);
549 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
550 void PCNT_FreezeEnable(PCNT_TypeDef *pcnt, bool enable);
551 #endif
552 void PCNT_Init(PCNT_TypeDef *pcnt, const PCNT_Init_TypeDef *init);
553
554 #if defined(PCNT_OVSCFG_FILTLEN_DEFAULT) || defined(_SILICON_LABS_32B_SERIES_2)
555 void PCNT_FilterConfiguration(PCNT_TypeDef *pcnt, const PCNT_Filter_TypeDef *config, bool enable);
556 #endif
557
558 #if defined(_PCNT_INPUT_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
559 void PCNT_PRSInputEnable(PCNT_TypeDef *pcnt,
560 PCNT_PRSInput_TypeDef prsInput,
561 bool enable);
562 #endif
563
564 #if defined(PCNT_CTRL_TCCMODE_DEFAULT)
565 void PCNT_TCCConfiguration(PCNT_TypeDef *pcnt, const PCNT_TCC_TypeDef *config);
566 #endif
567
568 /***************************************************************************//**
569 * @brief
570 * Clear one or more pending PCNT interrupts.
571 *
572 * @param[in] pcnt
573 * Pointer to the PCNT peripheral register block.
574 *
575 * @param[in] flags
576 * Pending PCNT interrupt source to clear. Use a bitwise logic OR combination
577 * of valid interrupt flags for the PCNT module (PCNT_IF_nnn).
578 ******************************************************************************/
PCNT_IntClear(PCNT_TypeDef * pcnt,uint32_t flags)579 __STATIC_INLINE void PCNT_IntClear(PCNT_TypeDef *pcnt, uint32_t flags)
580 {
581 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
582 pcnt->IFC = flags;
583 #else
584 pcnt->IF_CLR = flags;
585 #endif
586 }
587
588 /***************************************************************************//**
589 * @brief
590 * Disable one or more PCNT interrupts.
591 *
592 * @param[in] pcnt
593 * Pointer to the PCNT peripheral register block.
594 *
595 * @param[in] flags
596 * PCNT interrupt sources to disable. Use a bitwise logic OR combination of
597 * valid interrupt flags for PCNT module (PCNT_IF_nnn).
598 ******************************************************************************/
PCNT_IntDisable(PCNT_TypeDef * pcnt,uint32_t flags)599 __STATIC_INLINE void PCNT_IntDisable(PCNT_TypeDef *pcnt, uint32_t flags)
600 {
601 #if defined(PCNT_HAS_SET_CLEAR)
602 pcnt->IEN_CLR = flags;
603 #else
604 pcnt->IEN &= ~flags;
605 #endif
606 }
607
608 /***************************************************************************//**
609 * @brief
610 * Enable one or more PCNT interrupts.
611 *
612 * @note
613 * Depending on the use, a pending interrupt may already be set prior to
614 * enabling the interrupt. To ignore a pending interrupt, consider using
615 * PCNT_IntClear() prior to enabling the interrupt.
616 *
617 * @param[in] pcnt
618 * Pointer to the PCNT peripheral register block.
619 *
620 * @param[in] flags
621 * PCNT interrupt sources to enable. Use a bitwise logic OR combination of
622 * valid interrupt flags for PCNT module (PCNT_IF_nnn).
623 ******************************************************************************/
PCNT_IntEnable(PCNT_TypeDef * pcnt,uint32_t flags)624 __STATIC_INLINE void PCNT_IntEnable(PCNT_TypeDef *pcnt, uint32_t flags)
625 {
626 #if defined(PCNT_HAS_SET_CLEAR)
627 pcnt->IEN_SET = flags;
628 #else
629 pcnt->IEN |= flags;
630 #endif
631 }
632
633 /***************************************************************************//**
634 * @brief
635 * Get pending PCNT interrupt flags.
636 *
637 * @note
638 * The event bits are not cleared by the use of this function.
639 *
640 * @param[in] pcnt
641 * Pointer to the PCNT peripheral register block.
642 *
643 * @return
644 * PCNT interrupt sources pending. A bitwise logic OR combination of valid
645 * interrupt flags for PCNT module (PCNT_IF_nnn).
646 ******************************************************************************/
PCNT_IntGet(PCNT_TypeDef * pcnt)647 __STATIC_INLINE uint32_t PCNT_IntGet(PCNT_TypeDef *pcnt)
648 {
649 return pcnt->IF;
650 }
651
652 /***************************************************************************//**
653 * @brief
654 * Get enabled and pending PCNT interrupt flags.
655 *
656 * @details
657 * Useful for handling more interrupt sources in the same interrupt handler.
658 *
659 * @note
660 * The event bits are not cleared by the use of this function.
661 *
662 * @param[in] pcnt
663 * Pointer to thePCNT peripheral register block.
664 *
665 * @return
666 * Pending and enabled PCNT interrupt sources.
667 * The return value is the bitwise AND combination of
668 * - the OR combination of enabled interrupt sources in PCNT_IEN_nnn
669 * register (PCNT_IEN_nnn) and
670 * - the OR combination of valid interrupt flags of the PCNT module
671 * (PCNT_IF_nnn).
672 ******************************************************************************/
PCNT_IntGetEnabled(PCNT_TypeDef * pcnt)673 __STATIC_INLINE uint32_t PCNT_IntGetEnabled(PCNT_TypeDef *pcnt)
674 {
675 uint32_t ien;
676
677 /* Store pcnt->IEN in temporary variable in order to define explicit order
678 * of volatile accesses. */
679 ien = pcnt->IEN;
680
681 /* Bitwise AND of pending and enabled interrupts. */
682 return pcnt->IF & ien;
683 }
684
685 /***************************************************************************//**
686 * @brief
687 * Set one or more pending PCNT interrupts from SW.
688 *
689 * @param[in] pcnt
690 * Pointer to the PCNT peripheral register block.
691 *
692 * @param[in] flags
693 * PCNT interrupt sources to set to pending. Use a bitwise logic OR combination
694 * of valid interrupt flags for PCNT module (PCNT_IF_nnn).
695 ******************************************************************************/
PCNT_IntSet(PCNT_TypeDef * pcnt,uint32_t flags)696 __STATIC_INLINE void PCNT_IntSet(PCNT_TypeDef *pcnt, uint32_t flags)
697 {
698 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
699 pcnt->IFS = flags;
700 #else
701 pcnt->IF_SET = flags;
702 #endif
703 }
704
705 #if defined(_PCNT_LOCK_MASK)
706 /***************************************************************************//**
707 * @brief
708 * Lock PCNT registers.
709 *
710 * @param[in] pcnt
711 * Pointer to the PCNT peripheral register block.
712 *
713 * @note When PCNT registers are locked PCNT_CFG, PCNT_EN, PCNT_SWRST, PCNT_CMD,
714 * PCNT_CTRL, PCNT_OVSCTRL, PCNT_CNT, PCNT_TOP, and PCNT_TOPB registers
715 * cannot be written to.
716 ******************************************************************************/
PCNT_Lock(PCNT_TypeDef * pcnt)717 __STATIC_INLINE void PCNT_Lock(PCNT_TypeDef *pcnt)
718 {
719 pcnt->LOCK = ~PCNT_LOCK_PCNTLOCKKEY_UNLOCK;
720 }
721 #endif
722
723 #if defined(_PCNT_LOCK_MASK)
724 /***************************************************************************//**
725 * @brief
726 * Unlock PCNT registers.
727 *
728 * @param[in] pcnt
729 * Pointer to thePCNT peripheral register block.
730 ******************************************************************************/
PCNT_Unlock(PCNT_TypeDef * pcnt)731 __STATIC_INLINE void PCNT_Unlock(PCNT_TypeDef *pcnt)
732 {
733 pcnt->LOCK = PCNT_LOCK_PCNTLOCKKEY_UNLOCK;
734 }
735 #endif
736
737 void PCNT_Reset(PCNT_TypeDef *pcnt);
738
739 /***************************************************************************//**
740 * @brief
741 * Get the pulse counter top buffer value.
742 *
743 * @param[in] pcnt
744 * Pointer to the PCNT peripheral register block.
745 *
746 * @return
747 * Current pulse counter top buffer value.
748 ******************************************************************************/
PCNT_TopBufferGet(PCNT_TypeDef * pcnt)749 __STATIC_INLINE uint32_t PCNT_TopBufferGet(PCNT_TypeDef *pcnt)
750 {
751 #if defined(_SILICON_LABS_32B_SERIES_2)
752 while (pcnt->SYNCBUSY & PCNT_SYNCBUSY_TOPB) {
753 }
754 #endif
755 return pcnt->TOPB;
756 }
757
758 void PCNT_TopBufferSet(PCNT_TypeDef *pcnt, uint32_t val);
759
760 /***************************************************************************//**
761 * @brief
762 * Get the pulse counter top value.
763 *
764 * @param[in] pcnt
765 * Pointer to the PCNT peripheral register block.
766 *
767 * @return
768 * Current pulse counter top value.
769 ******************************************************************************/
PCNT_TopGet(PCNT_TypeDef * pcnt)770 __STATIC_INLINE uint32_t PCNT_TopGet(PCNT_TypeDef *pcnt)
771 {
772 #if defined(_SILICON_LABS_32B_SERIES_2)
773 while (pcnt->SYNCBUSY & PCNT_SYNCBUSY_TOP) {
774 }
775 #endif
776 return pcnt->TOP;
777 }
778
779 void PCNT_TopSet(PCNT_TypeDef *pcnt, uint32_t val);
780
781 /***************************************************************************//**
782 * @brief
783 * Wait for an ongoing sync of register(s) to low-frequency domain to complete.
784 *
785 * @param[in] pcnt
786 * A pointer to the PCNT peripheral register block.
787 *
788 * @param[in] mask
789 * A bitmask corresponding to SYNCBUSY register defined bits indicating
790 * registers that must complete any ongoing synchronization.
791 ******************************************************************************/
PCNT_Sync(PCNT_TypeDef * pcnt,uint32_t mask)792 __STATIC_INLINE void PCNT_Sync(PCNT_TypeDef *pcnt, uint32_t mask)
793 {
794 /* Avoid deadlock if modifying the same register twice when freeze mode is
795 * activated. */
796 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
797 if (pcnt->FREEZE & PCNT_FREEZE_REGFREEZE) {
798 return;
799 }
800 #endif
801
802 /* Wait for any pending previous write operation to have been completed in
803 * low-frequency domain. */
804 while (pcnt->SYNCBUSY & mask) {
805 }
806 }
807
808 #if defined(_SILICON_LABS_32B_SERIES_2)
809 /***************************************************************************//**
810 * @brief
811 * Start the main PCNT counter.
812 *
813 * @details
814 * This function will send a start command to the PCNT peripheral. The PCNT
815 * peripheral will use some LF clock ticks before the command is executed.
816 * The @ref PCNT_Sync() function can be used to wait for the start command
817 * to be executed.
818 *
819 * @param[in] pcnt
820 * A pointer to the PCNT peripheral register block.
821 *
822 * @note
823 * This function requires the PCNT to be enabled.
824 ******************************************************************************/
PCNT_StartMainCnt(PCNT_TypeDef * pcnt)825 __STATIC_INLINE void PCNT_StartMainCnt(PCNT_TypeDef *pcnt)
826 {
827 PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
828 pcnt->CMD_SET = PCNT_CMD_STARTCNT;
829 }
830
831 /***************************************************************************//**
832 * @brief
833 * Stop the main PCNT counter.
834 *
835 * @details
836 * This function will send a stop command to the PCNT peripheral. The PCNT
837 * peripheral will use some LF clock ticks before the command is executed.
838 * The @ref PCNT_Sync() function can be used to wait for the stop command
839 * to be executed.
840 *
841 * @param[in] pcnt
842 * A pointer to the PCNT peripheral register block.
843 *
844 * @note
845 * This function requires the PCNT to be enabled.
846 ******************************************************************************/
PCNT_StopMainCnt(PCNT_TypeDef * pcnt)847 __STATIC_INLINE void PCNT_StopMainCnt(PCNT_TypeDef *pcnt)
848 {
849 PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
850 pcnt->CMD_SET = PCNT_CMD_STOPCNT;
851 }
852
853 /***************************************************************************//**
854 * @brief
855 * Start the auxiliary PCNT counter.
856 *
857 * @details
858 * This function will send a start command to the PCNT peripheral. The PCNT
859 * peripheral will use some LF clock ticks before the command is executed.
860 * The @ref PCNT_Sync() function can be used to wait for the start command
861 * to be executed.
862 *
863 * @param[in] pcnt
864 * A pointer to the PCNT peripheral register block.
865 *
866 * @note
867 * This function requires the PCNT to be enabled.
868 ******************************************************************************/
PCNT_StartAuxCnt(PCNT_TypeDef * pcnt)869 __STATIC_INLINE void PCNT_StartAuxCnt(PCNT_TypeDef *pcnt)
870 {
871 PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
872 pcnt->CMD_SET = PCNT_CMD_STARTAUXCNT;
873 }
874
875 /***************************************************************************//**
876 * @brief
877 * Stop the auxiliary PCNT counter.
878 *
879 * @details
880 * This function will send a stop command to the PCNT peripheral. The PCNT
881 * peripheral will use some LF clock ticks before the command is executed.
882 * The @ref PCNT_Sync() function can be used to wait for the stop command
883 * to be executed.
884 *
885 * @param[in] pcnt
886 * A pointer to the PCNT peripheral register block.
887 *
888 * @note
889 * This function requires the PCNT to be enabled.
890 ******************************************************************************/
PCNT_StopAuxCnt(PCNT_TypeDef * pcnt)891 __STATIC_INLINE void PCNT_StopAuxCnt(PCNT_TypeDef *pcnt)
892 {
893 PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
894 pcnt->CMD_SET = PCNT_CMD_STOPAUXCNT;
895 }
896 #endif
897
898 /** @} (end addtogroup pcnt) */
899
900 #ifdef __cplusplus
901 }
902 #endif
903
904 #endif /* defined(PCNT_COUNT) && (PCNT_COUNT > 0) */
905 #endif /* EM_PCNT_H */
906