1 /***************************************************************************//**
\r
3 * @brief Pulse Counter (PCNT) peripheral API
\r
5 *******************************************************************************
\r
7 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
\r
8 *******************************************************************************
\r
10 * Permission is granted to anyone to use this software for any purpose,
\r
11 * including commercial applications, and to alter it and redistribute it
\r
12 * freely, subject to the following restrictions:
\r
14 * 1. The origin of this software must not be misrepresented; you must not
\r
15 * claim that you wrote the original software.
\r
16 * 2. Altered source versions must be plainly marked as such, and must not be
\r
17 * misrepresented as being the original software.
\r
18 * 3. This notice may not be removed or altered from any source distribution.
\r
20 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
\r
21 * obligation to support this Software. Silicon Labs is providing the
\r
22 * Software "AS IS", with no express or implied warranties of any kind,
\r
23 * including, but not limited to, any implied warranties of merchantability
\r
24 * or fitness for any particular purpose or warranties against infringement
\r
25 * of any proprietary rights of a third party.
\r
27 * Silicon Labs will not be liable for any consequential, incidental, or
\r
28 * special damages, or any other relief, or for any claim by any third party,
\r
29 * arising from your use of this Software.
\r
31 ******************************************************************************/
\r
33 #ifndef __SILICON_LABS_EM_PCNT_H__
\r
34 #define __SILICON_LABS_EM_PCNT_H__
\r
36 #include "em_device.h"
\r
37 #if defined(PCNT_COUNT) && (PCNT_COUNT > 0)
\r
39 #include <stdbool.h>
\r
45 /***************************************************************************//**
\r
46 * @addtogroup EM_Library
\r
48 ******************************************************************************/
\r
50 /***************************************************************************//**
\r
53 ******************************************************************************/
\r
55 /*******************************************************************************
\r
56 ******************************* DEFINES ***********************************
\r
57 ******************************************************************************/
\r
58 /** PCNT0 Counter register size. */
\r
59 #if defined(_EFM32_GECKO_FAMILY)
\r
60 #define PCNT0_CNT_SIZE (8) /* PCNT0 counter is 8 bits. */
\r
62 #define PCNT0_CNT_SIZE (16) /* PCNT0 counter is 16 bits. */
\r
66 /** PCNT1 Counter register size. */
\r
67 #define PCNT1_CNT_SIZE (8) /* PCNT1 counter is 8 bits. */
\r
71 /** PCNT2 Counter register size. */
\r
72 #define PCNT2_CNT_SIZE (8) /* PCNT2 counter is 8 bits. */
\r
76 /*******************************************************************************
\r
77 ******************************** ENUMS ************************************
\r
78 ******************************************************************************/
\r
80 /** Mode selection. */
\r
83 /** Disable pulse counter. */
\r
84 pcntModeDisable = _PCNT_CTRL_MODE_DISABLE,
\r
86 /** Single input LFACLK oversampling mode (available in EM0-EM2). */
\r
87 pcntModeOvsSingle = _PCNT_CTRL_MODE_OVSSINGLE,
\r
89 /** Externally clocked single input counter mode (available in EM0-EM3). */
\r
90 pcntModeExtSingle = _PCNT_CTRL_MODE_EXTCLKSINGLE,
\r
92 /** Externally clocked quadrature decoder mode (available in EM0-EM3). */
\r
93 pcntModeExtQuad = _PCNT_CTRL_MODE_EXTCLKQUAD,
\r
95 #if defined(_PCNT_CTRL_MODE_OVSQUAD1X)
\r
96 /** LFACLK oversampling quadrature decoder 1X mode (available in EM0-EM2). */
\r
97 pcntModeOvsQuad1 = _PCNT_CTRL_MODE_OVSQUAD1X,
\r
99 /** LFACLK oversampling quadrature decoder 2X mode (available in EM0-EM2). */
\r
100 pcntModeOvsQuad2 = _PCNT_CTRL_MODE_OVSQUAD2X,
\r
102 /** LFACLK oversampling quadrature decoder 4X mode (available in EM0-EM2). */
\r
103 pcntModeOvsQuad4 = _PCNT_CTRL_MODE_OVSQUAD4X,
\r
105 } PCNT_Mode_TypeDef;
\r
108 #if defined(_PCNT_CTRL_CNTEV_MASK)
\r
109 /** Counter event selection.
\r
110 * Note: unshifted values are being used for enumeration because multiple
\r
111 * configuration structure members use this type definition. */
\r
114 /** Counts up on up-count and down on down-count events. */
\r
115 pcntCntEventBoth = _PCNT_CTRL_CNTEV_BOTH,
\r
117 /** Only counts up on up-count events. */
\r
118 pcntCntEventUp = _PCNT_CTRL_CNTEV_UP,
\r
120 /** Only counts down on down-count events. */
\r
121 pcntCntEventDown = _PCNT_CTRL_CNTEV_DOWN,
\r
123 /** Never counts. */
\r
124 pcntCntEventNone = _PCNT_CTRL_CNTEV_NONE
\r
125 } PCNT_CntEvent_TypeDef;
\r
129 #if defined(_PCNT_INPUT_MASK)
\r
130 /** PRS sources for @p s0PRS and @p s1PRS. */
\r
133 pcntPRSCh0 = 0, /**< PRS channel 0. */
\r
134 pcntPRSCh1 = 1, /**< PRS channel 1. */
\r
135 pcntPRSCh2 = 2, /**< PRS channel 2. */
\r
136 pcntPRSCh3 = 3, /**< PRS channel 3. */
\r
137 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH4)
\r
138 pcntPRSCh4 = 4, /**< PRS channel 4. */
\r
140 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH5)
\r
141 pcntPRSCh5 = 5, /**< PRS channel 5. */
\r
143 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH6)
\r
144 pcntPRSCh6 = 6, /**< PRS channel 6. */
\r
146 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH7)
\r
147 pcntPRSCh7 = 7, /**< PRS channel 7. */
\r
149 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH8)
\r
150 pcntPRSCh8 = 8, /**< PRS channel 8. */
\r
152 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH9)
\r
153 pcntPRSCh9 = 9, /**< PRS channel 9. */
\r
155 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH10)
\r
156 pcntPRSCh10 = 10, /**< PRS channel 10. */
\r
158 #if defined(PCNT_INPUT_S0PRSSEL_PRSCH11)
\r
159 pcntPRSCh11 = 11 /**< PRS channel 11. */
\r
161 } PCNT_PRSSel_TypeDef;
\r
164 /** PRS inputs of PCNT. */
\r
167 pcntPRSInputS0 = 0, /** PRS input 0. */
\r
168 pcntPRSInputS1 = 1 /** PRS input 1. */
\r
169 } PCNT_PRSInput_TypeDef;
\r
173 /*******************************************************************************
\r
174 ******************************* STRUCTS ***********************************
\r
175 ******************************************************************************/
\r
177 /** Init structure. */
\r
180 /** Mode to operate in. */
\r
181 PCNT_Mode_TypeDef mode;
\r
183 /** Initial counter value (refer to reference manual for max value allowed).
\r
184 * Only used for #pcntModeOvsSingle (and possibly #pcntModeDisable) modes.
\r
185 * If using #pcntModeExtSingle or #pcntModeExtQuad modes, the counter
\r
186 * value is reset to HW reset value. */
\r
189 /** Initial top value (refer to reference manual for max value allowed).
\r
190 * Only used for #pcntModeOvsSingle (and possibly #pcntModeDisable) modes.
\r
191 * If using #pcntModeExtSingle or #pcntModeExtQuad modes, the top
\r
192 * value is reset to HW reset value. */
\r
195 /** Polarity of incoming edge.
\r
196 * @li #pcntModeExtSingle mode - if false, positive edges are counted,
\r
197 * otherwise negative edges.
\r
198 * @li #pcntModeExtQuad mode - if true, counting direction is inverted. */
\r
201 /** Counting direction, only applicable for #pcntModeOvsSingle and
\r
202 * #pcntModeExtSingle modes. */
\r
205 /** Enable filter, only available in #pcntModeOvs* modes. */
\r
208 #if defined(PCNT_CTRL_HYST)
\r
209 /** Set to true to enable hysteresis. When its enabled, the PCNT will always
\r
210 * overflow and underflow to TOP/2. */
\r
213 /** Set to true to enable S1 to determine the direction of counting in
\r
214 * OVSSINGLE or EXTCLKSINGLE modes. @n
\r
215 * When S1 is high, the count direction is given by CNTDIR, and when S1 is
\r
216 * low, the count direction is the opposite. */
\r
219 /** Selects whether the regular counter responds to up-count events,
\r
220 * down-count events, both or none. */
\r
221 PCNT_CntEvent_TypeDef cntEvent;
\r
223 /** Selects whether the auxiliary counter responds to up-count events,
\r
224 * down-count events, both or none. */
\r
225 PCNT_CntEvent_TypeDef auxCntEvent;
\r
227 /** Select PRS channel as input to S0IN in PCNTx_INPUT register. */
\r
228 PCNT_PRSSel_TypeDef s0PRS;
\r
230 /** Select PRS channel as input to S1IN in PCNTx_INPUT register. */
\r
231 PCNT_PRSSel_TypeDef s1PRS;
\r
233 } PCNT_Init_TypeDef;
\r
235 #if !defined(PCNT_CTRL_HYST)
\r
236 /** Default config for PCNT init structure. */
\r
237 #define PCNT_INIT_DEFAULT \
\r
239 pcntModeDisable, /* Disabled by default. */ \
\r
240 _PCNT_CNT_RESETVALUE, /* Default counter HW reset value. */ \
\r
241 _PCNT_TOP_RESETVALUE, /* Default counter HW reset value. */ \
\r
242 false, /* Use positive edge. */ \
\r
243 false, /* Up-counting. */ \
\r
244 false /* Filter disabled. */ \
\r
247 /** Default config for PCNT init structure. */
\r
248 #define PCNT_INIT_DEFAULT \
\r
250 pcntModeDisable, /* Disabled by default. */ \
\r
251 _PCNT_CNT_RESETVALUE, /* Default counter HW reset value. */ \
\r
252 _PCNT_TOP_RESETVALUE, /* Default counter HW reset value. */ \
\r
253 false, /* Use positive edge. */ \
\r
254 false, /* Up-counting. */ \
\r
255 false, /* Filter disabled. */ \
\r
256 false, /* Hysteresis disabled. */ \
\r
257 true, /* Counter direction is given by CNTDIR. */ \
\r
258 pcntCntEventUp, /* Regular counter counts up on upcount events. */ \
\r
259 pcntCntEventNone, /* Auxiliary counter doesn't respond to events. */ \
\r
260 pcntPRSCh0, /* PRS channel 0 selected as S0IN. */ \
\r
261 pcntPRSCh0 /* PRS channel 0 selected as S1IN. */ \
\r
265 #if defined(PCNT_OVSCFG_FILTLEN_DEFAULT)
\r
266 /** Filter initialization structure */
\r
269 /** Used only in OVSINGLE and OVSQUAD1X-4X modes. To use this, enable the filter through
\r
270 * setting filter to true during PCNT_Init(). Filter length = (filtLen + 5) LFACLK cycles. */
\r
273 /** When set, removes flutter from Quaddecoder inputs S0IN and S1IN.
\r
274 * Available only in OVSQUAD1X-4X modes. */
\r
276 } PCNT_Filter_TypeDef;
\r
279 /** Default config for PCNT init structure. */
\r
280 #if defined(PCNT_OVSCFG_FILTLEN_DEFAULT)
\r
281 #define PCNT_FILTER_DEFAULT \
\r
283 0, /* Default length is 5 LFACLK cycles */ \
\r
284 false /* No flutter removal */ \
\r
288 #if defined(PCNT_CTRL_TCCMODE_DEFAULT)
\r
290 /** Modes for Triggered Compare and Clear module */
\r
293 /** Triggered compare and clear not enabled. */
\r
294 tccModeDisabled = _PCNT_CTRL_TCCMODE_DISABLED,
\r
296 /** Compare and clear performed on each (optionally prescaled) LFA clock cycle. */
\r
297 tccModeLFA = _PCNT_CTRL_TCCMODE_LFA,
\r
299 /** Compare and clear performed on PRS edges. Polarity defined by prsPolarity. */
\r
300 tccModePRS = _PCNT_CTRL_TCCMODE_PRS
\r
301 } PCNT_TCCMode_TypeDef;
\r
303 /** Prescaler values for LFA compare and clear events. Only has effect when TCC mode is LFA. */
\r
306 /** Compare and clear event each LFA cycle. */
\r
307 tccPrescDiv1 = _PCNT_CTRL_TCCPRESC_DIV1,
\r
309 /** Compare and clear event every other LFA cycle. */
\r
310 tccPrescDiv2 = _PCNT_CTRL_TCCPRESC_DIV2,
\r
312 /** Compare and clear event every 4th LFA cycle. */
\r
313 tccPrescDiv4 = _PCNT_CTRL_TCCPRESC_DIV4,
\r
315 /** Compare and clear event every 8th LFA cycle. */
\r
316 tccPrescDiv8 = _PCNT_CTRL_TCCPRESC_DIV8
\r
317 } PCNT_TCCPresc_Typedef;
\r
319 /** Compare modes for TCC module */
\r
322 /** Compare match if PCNT_CNT is less than, or equal to PCNT_TOP. */
\r
323 tccCompLTOE = _PCNT_CTRL_TCCCOMP_LTOE,
\r
325 /** Compare match if PCNT_CNT is greater than or equal to PCNT_TOP. */
\r
326 tccCompGTOE = _PCNT_CTRL_TCCCOMP_GTOE,
\r
328 /** Compare match if PCNT_CNT is less than, or equal to PCNT_TOP[15:8]], and greater
\r
329 * than, or equal to PCNT_TOP[7:0]. */
\r
330 tccCompRange = _PCNT_CTRL_TCCCOMP_RANGE
\r
331 } PCNT_TCCComp_Typedef;
\r
333 /** TCC initialization structure */
\r
336 /** Mode to operate in. */
\r
337 PCNT_TCCMode_TypeDef mode;
\r
339 /** Prescaler value for LFACLK in LFA mode */
\r
340 PCNT_TCCPresc_Typedef prescaler;
\r
342 /** Choose the event that will trigger a clear */
\r
343 PCNT_TCCComp_Typedef compare;
\r
345 /** PRS input to TCC module, either for gating the PCNT clock, triggering the TCC comparison, or both. */
\r
346 PCNT_PRSSel_TypeDef tccPRS;
\r
348 /** TCC PRS input polarity. @n
\r
349 * False = Rising edge for comparison trigger, and PCNT clock gated when the PRS signal is high. @n
\r
350 * True = Falling edge for comparison trigger, and PCNT clock gated when the PRS signal is low. */
\r
353 /** Enable gating PCNT input clock through TCC PRS signal.
\r
354 * Polarity selection is done through prsPolarity. */
\r
355 bool prsGateEnable;
\r
356 } PCNT_TCC_TypeDef;
\r
358 #define PCNT_TCC_DEFAULT \
\r
360 tccModeDisabled, /* Disabled by default */ \
\r
361 tccPrescDiv1, /* Do not prescale LFA clock in LFA mode */ \
\r
362 tccCompLTOE, /* Clear when CNT <= TOP */ \
\r
363 pcntPRSCh0, /* Select PRS channel 0 as input to TCC */ \
\r
364 false, /* PRS polarity is rising edge, and gate when 1 */ \
\r
365 false /* Do not gate the PCNT counter input */ \
\r
369 /* defined(PCNT_CTRL_TCCMODE_DEFAULT) */
\r
371 /*******************************************************************************
\r
372 ***************************** PROTOTYPES **********************************
\r
373 ******************************************************************************/
\r
375 /***************************************************************************//**
\r
377 * Get pulse counter value.
\r
380 * Pointer to PCNT peripheral register block.
\r
383 * Current pulse counter value.
\r
384 ******************************************************************************/
\r
385 __STATIC_INLINE uint32_t PCNT_CounterGet(PCNT_TypeDef *pcnt)
\r
390 #if defined(_PCNT_AUXCNT_MASK)
\r
391 /***************************************************************************//**
\r
393 * Get auxiliary counter value.
\r
396 * Pointer to PCNT peripheral register block.
\r
399 * Current auxiliary counter value.
\r
400 ******************************************************************************/
\r
401 __STATIC_INLINE uint32_t PCNT_AuxCounterGet(PCNT_TypeDef *pcnt)
\r
403 return pcnt->AUXCNT;
\r
407 void PCNT_CounterReset(PCNT_TypeDef *pcnt);
\r
408 void PCNT_CounterTopSet(PCNT_TypeDef *pcnt, uint32_t count, uint32_t top);
\r
410 /***************************************************************************//**
\r
412 * Set counter value.
\r
415 * The pulse counter is disabled while changing counter value, and reenabled
\r
416 * (if originally enabled) when counter value has been set.
\r
419 * This function will stall until synchronization to low frequency domain is
\r
420 * completed. For that reason, it should normally not be used when using
\r
421 * an external clock to clock the PCNT module, since stall time may be
\r
422 * undefined in that case. The counter should normally only be set when
\r
423 * operating in (or about to enable) #pcntModeOvsSingle mode.
\r
426 * Pointer to PCNT peripheral register block.
\r
429 * Value to set in counter register.
\r
430 ******************************************************************************/
\r
431 __STATIC_INLINE void PCNT_CounterSet(PCNT_TypeDef *pcnt, uint32_t count)
\r
433 PCNT_CounterTopSet(pcnt, count, pcnt->TOP);
\r
436 void PCNT_Enable(PCNT_TypeDef *pcnt, PCNT_Mode_TypeDef mode);
\r
437 void PCNT_FreezeEnable(PCNT_TypeDef *pcnt, bool enable);
\r
438 void PCNT_Init(PCNT_TypeDef *pcnt, const PCNT_Init_TypeDef *init);
\r
440 #if defined(PCNT_OVSCFG_FILTLEN_DEFAULT)
\r
441 void PCNT_FilterConfiguration(PCNT_TypeDef *pcnt, const PCNT_Filter_TypeDef *config, bool enable);
\r
444 #if defined(_PCNT_INPUT_MASK)
\r
445 void PCNT_PRSInputEnable(PCNT_TypeDef *pcnt,
\r
446 PCNT_PRSInput_TypeDef prsInput,
\r
450 #if defined(PCNT_CTRL_TCCMODE_DEFAULT)
\r
451 void PCNT_TCCConfiguration(PCNT_TypeDef *pcnt, const PCNT_TCC_TypeDef *config);
\r
453 /***************************************************************************//**
\r
455 * Clear one or more pending PCNT interrupts.
\r
458 * Pointer to PCNT peripheral register block.
\r
461 * Pending PCNT interrupt source to clear. Use a bitwise logic OR combination
\r
462 * of valid interrupt flags for the PCNT module (PCNT_IF_nnn).
\r
463 ******************************************************************************/
\r
464 __STATIC_INLINE void PCNT_IntClear(PCNT_TypeDef *pcnt, uint32_t flags)
\r
469 /***************************************************************************//**
\r
471 * Disable one or more PCNT interrupts.
\r
474 * Pointer to PCNT peripheral register block.
\r
477 * PCNT interrupt sources to disable. Use a bitwise logic OR combination of
\r
478 * valid interrupt flags for the PCNT module (PCNT_IF_nnn).
\r
479 ******************************************************************************/
\r
480 __STATIC_INLINE void PCNT_IntDisable(PCNT_TypeDef *pcnt, uint32_t flags)
\r
482 pcnt->IEN &= ~flags;
\r
485 /***************************************************************************//**
\r
487 * Enable one or more PCNT interrupts.
\r
490 * Depending on the use, a pending interrupt may already be set prior to
\r
491 * enabling the interrupt. Consider using PCNT_IntClear() prior to enabling
\r
492 * if such a pending interrupt should be ignored.
\r
495 * Pointer to PCNT peripheral register block.
\r
498 * PCNT interrupt sources to enable. Use a bitwise logic OR combination of
\r
499 * valid interrupt flags for the PCNT module (PCNT_IF_nnn).
\r
500 ******************************************************************************/
\r
501 __STATIC_INLINE void PCNT_IntEnable(PCNT_TypeDef *pcnt, uint32_t flags)
\r
503 pcnt->IEN |= flags;
\r
506 /***************************************************************************//**
\r
508 * Get pending PCNT interrupt flags.
\r
511 * The event bits are not cleared by the use of this function.
\r
514 * Pointer to PCNT peripheral register block.
\r
517 * PCNT interrupt sources pending. A bitwise logic OR combination of valid
\r
518 * interrupt flags for the PCNT module (PCNT_IF_nnn).
\r
519 ******************************************************************************/
\r
520 __STATIC_INLINE uint32_t PCNT_IntGet(PCNT_TypeDef *pcnt)
\r
525 /***************************************************************************//**
\r
527 * Get enabled and pending PCNT interrupt flags.
\r
530 * Useful for handling more interrupt sources in the same interrupt handler.
\r
533 * The event bits are not cleared by the use of this function.
\r
536 * Pointer to PCNT peripheral register block.
\r
539 * Pending and enabled PCNT interrupt sources.
\r
540 * The return value is the bitwise AND combination of
\r
541 * - the OR combination of enabled interrupt sources in PCNT_IEN_nnn
\r
542 * register (PCNT_IEN_nnn) and
\r
543 * - the OR combination of valid interrupt flags of the PCNT module
\r
545 ******************************************************************************/
\r
546 __STATIC_INLINE uint32_t PCNT_IntGetEnabled(PCNT_TypeDef *pcnt)
\r
551 /* Store pcnt->IEN in temporary variable in order to define explicit order
\r
552 * of volatile accesses. */
\r
555 /* Bitwise AND of pending and enabled interrupts */
\r
556 return pcnt->IF & ien;
\r
559 /***************************************************************************//**
\r
561 * Set one or more pending PCNT interrupts from SW.
\r
564 * Pointer to PCNT peripheral register block.
\r
567 * PCNT interrupt sources to set to pending. Use a bitwise logic OR combination
\r
568 * of valid interrupt flags for the PCNT module (PCNT_IF_nnn).
\r
569 ******************************************************************************/
\r
570 __STATIC_INLINE void PCNT_IntSet(PCNT_TypeDef *pcnt, uint32_t flags)
\r
575 void PCNT_Reset(PCNT_TypeDef *pcnt);
\r
577 /***************************************************************************//**
\r
579 * Get pulse counter top buffer value.
\r
582 * Pointer to PCNT peripheral register block.
\r
585 * Current pulse counter top buffer value.
\r
586 ******************************************************************************/
\r
587 __STATIC_INLINE uint32_t PCNT_TopBufferGet(PCNT_TypeDef *pcnt)
\r
592 void PCNT_TopBufferSet(PCNT_TypeDef *pcnt, uint32_t val);
\r
594 /***************************************************************************//**
\r
596 * Get pulse counter top value.
\r
599 * Pointer to PCNT peripheral register block.
\r
602 * Current pulse counter top value.
\r
603 ******************************************************************************/
\r
604 __STATIC_INLINE uint32_t PCNT_TopGet(PCNT_TypeDef *pcnt)
\r
609 void PCNT_TopSet(PCNT_TypeDef *pcnt, uint32_t val);
\r
611 /** @} (end addtogroup PCNT) */
\r
612 /** @} (end addtogroup EM_Library) */
\r
618 #endif /* defined(PCNT_COUNT) && (PCNT_COUNT > 0) */
\r
619 #endif /* __SILICON_LABS_EM_PCNT_H__ */
\r