em_pcnt.c 22 KB

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