added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
JojoS
Date:
Sat Sep 10 15:32:04 2016 +0000
Revision:
147:ba84b7dc41a7
Parent:
144:ef7eb2e8f9f7
added prescaler for 16 bit timers (solution as in LPC11xx), default prescaler 31 for max 28 ms period time

Who changed what in which revision?

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