1 /***************************************************************************//**
2  * @file
3  * @brief Pulse Counter (PCNT) peripheral API
4  * @author Energy Micro AS
5  * @version 3.0.0
6  *******************************************************************************
7  * @section License
8  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9  *******************************************************************************
10  *
11  * Permission is granted to anyone to use this software for any purpose,
12  * including commercial applications, and to alter it and redistribute it
13  * freely, subject to the following restrictions:
14  *
15  * 1. The origin of this software must not be misrepresented; you must not
16  *    claim that you wrote the original software.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  *    misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  *
21  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22  * obligation to support this Software. Energy Micro AS is providing the
23  * Software "AS IS", with no express or implied warranties of any kind,
24  * including, but not limited to, any implied warranties of merchantability
25  * or fitness for any particular purpose or warranties against infringement
26  * of any proprietary rights of a third party.
27  *
28  * Energy Micro AS will not be liable for any consequential, incidental, or
29  * special damages, or any other relief, or for any claim by any third party,
30  * arising from your use of this Software.
31  *
32  ******************************************************************************/
33 #include "em_pcnt.h"
34 #include "em_cmu.h"
35 #include "em_assert.h"
36 #include "em_bitband.h"
37 
38 /***************************************************************************//**
39  * @addtogroup EM_Library
40  * @{
41  ******************************************************************************/
42 
43 /***************************************************************************//**
44  * @addtogroup PCNT
45  * @brief Pulse Counter (PCNT) Peripheral API
46  * @{
47  ******************************************************************************/
48 
49 /*******************************************************************************
50  *******************************   DEFINES   ***********************************
51  ******************************************************************************/
52 
53 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
54 
55 
56 /** Validation of PCNT register block pointer reference for assert statements. */
57 #if (PCNT_COUNT == 1)
58 #define PCNT_REF_VALID(ref)    ((ref) == PCNT0)
59 #elif (PCNT_COUNT == 2)
60 #define PCNT_REF_VALID(ref)    (((ref) == PCNT0) || ((ref) == PCNT1))
61 #elif (PCNT_COUNT == 3)
62 #define PCNT_REF_VALID(ref)    (((ref) == PCNT0) || ((ref) == PCNT1) || \
63                                 ((ref) == PCNT2))
64 #else
65 #error Undefined number of pulse counters (PCNT).
66 #endif
67 
68 /** @endcond */
69 
70 
71 /*******************************************************************************
72  **************************   LOCAL FUNCTIONS   ********************************
73  ******************************************************************************/
74 
75 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
76 
77 /***************************************************************************//**
78  * @brief
79  *   Map PCNT structure into instance number.
80  *
81  * @param[in] pcnt
82  *   Pointer to PCNT peripheral register block
83  *
84  * @return
85  *   Instance number.
86  ******************************************************************************/
PCNT_Map(PCNT_TypeDef * pcnt)87 __STATIC_INLINE unsigned int PCNT_Map(PCNT_TypeDef *pcnt)
88 {
89   return(((uint32_t)pcnt - PCNT0_BASE) / 0x400);
90 }
91 
92 
93 /***************************************************************************//**
94  * @brief
95  *   Wait for ongoing sync of register(s) to low frequency domain to complete.
96  *
97  * @param[in] pcnt
98  *   Pointer to PCNT peripheral register block
99  *
100  * @param[in] mask
101  *   Bitmask corresponding to SYNCBUSY register defined bits, indicating
102  *   registers that must complete any ongoing synchronization.
103  ******************************************************************************/
PCNT_Sync(PCNT_TypeDef * pcnt,uint32_t mask)104 __STATIC_INLINE void PCNT_Sync(PCNT_TypeDef *pcnt, uint32_t mask)
105 {
106   /* Avoid deadlock if modifying the same register twice when freeze mode is
107    * activated. */
108   if (pcnt->FREEZE & PCNT_FREEZE_REGFREEZE)
109   {
110     return;
111   }
112 
113   /* Wait for any pending previous write operation to have been completed in low
114    * frequency domain. */
115   while (pcnt->SYNCBUSY & mask)
116     ;
117 }
118 
119 /** @endcond */
120 
121 /*******************************************************************************
122  **************************   GLOBAL FUNCTIONS   *******************************
123  ******************************************************************************/
124 
125 /***************************************************************************//**
126  * @brief
127  *   Reset PCNT counters and TOP register.
128  *
129  * @note
130  *   Notice that special SYNCBUSY handling is not applicable for the RSTEN
131  *   bit of the control register, so we don't need to wait for it when only
132  *   modifying RSTEN. (It would mean undefined wait time if clocked by external
133  *   clock.) The SYNCBUSY bit will however be set, leading to a synchronization
134  *   in the LF domain, with in reality no changes.
135  *
136  * @param[in] pcnt
137  *   Pointer to PCNT peripheral register block.
138  ******************************************************************************/
PCNT_CounterReset(PCNT_TypeDef * pcnt)139 void PCNT_CounterReset(PCNT_TypeDef *pcnt)
140 {
141   EFM_ASSERT(PCNT_REF_VALID(pcnt));
142 
143   /* Enable reset of CNT and TOP register */
144   BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
145 
146   /* Disable reset of CNT and TOP register */
147   BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
148 }
149 
150 
151 /***************************************************************************//**
152  * @brief
153  *   Set counter and top values.
154  *
155  * @details
156  *   The pulse counter is disabled while changing these values, and reenabled
157  *   (if originally enabled) when values have been set.
158  *
159  * @note
160  *   This function will stall until synchronization to low frequency domain is
161  *   completed. For that reason, it should normally not be used when using
162  *   an external clock to clock the PCNT module, since stall time may be
163  *   undefined in that case. The counter should normally only be set when
164  *   operating in (or about to enable) #pcntModeOvsSingle mode.
165  *
166  * @param[in] pcnt
167  *   Pointer to PCNT peripheral register block.
168  *
169  * @param[in] count
170  *   Value to set in counter register.
171  *
172  * @param[in] top
173  *   Value to set in top register.
174  ******************************************************************************/
PCNT_CounterTopSet(PCNT_TypeDef * pcnt,uint32_t count,uint32_t top)175 void PCNT_CounterTopSet(PCNT_TypeDef *pcnt, uint32_t count, uint32_t top)
176 {
177   uint32_t ctrl;
178 
179   EFM_ASSERT(PCNT_REF_VALID(pcnt));
180 
181   /* Keep current control setting, must be restored */
182   ctrl = pcnt->CTRL;
183 
184   /* If enabled, disable pulse counter before changing values */
185   if ((ctrl & _PCNT_CTRL_MODE_MASK) != PCNT_CTRL_MODE_DISABLE)
186   {
187     PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
188     pcnt->CTRL = (ctrl & ~_PCNT_CTRL_MODE_MASK) | PCNT_CTRL_MODE_DISABLE;
189   }
190 
191   /* Load into TOPB */
192   PCNT_Sync(pcnt, PCNT_SYNCBUSY_TOPB);
193   pcnt->TOPB = count;
194 
195   /* Load TOPB value into TOP */
196   PCNT_Sync(pcnt, PCNT_SYNCBUSY_TOPB | PCNT_SYNCBUSY_CMD);
197 
198   /* This bit has no effect on rev. C and onwards parts - for compatibility */
199   pcnt->CMD = PCNT_CMD_LTOPBIM;
200   PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
201 
202   /* Load TOP into CNT */
203   pcnt->CMD = PCNT_CMD_LCNTIM;
204 
205   /* Restore TOP? ('count' setting has been loaded into pcnt->TOP, better
206    * to use 'top' than pcnt->TOP in compare, since latter may in theory not
207    * be visible yet.) */
208   if (top != count)
209   {
210     /* Wait for command to sync LCNTIM before setting TOPB */
211     PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
212 
213     /* Load into TOPB, we don't need to check for TOPB sync complete here,
214      * it has been ensured above. */
215     pcnt->TOPB = top;
216 
217     /* Load TOPB value into TOP */
218     PCNT_Sync(pcnt, PCNT_SYNCBUSY_TOPB | PCNT_SYNCBUSY_CMD);
219     pcnt->CMD = PCNT_CMD_LTOPBIM;
220   }
221 
222   /* Reenable if it was enabled */
223   if ((ctrl & _PCNT_CTRL_MODE_MASK) != PCNT_CTRL_MODE_DISABLE)
224   {
225     PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL | PCNT_SYNCBUSY_CMD);
226     pcnt->CTRL = ctrl;
227   }
228 }
229 
230 
231 /***************************************************************************//**
232  * @brief
233  *   Set PCNT operational mode.
234  *
235  * @details
236  *   Notice that this function does not do any configuration. Setting operational
237  *   mode is normally only required after initialization is done, and if not
238  *   done as part of initialization. Or if requiring to disable/reenable pulse
239  *   counter.
240  *
241  * @note
242  *   This function may stall until synchronization to low frequency domain is
243  *   completed. For that reason, it should normally not be used when using
244  *   an external clock to clock the PCNT module, since stall time may be
245  *   undefined in that case.
246  *
247  * @param[in] pcnt
248  *   Pointer to PCNT peripheral register block.
249  *
250  * @param[in] mode
251  *   Operational mode to use for PCNT.
252  ******************************************************************************/
PCNT_Enable(PCNT_TypeDef * pcnt,PCNT_Mode_TypeDef mode)253 void PCNT_Enable(PCNT_TypeDef *pcnt, PCNT_Mode_TypeDef mode)
254 {
255   uint32_t tmp;
256 
257   EFM_ASSERT(PCNT_REF_VALID(pcnt));
258 
259   /* Set as specified */
260   tmp  = pcnt->CTRL & ~_PCNT_CTRL_MODE_MASK;
261   tmp |= (uint32_t)mode << _PCNT_CTRL_MODE_SHIFT;
262 
263   /* LF register about to be modified require sync. busy check */
264   PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
265   pcnt->CTRL = tmp;
266 }
267 
268 #if (defined (_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY))
269 /***************************************************************************//**
270  * @brief
271  *   Enable/disable the selected PRS input of PCNT.
272  *
273  * @details
274  *   Notice that this function does not do any configuration.
275  *
276  * @param[in] pcnt
277  *   Pointer to PCNT peripheral register block.
278  *
279  * @param[in] prsInput
280  *   PRS input (S0 or S1) of the selected PCNT module.
281  *
282  * @param[in] enable
283  *   Set to true to enable, false to disable the selected PRS input.
284  ******************************************************************************/
PCNT_PRSInputEnable(PCNT_TypeDef * pcnt,PCNT_PRSInput_TypeDef prsInput,bool enable)285 void PCNT_PRSInputEnable(PCNT_TypeDef *pcnt,
286                          PCNT_PRSInput_TypeDef prsInput,
287                          bool enable)
288 {
289   EFM_ASSERT(PCNT_REF_VALID(pcnt));
290 
291   /* Enable/disable the selected PRS input on the selected PCNT module. */
292   switch (prsInput)
293   {
294   /* Enable/disable PRS input S0. */
295   case pcntPRSInputS0:
296   {
297     BITBAND_Peripheral(&(pcnt->INPUT), _PCNT_INPUT_S0PRSEN_SHIFT, (uint32_t)enable);
298   }
299   break;
300 
301   /* Enable/disable PRS input S1. */
302   case pcntPRSInputS1:
303   {
304     BITBAND_Peripheral(&(pcnt->INPUT), _PCNT_INPUT_S1PRSEN_SHIFT, (uint32_t)enable);
305   }
306   break;
307 
308   /* Invalid parameter, asserted. */
309   default:
310   {
311     EFM_ASSERT(0);
312   }
313   break;
314   }
315 }
316 #endif
317 
318 
319 /***************************************************************************//**
320  * @brief
321  *   PCNT register synchronization freeze control.
322  *
323  * @details
324  *   Some PCNT registers require synchronization into the low frequency (LF)
325  *   domain. The freeze feature allows for several such registers to be
326  *   modified before passing them to the LF domain simultaneously (which
327  *   takes place when the freeze mode is disabled).
328  *
329  * @note
330  *   When enabling freeze mode, this function will wait for all current
331  *   ongoing PCNT synchronization to LF domain to complete (Normally
332  *   synchronization will not be in progress.) However for this reason, when
333  *   using freeze mode, modifications of registers requiring LF synchronization
334  *   should be done within one freeze enable/disable block to avoid unecessary
335  *   stalling.
336  *
337  * @param[in] pcnt
338  *   Pointer to PCNT peripheral register block.
339  *
340  * @param[in] enable
341  *   @li true - enable freeze, modified registers are not propagated to the
342  *       LF domain
343  *   @li false - disables freeze, modified registers are propagated to LF
344  *       domain
345  ******************************************************************************/
PCNT_FreezeEnable(PCNT_TypeDef * pcnt,bool enable)346 void PCNT_FreezeEnable(PCNT_TypeDef *pcnt, bool enable)
347 {
348   EFM_ASSERT(PCNT_REF_VALID(pcnt));
349 
350   if (enable)
351   {
352     /* Wait for any ongoing LF synchronization to complete. This is just to
353      * protect against the rare case when a user:
354      * - modifies a register requiring LF sync
355      * - then enables freeze before LF sync completed
356      * - then modifies the same register again
357      * since modifying a register while it is in sync progress should be
358      * avoided. */
359     while (pcnt->SYNCBUSY)
360       ;
361 
362     pcnt->FREEZE = PCNT_FREEZE_REGFREEZE;
363   }
364   else
365   {
366     pcnt->FREEZE = 0;
367   }
368 }
369 
370 
371 /***************************************************************************//**
372  * @brief
373  *   Init pulse counter.
374  *
375  * @details
376  *   This function will configure the pulse counter. The clock selection is
377  *   configured as follows, depending on operational mode:
378  *
379  *   @li #pcntModeOvsSingle - Use LFACLK.
380  *   @li #pcntModeExtSingle - Use external PCNTn_S0 pin.
381  *   @li #pcntModeExtQuad - Use external PCNTn_S0 pin.
382  *
383  *   Notice that the LFACLK must be enabled in all modes, since some basic setup
384  *   is done with this clock even if external pin clock usage mode is chosen.
385  *   The pulse counter clock for the selected instance must also be enabled
386  *   prior to init.
387  *
388  *   Notice that pins used by the PCNT module must be properly configured
389  *   by the user explicitly through setting the ROUTE register, in order for
390  *   the PCNT to work as intended.
391  *
392  *   Writing to CNT will not occur in external clock modes (EXTCLKQUAD and
393  *   EXTCLKSINGLE) because the external clock rate is unknown. The user should
394  *   handle it manually depending on the application
395  *
396  *   TOPB is written for all modes but in external clock mode it will take
397  *   3 external clock cycles to sync to TOP
398  *
399  *
400  * @note
401  *   Initializing requires synchronization into the low frequency domain. This
402  *   may cause some delay.
403  *
404  * @param[in] pcnt
405  *   Pointer to PCNT peripheral register block.
406  *
407  * @param[in] init
408  *   Pointer to initialization structure used to initialize.
409  ******************************************************************************/
PCNT_Init(PCNT_TypeDef * pcnt,const PCNT_Init_TypeDef * init)410 void PCNT_Init(PCNT_TypeDef *pcnt, const PCNT_Init_TypeDef *init)
411 {
412   unsigned int inst;
413   uint32_t     tmp;
414 
415   EFM_ASSERT(PCNT_REF_VALID(pcnt));
416 
417   /* Map pointer to instance */
418   inst = PCNT_Map(pcnt);
419 
420 #if (defined (_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY))
421   /* Selecting the PRS channels for the PRS input sources of the PCNT. These are
422    * written with a Read-Modify-Write sequence in order to keep the value of the
423    * input enable bits which can be modified using PCNT_PRSInputEnable(). */
424   tmp = pcnt->INPUT & ~(_PCNT_INPUT_S0PRSSEL_MASK | _PCNT_INPUT_S1PRSSEL_MASK);
425   tmp |= ((uint32_t)init->s0PRS << _PCNT_INPUT_S0PRSSEL_SHIFT) |
426          ((uint32_t)init->s1PRS << _PCNT_INPUT_S1PRSSEL_SHIFT);
427   pcnt->INPUT = tmp;
428 #endif
429 
430   /* Build CTRL setting, except for mode */
431   tmp = 0;
432   if (init->negEdge)
433   {
434     tmp |= PCNT_CTRL_EDGE_NEG;
435   }
436 
437   if (init->countDown)
438   {
439     tmp |= PCNT_CTRL_CNTDIR_DOWN;
440   }
441 
442   if (init->filter)
443   {
444     tmp |= PCNT_CTRL_FILT;
445   }
446 
447 #if (defined (_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY))
448   if (init->hyst)
449   {
450     tmp |= PCNT_CTRL_HYST;
451   }
452 
453   if (init->s1CntDir)
454   {
455     tmp |= PCNT_CTRL_S1CDIR;
456   }
457 
458   /* Configure counter events for regular and auxiliary counter. */
459   tmp |= init->cntEvent << _PCNT_CTRL_CNTEV_SHIFT;
460   tmp |= init->auxCntEvent << _PCNT_CTRL_AUXCNTEV_SHIFT;
461 #endif
462 
463   /* Reset pulse counter while changing clock source. The reset bit */
464   /* is asynchronous, we don't have to check for SYNCBUSY. */
465   BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
466 
467   /* Select LFACLK to clock in control setting */
468   CMU_PCNTClockExternalSet(inst, false);
469 
470   /* Handling depends on whether using external clock or not. */
471   switch (init->mode)
472   {
473   case pcntModeExtSingle:
474   case pcntModeExtQuad:
475     tmp |= init->mode << _PCNT_CTRL_MODE_SHIFT;
476 
477     /* In most cases, the SYNCBUSY bit is set due to reset bit set, and waiting
478      * for asynchronous reset bit is strictly not necessary.
479      * But in theory, other operations on CTRL register may have been done
480      * outside this function, so wait. */
481     PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
482 
483     /* Enable PCNT Clock Domain Reset. The PCNT must be in reset before changing
484      * the clock source to an external clock */
485     pcnt->CTRL = PCNT_CTRL_RSTEN;
486 
487     /* Wait until CTRL write synchronized into LF domain. */
488     PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
489 
490     /* Change to external clock BEFORE disabling reset */
491     CMU_PCNTClockExternalSet(inst, true);
492 
493     /* Write to TOPB. If using external clock TOPB will sync to TOP at the same
494      * time as the mode. This will insure that if the user chooses to count
495      * down, the first "countable" pulse will make CNT go to TOP and not 0xFF
496      * (default TOP value). */
497     pcnt->TOPB = init->top;
498 
499     /* This bit has no effect on rev. C and onwards parts - for compatibility */
500     pcnt->CMD = PCNT_CMD_LTOPBIM;
501 
502     /* Write the CTRL register with the configurations.
503      * This should be written after TOPB in the eventuality of a pulse between
504      * these two writes that would cause the CTRL register to be synced one
505      * clock cycle earlier than the TOPB. */
506     pcnt->CTRL = tmp;
507 
508     /* There are no syncs for TOP, CMD or CTRL because the clock rate is unknown
509      * and the program could stall
510      * These will be synced within 3 clock cycles of the external clock  /
511      * For the same reason CNT cannot be written here. */
512     break;
513 
514   /* pcntModeDisable */
515   /* pcntModeOvsSingle */
516   default:
517     /* No need to set disabled mode if already disabled. */
518     if ((pcnt->CTRL & _PCNT_CTRL_MODE_MASK) != PCNT_CTRL_MODE_DISABLE)
519     {
520       /* Set control to disabled mode, leave reset on until ensured disabled.
521        * We don't need to wait for CTRL SYNCBUSY completion here, it was
522        * triggered by reset bit above, which is asynchronous. */
523       pcnt->CTRL = tmp | PCNT_CTRL_MODE_DISABLE | PCNT_CTRL_RSTEN;
524 
525       /* Wait until CTRL write synchronized into LF domain before proceeding
526        * to disable reset. */
527       PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
528     }
529 
530     /* Disable reset bit, counter should now be in disabled mode. */
531     BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
532 
533     /* Set counter and top values as specified. */
534     PCNT_CounterTopSet(pcnt, init->counter, init->top);
535 
536     /* Enter oversampling mode if selected. */
537     if (init->mode == pcntModeOvsSingle)
538     {
539       PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
540       pcnt->CTRL = tmp | (init->mode << _PCNT_CTRL_MODE_SHIFT);
541     }
542     break;
543   }
544 }
545 
546 
547 /***************************************************************************//**
548  * @brief
549  *   Reset PCNT to same state as after a HW reset.
550  *
551  * @details
552  *   Notice the LFACLK must be enabled, since some basic reset is done with
553  *   this clock. The pulse counter clock for the selected instance must also
554  *   be enabled prior to init.
555  *
556  * @note
557  *   The ROUTE register is NOT reset by this function, in order to allow for
558  *   centralized setup of this feature.
559  *
560  * @param[in] pcnt
561  *   Pointer to PCNT peripheral register block.
562  ******************************************************************************/
PCNT_Reset(PCNT_TypeDef * pcnt)563 void PCNT_Reset(PCNT_TypeDef *pcnt)
564 {
565   unsigned int inst;
566 
567   EFM_ASSERT(PCNT_REF_VALID(pcnt));
568 
569   /* Map pointer to instance and clock info */
570   inst = PCNT_Map(pcnt);
571 
572   pcnt->IEN = _PCNT_IEN_RESETVALUE;
573 
574   /* Notice that special SYNCBUSY handling is not applicable for the RSTEN
575    * bit of the control register, so we don't need to wait for it when only
576    * modifying RSTEN. The SYNCBUSY bit will be set, leading to a
577    * synchronization in the LF domain, with in reality no changes to LF domain.
578    * Enable reset of CNT and TOP register. */
579   BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
580 
581   /* Select LFACLK as default */
582   CMU_PCNTClockExternalSet(inst, false);
583 
584   PCNT_TopBufferSet(pcnt, _PCNT_TOPB_RESETVALUE);
585 
586   /* Reset CTRL leaving RSTEN set */
587   pcnt->CTRL = _PCNT_CTRL_RESETVALUE | PCNT_CTRL_RSTEN;
588 
589   /* Disable reset after CTRL reg has been synchronized */
590   PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
591   BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
592 
593   /* Clear pending interrupts */
594   pcnt->IFC = _PCNT_IFC_MASK;
595 
596   /* Do not reset route register, setting should be done independently */
597 }
598 
599 
600 /***************************************************************************//**
601  * @brief
602  *   Set top buffer value.
603  *
604  * @note
605  *   This function may stall until synchronization to low frequency domain is
606  *   completed. For that reason, it should normally not be used when using
607  *   an external clock to clock the PCNT module, since stall time may be
608  *   undefined in that case.
609  *
610  * @param[in] pcnt
611  *   Pointer to PCNT peripheral register block.
612  *
613  * @param[in] val
614  *   Value to set in top buffer register.
615  ******************************************************************************/
PCNT_TopBufferSet(PCNT_TypeDef * pcnt,uint32_t val)616 void PCNT_TopBufferSet(PCNT_TypeDef *pcnt, uint32_t val)
617 {
618   EFM_ASSERT(PCNT_REF_VALID(pcnt));
619 
620   /* LF register about to be modified require sync. busy check */
621   PCNT_Sync(pcnt, PCNT_SYNCBUSY_TOPB);
622   pcnt->TOPB = val;
623 }
624 
625 
626 /***************************************************************************//**
627  * @brief
628  *   Set top value.
629  *
630  * @note
631  *   This function will stall until synchronization to low frequency domain is
632  *   completed. For that reason, it should normally not be used when using
633  *   an external clock to clock the PCNT module, since stall time may be
634  *   undefined in that case.
635  *
636  * @param[in] pcnt
637  *   Pointer to PCNT peripheral register block.
638  *
639  * @param[in] val
640  *   Value to set in top register.
641  ******************************************************************************/
PCNT_TopSet(PCNT_TypeDef * pcnt,uint32_t val)642 void PCNT_TopSet(PCNT_TypeDef *pcnt, uint32_t val)
643 {
644   EFM_ASSERT(PCNT_REF_VALID(pcnt));
645 
646   /* LF register about to be modified require sync. busy check */
647 
648   /* Load into TOPB */
649   PCNT_Sync(pcnt, PCNT_SYNCBUSY_TOPB);
650   pcnt->TOPB = val;
651 
652   /* Load TOPB value into TOP */
653   PCNT_Sync(pcnt, PCNT_SYNCBUSY_TOPB | PCNT_SYNCBUSY_CMD);
654   pcnt->CMD = PCNT_CMD_LTOPBIM;
655 }
656 
657 
658 /** @} (end addtogroup PCNT) */
659 /** @} (end addtogroup EM_Library) */
660