added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
bogdanm
Date:
Thu Oct 01 15:25:22 2015 +0300
Revision:
0:9b334a45a8ff
Child:
50:a417edff4437
Initial commit on mbed-dev

Replaces mbed-src (now inactive)

Who changed what in which revision?

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