added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
<>
Date:
Fri Sep 02 15:07:44 2016 +0100
Revision:
144:ef7eb2e8f9f7
Parent:
50:a417edff4437
This updates the lib to the mbed lib v125

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) */