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