added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
mbed_official
Date:
Fri Jan 15 07:45:16 2016 +0000
Revision:
50:a417edff4437
Parent:
0:9b334a45a8ff
Child:
144:ef7eb2e8f9f7
Synchronized with git revision 6010f32619bfcbb01cc73747d4ff9040863482d9

Full URL: https://github.com/mbedmicro/mbed/commit/6010f32619bfcbb01cc73747d4ff9040863482d9/

Remove doubling of buffer size in realiseEndpoint()

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