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_usart.c
bogdanm 0:9b334a45a8ff 3 * @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART)
bogdanm 0:9b334a45a8ff 4 * Peripheral API
bogdanm 0:9b334a45a8ff 5 * @version 3.20.12
bogdanm 0:9b334a45a8ff 6 *******************************************************************************
bogdanm 0:9b334a45a8ff 7 * @section License
bogdanm 0:9b334a45a8ff 8 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
bogdanm 0:9b334a45a8ff 9 *******************************************************************************
bogdanm 0:9b334a45a8ff 10 *
bogdanm 0:9b334a45a8ff 11 * Permission is granted to anyone to use this software for any purpose,
bogdanm 0:9b334a45a8ff 12 * including commercial applications, and to alter it and redistribute it
bogdanm 0:9b334a45a8ff 13 * freely, subject to the following restrictions:
bogdanm 0:9b334a45a8ff 14 *
bogdanm 0:9b334a45a8ff 15 * 1. The origin of this software must not be misrepresented; you must not
bogdanm 0:9b334a45a8ff 16 * claim that you wrote the original software.
bogdanm 0:9b334a45a8ff 17 * 2. Altered source versions must be plainly marked as such, and must not be
bogdanm 0:9b334a45a8ff 18 * misrepresented as being the original software.
bogdanm 0:9b334a45a8ff 19 * 3. This notice may not be removed or altered from any source distribution.
bogdanm 0:9b334a45a8ff 20 *
bogdanm 0:9b334a45a8ff 21 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
bogdanm 0:9b334a45a8ff 22 * obligation to support this Software. Silicon Labs is providing the
bogdanm 0:9b334a45a8ff 23 * Software "AS IS", with no express or implied warranties of any kind,
bogdanm 0:9b334a45a8ff 24 * including, but not limited to, any implied warranties of merchantability
bogdanm 0:9b334a45a8ff 25 * or fitness for any particular purpose or warranties against infringement
bogdanm 0:9b334a45a8ff 26 * of any proprietary rights of a third party.
bogdanm 0:9b334a45a8ff 27 *
bogdanm 0:9b334a45a8ff 28 * Silicon Labs will not be liable for any consequential, incidental, or
bogdanm 0:9b334a45a8ff 29 * special damages, or any other relief, or for any claim by any third party,
bogdanm 0:9b334a45a8ff 30 * arising from your use of this Software.
bogdanm 0:9b334a45a8ff 31 *
bogdanm 0:9b334a45a8ff 32 ******************************************************************************/
bogdanm 0:9b334a45a8ff 33
bogdanm 0:9b334a45a8ff 34
bogdanm 0:9b334a45a8ff 35 #include "em_usart.h"
bogdanm 0:9b334a45a8ff 36 #if defined(USART_COUNT) && (USART_COUNT > 0)
bogdanm 0:9b334a45a8ff 37
bogdanm 0:9b334a45a8ff 38 #include "em_cmu.h"
bogdanm 0:9b334a45a8ff 39 #include "em_assert.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 USART
bogdanm 0:9b334a45a8ff 48 * @brief Universal Synchronous/Asynchronous Receiver/Transmitter
bogdanm 0:9b334a45a8ff 49 * Peripheral API
bogdanm 0:9b334a45a8ff 50 * @{
bogdanm 0:9b334a45a8ff 51 ******************************************************************************/
bogdanm 0:9b334a45a8ff 52
bogdanm 0:9b334a45a8ff 53 /*******************************************************************************
bogdanm 0:9b334a45a8ff 54 ******************************* DEFINES ***********************************
bogdanm 0:9b334a45a8ff 55 ******************************************************************************/
bogdanm 0:9b334a45a8ff 56
bogdanm 0:9b334a45a8ff 57 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
bogdanm 0:9b334a45a8ff 58
bogdanm 0:9b334a45a8ff 59
bogdanm 0:9b334a45a8ff 60 /** Validation of USART register block pointer reference for assert statements. */
bogdanm 0:9b334a45a8ff 61 #if (USART_COUNT == 1) && defined(USART0)
bogdanm 0:9b334a45a8ff 62 #define USART_REF_VALID(ref) ((ref) == USART0)
bogdanm 0:9b334a45a8ff 63
bogdanm 0:9b334a45a8ff 64 #elif (USART_COUNT == 1) && defined(USART1)
bogdanm 0:9b334a45a8ff 65 #define USART_REF_VALID(ref) ((ref) == USART1)
bogdanm 0:9b334a45a8ff 66
bogdanm 0:9b334a45a8ff 67 #elif (USART_COUNT == 2) && defined(USART2)
bogdanm 0:9b334a45a8ff 68 #define USART_REF_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
bogdanm 0:9b334a45a8ff 69
bogdanm 0:9b334a45a8ff 70 #elif (USART_COUNT == 2)
bogdanm 0:9b334a45a8ff 71 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
bogdanm 0:9b334a45a8ff 72
bogdanm 0:9b334a45a8ff 73 #elif (USART_COUNT == 3)
bogdanm 0:9b334a45a8ff 74 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \
bogdanm 0:9b334a45a8ff 75 ((ref) == USART2))
bogdanm 0:9b334a45a8ff 76 #elif (USART_COUNT == 4)
bogdanm 0:9b334a45a8ff 77 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \
bogdanm 0:9b334a45a8ff 78 ((ref) == USART2) || ((ref) == USART3))
bogdanm 0:9b334a45a8ff 79 #else
bogdanm 0:9b334a45a8ff 80 #error Undefined number of USARTs.
bogdanm 0:9b334a45a8ff 81 #endif
bogdanm 0:9b334a45a8ff 82
bogdanm 0:9b334a45a8ff 83 #if (USARTRF_COUNT == 1) && defined(USARTRF0)
bogdanm 0:9b334a45a8ff 84 #define USARTRF_REF_VALID(ref) ((ref) == USARTRF0)
bogdanm 0:9b334a45a8ff 85 #else
bogdanm 0:9b334a45a8ff 86 #define USARTRF_REF_VALID(ref) (0)
bogdanm 0:9b334a45a8ff 87 #endif
bogdanm 0:9b334a45a8ff 88
bogdanm 0:9b334a45a8ff 89 #if defined( _EFM32_HAPPY_FAMILY )
bogdanm 0:9b334a45a8ff 90 #define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
bogdanm 0:9b334a45a8ff 91 #elif defined(USART0)
bogdanm 0:9b334a45a8ff 92 #define USART_IRDA_VALID(ref) ((ref) == USART0)
bogdanm 0:9b334a45a8ff 93 #elif (USART_COUNT == 1) && defined(USART1)
bogdanm 0:9b334a45a8ff 94 #define USART_IRDA_VALID(ref) ((ref) == USART1)
bogdanm 0:9b334a45a8ff 95 #else
bogdanm 0:9b334a45a8ff 96 #define USART_IRDA_VALID(ref) (0)
bogdanm 0:9b334a45a8ff 97 #endif
bogdanm 0:9b334a45a8ff 98
bogdanm 0:9b334a45a8ff 99 #if defined( _EFM32_HAPPY_FAMILY )
bogdanm 0:9b334a45a8ff 100 #define USART_I2S_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
bogdanm 0:9b334a45a8ff 101 #elif defined(_EFM32_TINY_FAMILY) || defined(_EFM32_ZERO_FAMILY)
bogdanm 0:9b334a45a8ff 102 #define USART_I2S_VALID(ref) ((ref) == USART1)
bogdanm 0:9b334a45a8ff 103 #elif defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
bogdanm 0:9b334a45a8ff 104 #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
bogdanm 0:9b334a45a8ff 105 #endif
bogdanm 0:9b334a45a8ff 106
bogdanm 0:9b334a45a8ff 107 #if (UART_COUNT == 1)
bogdanm 0:9b334a45a8ff 108 #define UART_REF_VALID(ref) ((ref) == UART0)
bogdanm 0:9b334a45a8ff 109 #elif (UART_COUNT == 2)
bogdanm 0:9b334a45a8ff 110 #define UART_REF_VALID(ref) (((ref) == UART0) || ((ref) == UART1))
bogdanm 0:9b334a45a8ff 111 #else
bogdanm 0:9b334a45a8ff 112 #define UART_REF_VALID(ref) (0)
bogdanm 0:9b334a45a8ff 113 #endif
bogdanm 0:9b334a45a8ff 114
bogdanm 0:9b334a45a8ff 115 /** @endcond */
bogdanm 0:9b334a45a8ff 116
bogdanm 0:9b334a45a8ff 117
bogdanm 0:9b334a45a8ff 118 /*******************************************************************************
bogdanm 0:9b334a45a8ff 119 ************************** GLOBAL FUNCTIONS *******************************
bogdanm 0:9b334a45a8ff 120 ******************************************************************************/
bogdanm 0:9b334a45a8ff 121
bogdanm 0:9b334a45a8ff 122 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 123 * @brief
bogdanm 0:9b334a45a8ff 124 * Configure USART/UART operating in asynchronous mode to use a given
bogdanm 0:9b334a45a8ff 125 * baudrate (or as close as possible to specified baudrate).
bogdanm 0:9b334a45a8ff 126 *
bogdanm 0:9b334a45a8ff 127 * @param[in] usart
bogdanm 0:9b334a45a8ff 128 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 129 *
bogdanm 0:9b334a45a8ff 130 * @param[in] refFreq
bogdanm 0:9b334a45a8ff 131 * USART/UART reference clock frequency in Hz that will be used. If set to 0,
bogdanm 0:9b334a45a8ff 132 * the currently configured reference clock is assumed.
bogdanm 0:9b334a45a8ff 133 *
bogdanm 0:9b334a45a8ff 134 * @param[in] baudrate
bogdanm 0:9b334a45a8ff 135 * Baudrate to try to achieve for USART/UART.
bogdanm 0:9b334a45a8ff 136 *
bogdanm 0:9b334a45a8ff 137 * @param[in] ovs
bogdanm 0:9b334a45a8ff 138 * Oversampling to be used. Normal is 16x oversampling, but lower oversampling
bogdanm 0:9b334a45a8ff 139 * may be used to achieve higher rates or better baudrate accuracy in some
bogdanm 0:9b334a45a8ff 140 * cases. Notice that lower oversampling frequency makes channel more
bogdanm 0:9b334a45a8ff 141 * vulnerable to bit faults during reception due to clock inaccuracies
bogdanm 0:9b334a45a8ff 142 * compared to link partner.
bogdanm 0:9b334a45a8ff 143 ******************************************************************************/
bogdanm 0:9b334a45a8ff 144 void USART_BaudrateAsyncSet(USART_TypeDef *usart,
bogdanm 0:9b334a45a8ff 145 uint32_t refFreq,
bogdanm 0:9b334a45a8ff 146 uint32_t baudrate,
bogdanm 0:9b334a45a8ff 147 USART_OVS_TypeDef ovs)
bogdanm 0:9b334a45a8ff 148 {
bogdanm 0:9b334a45a8ff 149 uint32_t clkdiv;
bogdanm 0:9b334a45a8ff 150 uint32_t oversample;
bogdanm 0:9b334a45a8ff 151
bogdanm 0:9b334a45a8ff 152 /* Inhibit divide by 0 */
bogdanm 0:9b334a45a8ff 153 EFM_ASSERT(baudrate);
bogdanm 0:9b334a45a8ff 154
bogdanm 0:9b334a45a8ff 155 /*
bogdanm 0:9b334a45a8ff 156 * We want to use integer division to avoid forcing in float division
bogdanm 0:9b334a45a8ff 157 * utils, and yet keep rounding effect errors to a minimum.
bogdanm 0:9b334a45a8ff 158 *
bogdanm 0:9b334a45a8ff 159 * CLKDIV in asynchronous mode is given by:
bogdanm 0:9b334a45a8ff 160 *
bogdanm 0:9b334a45a8ff 161 * CLKDIV = 256 * (fHFPERCLK/(oversample * br) - 1)
bogdanm 0:9b334a45a8ff 162 * or
bogdanm 0:9b334a45a8ff 163 * CLKDIV = (256 * fHFPERCLK)/(oversample * br) - 256
bogdanm 0:9b334a45a8ff 164 *
bogdanm 0:9b334a45a8ff 165 * The basic problem with integer division in the above formula is that
bogdanm 0:9b334a45a8ff 166 * the dividend (256 * fHFPERCLK) may become higher than max 32 bit
bogdanm 0:9b334a45a8ff 167 * integer. Yet, we want to evaluate dividend first before dividing in
bogdanm 0:9b334a45a8ff 168 * order to get as small rounding effects as possible. We do not want
bogdanm 0:9b334a45a8ff 169 * to make too harsh restrictions on max fHFPERCLK value either.
bogdanm 0:9b334a45a8ff 170 *
bogdanm 0:9b334a45a8ff 171 * One can possibly factorize 256 and oversample/br. However,
bogdanm 0:9b334a45a8ff 172 * since the last 6 bits of CLKDIV are don't care, we can base our
bogdanm 0:9b334a45a8ff 173 * integer arithmetic on the below formula
bogdanm 0:9b334a45a8ff 174 *
bogdanm 0:9b334a45a8ff 175 * CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4
bogdanm 0:9b334a45a8ff 176 *
bogdanm 0:9b334a45a8ff 177 * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
bogdanm 0:9b334a45a8ff 178 * up to 1GHz without overflowing a 32 bit value!
bogdanm 0:9b334a45a8ff 179 */
bogdanm 0:9b334a45a8ff 180
bogdanm 0:9b334a45a8ff 181 /* HFPERCLK used to clock all USART/UART peripheral modules */
bogdanm 0:9b334a45a8ff 182 if (!refFreq)
bogdanm 0:9b334a45a8ff 183 {
bogdanm 0:9b334a45a8ff 184 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
bogdanm 0:9b334a45a8ff 185 }
bogdanm 0:9b334a45a8ff 186
bogdanm 0:9b334a45a8ff 187 /* Map oversampling */
bogdanm 0:9b334a45a8ff 188 switch (ovs)
bogdanm 0:9b334a45a8ff 189 {
bogdanm 0:9b334a45a8ff 190 case USART_CTRL_OVS_X16:
bogdanm 0:9b334a45a8ff 191 EFM_ASSERT(baudrate <= (refFreq / 16));
bogdanm 0:9b334a45a8ff 192 oversample = 16;
bogdanm 0:9b334a45a8ff 193 break;
bogdanm 0:9b334a45a8ff 194
bogdanm 0:9b334a45a8ff 195 case USART_CTRL_OVS_X8:
bogdanm 0:9b334a45a8ff 196 EFM_ASSERT(baudrate <= (refFreq / 8));
bogdanm 0:9b334a45a8ff 197 oversample = 8;
bogdanm 0:9b334a45a8ff 198 break;
bogdanm 0:9b334a45a8ff 199
bogdanm 0:9b334a45a8ff 200 case USART_CTRL_OVS_X6:
bogdanm 0:9b334a45a8ff 201 EFM_ASSERT(baudrate <= (refFreq / 6));
bogdanm 0:9b334a45a8ff 202 oversample = 6;
bogdanm 0:9b334a45a8ff 203 break;
bogdanm 0:9b334a45a8ff 204
bogdanm 0:9b334a45a8ff 205 case USART_CTRL_OVS_X4:
bogdanm 0:9b334a45a8ff 206 EFM_ASSERT(baudrate <= (refFreq / 4));
bogdanm 0:9b334a45a8ff 207 oversample = 4;
bogdanm 0:9b334a45a8ff 208 break;
bogdanm 0:9b334a45a8ff 209
bogdanm 0:9b334a45a8ff 210 default:
bogdanm 0:9b334a45a8ff 211 /* Invalid input */
bogdanm 0:9b334a45a8ff 212 EFM_ASSERT(0);
bogdanm 0:9b334a45a8ff 213 return;
bogdanm 0:9b334a45a8ff 214 }
bogdanm 0:9b334a45a8ff 215
bogdanm 0:9b334a45a8ff 216 /* Calculate and set CLKDIV with fractional bits.
bogdanm 0:9b334a45a8ff 217 * The addend (oversample*baudrate)/2 in the first line is to round the
bogdanm 0:9b334a45a8ff 218 * divisor up by half the divisor before the division in order to reduce the
bogdanm 0:9b334a45a8ff 219 * integer division error, which consequently results in a higher baudrate
bogdanm 0:9b334a45a8ff 220 * than desired. */
bogdanm 0:9b334a45a8ff 221 clkdiv = 4 * refFreq + (oversample * baudrate) / 2;
bogdanm 0:9b334a45a8ff 222 clkdiv /= (oversample * baudrate);
bogdanm 0:9b334a45a8ff 223 clkdiv -= 4;
bogdanm 0:9b334a45a8ff 224 clkdiv *= 64;
bogdanm 0:9b334a45a8ff 225
bogdanm 0:9b334a45a8ff 226 /* Verify that resulting clock divider is within limits */
bogdanm 0:9b334a45a8ff 227 EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK);
bogdanm 0:9b334a45a8ff 228
bogdanm 0:9b334a45a8ff 229 /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */
bogdanm 0:9b334a45a8ff 230 clkdiv &= _USART_CLKDIV_MASK;
bogdanm 0:9b334a45a8ff 231
bogdanm 0:9b334a45a8ff 232 usart->CTRL &= ~_USART_CTRL_OVS_MASK;
bogdanm 0:9b334a45a8ff 233 usart->CTRL |= ovs;
bogdanm 0:9b334a45a8ff 234 usart->CLKDIV = clkdiv;
bogdanm 0:9b334a45a8ff 235 }
bogdanm 0:9b334a45a8ff 236
bogdanm 0:9b334a45a8ff 237
bogdanm 0:9b334a45a8ff 238 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 239 * @brief
bogdanm 0:9b334a45a8ff 240 * Calculate baudrate for USART/UART given reference frequency, clock division
bogdanm 0:9b334a45a8ff 241 * and oversampling rate (if async mode).
bogdanm 0:9b334a45a8ff 242 *
bogdanm 0:9b334a45a8ff 243 * @details
bogdanm 0:9b334a45a8ff 244 * This function returns the baudrate that a USART/UART module will use if
bogdanm 0:9b334a45a8ff 245 * configured with the given frequency, clock divisor and mode. Notice that
bogdanm 0:9b334a45a8ff 246 * this function will not use actual HW configuration. It can be used
bogdanm 0:9b334a45a8ff 247 * to determinate if a given configuration is sufficiently accurate for the
bogdanm 0:9b334a45a8ff 248 * application.
bogdanm 0:9b334a45a8ff 249 *
bogdanm 0:9b334a45a8ff 250 * @param[in] refFreq
bogdanm 0:9b334a45a8ff 251 * USART/UART HF peripheral frequency used.
bogdanm 0:9b334a45a8ff 252 *
bogdanm 0:9b334a45a8ff 253 * @param[in] clkdiv
bogdanm 0:9b334a45a8ff 254 * Clock division factor to be used.
bogdanm 0:9b334a45a8ff 255 *
bogdanm 0:9b334a45a8ff 256 * @param[in] syncmode
bogdanm 0:9b334a45a8ff 257 * @li true - synchronous mode operation.
bogdanm 0:9b334a45a8ff 258 * @li false - asynchronous mode operation.
bogdanm 0:9b334a45a8ff 259 *
bogdanm 0:9b334a45a8ff 260 * @param[in] ovs
bogdanm 0:9b334a45a8ff 261 * Oversampling used if asynchronous mode. Not used if @p syncmode is true.
bogdanm 0:9b334a45a8ff 262 *
bogdanm 0:9b334a45a8ff 263 * @return
bogdanm 0:9b334a45a8ff 264 * Baudrate with given settings.
bogdanm 0:9b334a45a8ff 265 ******************************************************************************/
bogdanm 0:9b334a45a8ff 266 uint32_t USART_BaudrateCalc(uint32_t refFreq,
bogdanm 0:9b334a45a8ff 267 uint32_t clkdiv,
bogdanm 0:9b334a45a8ff 268 bool syncmode,
bogdanm 0:9b334a45a8ff 269 USART_OVS_TypeDef ovs)
bogdanm 0:9b334a45a8ff 270 {
bogdanm 0:9b334a45a8ff 271 uint32_t oversample;
bogdanm 0:9b334a45a8ff 272 uint32_t divisor;
bogdanm 0:9b334a45a8ff 273 uint32_t factor;
bogdanm 0:9b334a45a8ff 274 uint32_t remainder;
bogdanm 0:9b334a45a8ff 275 uint32_t quotient;
bogdanm 0:9b334a45a8ff 276 uint32_t br;
bogdanm 0:9b334a45a8ff 277
bogdanm 0:9b334a45a8ff 278 /* Mask out unused bits */
bogdanm 0:9b334a45a8ff 279 clkdiv &= _USART_CLKDIV_MASK;
bogdanm 0:9b334a45a8ff 280
bogdanm 0:9b334a45a8ff 281 /* We want to use integer division to avoid forcing in float division */
bogdanm 0:9b334a45a8ff 282 /* utils, and yet keep rounding effect errors to a minimum. */
bogdanm 0:9b334a45a8ff 283
bogdanm 0:9b334a45a8ff 284 /* Baudrate calculation depends on if synchronous or asynchronous mode */
bogdanm 0:9b334a45a8ff 285 if (syncmode)
bogdanm 0:9b334a45a8ff 286 {
bogdanm 0:9b334a45a8ff 287 /*
bogdanm 0:9b334a45a8ff 288 * Baudrate is given by:
bogdanm 0:9b334a45a8ff 289 *
bogdanm 0:9b334a45a8ff 290 * br = fHFPERCLK/(2 * (1 + (CLKDIV / 256)))
bogdanm 0:9b334a45a8ff 291 *
bogdanm 0:9b334a45a8ff 292 * which can be rewritten to
bogdanm 0:9b334a45a8ff 293 *
bogdanm 0:9b334a45a8ff 294 * br = (128 * fHFPERCLK)/(256 + CLKDIV)
bogdanm 0:9b334a45a8ff 295 */
bogdanm 0:9b334a45a8ff 296 oversample = 1; /* Not used in sync mode, ie 1 */
bogdanm 0:9b334a45a8ff 297 factor = 128;
bogdanm 0:9b334a45a8ff 298 }
bogdanm 0:9b334a45a8ff 299 else
bogdanm 0:9b334a45a8ff 300 {
bogdanm 0:9b334a45a8ff 301 /*
bogdanm 0:9b334a45a8ff 302 * Baudrate in asynchronous mode is given by:
bogdanm 0:9b334a45a8ff 303 *
bogdanm 0:9b334a45a8ff 304 * br = fHFPERCLK/(oversample * (1 + (CLKDIV / 256)))
bogdanm 0:9b334a45a8ff 305 *
bogdanm 0:9b334a45a8ff 306 * which can be rewritten to
bogdanm 0:9b334a45a8ff 307 *
bogdanm 0:9b334a45a8ff 308 * br = (256 * fHFPERCLK)/(oversample * (256 + CLKDIV))
bogdanm 0:9b334a45a8ff 309 *
bogdanm 0:9b334a45a8ff 310 * First of all we can reduce the 256 factor of the dividend with
bogdanm 0:9b334a45a8ff 311 * (part of) oversample part of the divisor.
bogdanm 0:9b334a45a8ff 312 */
bogdanm 0:9b334a45a8ff 313
bogdanm 0:9b334a45a8ff 314 switch (ovs)
bogdanm 0:9b334a45a8ff 315 {
bogdanm 0:9b334a45a8ff 316 case USART_CTRL_OVS_X16:
bogdanm 0:9b334a45a8ff 317 oversample = 1;
bogdanm 0:9b334a45a8ff 318 factor = 256 / 16;
bogdanm 0:9b334a45a8ff 319 break;
bogdanm 0:9b334a45a8ff 320
bogdanm 0:9b334a45a8ff 321 case USART_CTRL_OVS_X8:
bogdanm 0:9b334a45a8ff 322 oversample = 1;
bogdanm 0:9b334a45a8ff 323 factor = 256 / 8;
bogdanm 0:9b334a45a8ff 324 break;
bogdanm 0:9b334a45a8ff 325
bogdanm 0:9b334a45a8ff 326 case USART_CTRL_OVS_X6:
bogdanm 0:9b334a45a8ff 327 oversample = 3;
bogdanm 0:9b334a45a8ff 328 factor = 256 / 2;
bogdanm 0:9b334a45a8ff 329 break;
bogdanm 0:9b334a45a8ff 330
bogdanm 0:9b334a45a8ff 331 default:
bogdanm 0:9b334a45a8ff 332 oversample = 1;
bogdanm 0:9b334a45a8ff 333 factor = 256 / 4;
bogdanm 0:9b334a45a8ff 334 break;
bogdanm 0:9b334a45a8ff 335 }
bogdanm 0:9b334a45a8ff 336 }
bogdanm 0:9b334a45a8ff 337
bogdanm 0:9b334a45a8ff 338 /*
bogdanm 0:9b334a45a8ff 339 * The basic problem with integer division in the above formula is that
bogdanm 0:9b334a45a8ff 340 * the dividend (factor * fHFPERCLK) may become higher than max 32 bit
bogdanm 0:9b334a45a8ff 341 * integer. Yet we want to evaluate dividend first before dividing in
bogdanm 0:9b334a45a8ff 342 * order to get as small rounding effects as possible. We do not want
bogdanm 0:9b334a45a8ff 343 * to make too harsh restrictions on max fHFPERCLK value either.
bogdanm 0:9b334a45a8ff 344 *
bogdanm 0:9b334a45a8ff 345 * For division a/b, we can write
bogdanm 0:9b334a45a8ff 346 *
bogdanm 0:9b334a45a8ff 347 * a = qb + r
bogdanm 0:9b334a45a8ff 348 *
bogdanm 0:9b334a45a8ff 349 * where q is the quotient and r is the remainder, both integers.
bogdanm 0:9b334a45a8ff 350 *
bogdanm 0:9b334a45a8ff 351 * The orignal baudrate formula can be rewritten as
bogdanm 0:9b334a45a8ff 352 *
bogdanm 0:9b334a45a8ff 353 * br = xa / b = x(qb + r)/b = xq + xr/b
bogdanm 0:9b334a45a8ff 354 *
bogdanm 0:9b334a45a8ff 355 * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to
bogdanm 0:9b334a45a8ff 356 * variable names.
bogdanm 0:9b334a45a8ff 357 */
bogdanm 0:9b334a45a8ff 358
bogdanm 0:9b334a45a8ff 359 /* Divisor will never exceed max 32 bit value since clkdiv <= 0x1fffc0 */
bogdanm 0:9b334a45a8ff 360 /* and 'oversample' has been reduced to <= 3. */
bogdanm 0:9b334a45a8ff 361 divisor = oversample * (256 + clkdiv);
bogdanm 0:9b334a45a8ff 362
bogdanm 0:9b334a45a8ff 363 quotient = refFreq / divisor;
bogdanm 0:9b334a45a8ff 364 remainder = refFreq % divisor;
bogdanm 0:9b334a45a8ff 365
bogdanm 0:9b334a45a8ff 366 /* factor <= 128 and since divisor >= 256, the below cannot exceed max */
bogdanm 0:9b334a45a8ff 367 /* 32 bit value. */
bogdanm 0:9b334a45a8ff 368 br = factor * quotient;
bogdanm 0:9b334a45a8ff 369
bogdanm 0:9b334a45a8ff 370 /*
bogdanm 0:9b334a45a8ff 371 * factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
bogdanm 0:9b334a45a8ff 372 * means dividend (factor * remainder) worst case is
bogdanm 0:9b334a45a8ff 373 * 128*(3 * (256 + 0x1fffc0)) = 0x30012000.
bogdanm 0:9b334a45a8ff 374 */
bogdanm 0:9b334a45a8ff 375 br += (factor * remainder) / divisor;
bogdanm 0:9b334a45a8ff 376
bogdanm 0:9b334a45a8ff 377 return br;
bogdanm 0:9b334a45a8ff 378 }
bogdanm 0:9b334a45a8ff 379
bogdanm 0:9b334a45a8ff 380
bogdanm 0:9b334a45a8ff 381 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 382 * @brief
bogdanm 0:9b334a45a8ff 383 * Get current baudrate for USART/UART.
bogdanm 0:9b334a45a8ff 384 *
bogdanm 0:9b334a45a8ff 385 * @details
bogdanm 0:9b334a45a8ff 386 * This function returns the actual baudrate (not considering oscillator
bogdanm 0:9b334a45a8ff 387 * inaccuracies) used by a USART/UART peripheral.
bogdanm 0:9b334a45a8ff 388 *
bogdanm 0:9b334a45a8ff 389 * @param[in] usart
bogdanm 0:9b334a45a8ff 390 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 391 *
bogdanm 0:9b334a45a8ff 392 * @return
bogdanm 0:9b334a45a8ff 393 * Current baudrate.
bogdanm 0:9b334a45a8ff 394 ******************************************************************************/
bogdanm 0:9b334a45a8ff 395 uint32_t USART_BaudrateGet(USART_TypeDef *usart)
bogdanm 0:9b334a45a8ff 396 {
bogdanm 0:9b334a45a8ff 397 uint32_t freq;
bogdanm 0:9b334a45a8ff 398 USART_OVS_TypeDef ovs;
bogdanm 0:9b334a45a8ff 399 bool syncmode;
bogdanm 0:9b334a45a8ff 400
bogdanm 0:9b334a45a8ff 401 if (usart->CTRL & USART_CTRL_SYNC)
bogdanm 0:9b334a45a8ff 402 {
bogdanm 0:9b334a45a8ff 403 syncmode = true;
bogdanm 0:9b334a45a8ff 404 }
bogdanm 0:9b334a45a8ff 405 else
bogdanm 0:9b334a45a8ff 406 {
bogdanm 0:9b334a45a8ff 407 syncmode = false;
bogdanm 0:9b334a45a8ff 408 }
bogdanm 0:9b334a45a8ff 409
bogdanm 0:9b334a45a8ff 410 /* HFPERCLK used to clock all USART/UART peripheral modules */
bogdanm 0:9b334a45a8ff 411 freq = CMU_ClockFreqGet(cmuClock_HFPER);
bogdanm 0:9b334a45a8ff 412 ovs = (USART_OVS_TypeDef) (usart->CTRL & _USART_CTRL_OVS_MASK);
bogdanm 0:9b334a45a8ff 413 return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs);
bogdanm 0:9b334a45a8ff 414 }
bogdanm 0:9b334a45a8ff 415
bogdanm 0:9b334a45a8ff 416
bogdanm 0:9b334a45a8ff 417 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 418 * @brief
bogdanm 0:9b334a45a8ff 419 * Configure USART operating in synchronous mode to use a given baudrate
bogdanm 0:9b334a45a8ff 420 * (or as close as possible to specified baudrate).
bogdanm 0:9b334a45a8ff 421 *
bogdanm 0:9b334a45a8ff 422 * @details
bogdanm 0:9b334a45a8ff 423 * The configuration will be set to use a baudrate <= the specified baudrate
bogdanm 0:9b334a45a8ff 424 * in order to ensure that the baudrate does not exceed the specified value.
bogdanm 0:9b334a45a8ff 425 *
bogdanm 0:9b334a45a8ff 426 * Fractional clock division is suppressed, although the HW design allows it.
bogdanm 0:9b334a45a8ff 427 * It could cause half clock cycles to exceed specified limit, and thus
bogdanm 0:9b334a45a8ff 428 * potentially violate specifications for the slave device. In some special
bogdanm 0:9b334a45a8ff 429 * situations fractional clock division may be useful even in synchronous
bogdanm 0:9b334a45a8ff 430 * mode, but in those cases it must be directly adjusted, possibly assisted
bogdanm 0:9b334a45a8ff 431 * by USART_BaudrateCalc():
bogdanm 0:9b334a45a8ff 432 *
bogdanm 0:9b334a45a8ff 433 * @param[in] usart
bogdanm 0:9b334a45a8ff 434 * Pointer to USART peripheral register block. (Cannot be used on UART
bogdanm 0:9b334a45a8ff 435 * modules.)
bogdanm 0:9b334a45a8ff 436 *
bogdanm 0:9b334a45a8ff 437 * @param[in] refFreq
bogdanm 0:9b334a45a8ff 438 * USART reference clock frequency in Hz that will be used. If set to 0,
bogdanm 0:9b334a45a8ff 439 * the currently configured reference clock is assumed.
bogdanm 0:9b334a45a8ff 440 *
bogdanm 0:9b334a45a8ff 441 * @param[in] baudrate
bogdanm 0:9b334a45a8ff 442 * Baudrate to try to achieve for USART.
bogdanm 0:9b334a45a8ff 443 ******************************************************************************/
bogdanm 0:9b334a45a8ff 444 void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
bogdanm 0:9b334a45a8ff 445 {
bogdanm 0:9b334a45a8ff 446 uint32_t clkdiv;
bogdanm 0:9b334a45a8ff 447
bogdanm 0:9b334a45a8ff 448 /* Inhibit divide by 0 */
bogdanm 0:9b334a45a8ff 449 EFM_ASSERT(baudrate);
bogdanm 0:9b334a45a8ff 450
bogdanm 0:9b334a45a8ff 451 /*
bogdanm 0:9b334a45a8ff 452 * We want to use integer division to avoid forcing in float division
bogdanm 0:9b334a45a8ff 453 * utils, and yet keep rounding effect errors to a minimum.
bogdanm 0:9b334a45a8ff 454 *
bogdanm 0:9b334a45a8ff 455 * CLKDIV in synchronous mode is given by:
bogdanm 0:9b334a45a8ff 456 *
bogdanm 0:9b334a45a8ff 457 * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
bogdanm 0:9b334a45a8ff 458 * or
bogdanm 0:9b334a45a8ff 459 * CLKDIV = (256 * fHFPERCLK)/(2 * br) - 256 = (128 * fHFPERCLK)/br - 256
bogdanm 0:9b334a45a8ff 460 *
bogdanm 0:9b334a45a8ff 461 * The basic problem with integer division in the above formula is that
bogdanm 0:9b334a45a8ff 462 * the dividend (128 * fHFPERCLK) may become higher than max 32 bit
bogdanm 0:9b334a45a8ff 463 * integer. Yet, we want to evaluate dividend first before dividing in
bogdanm 0:9b334a45a8ff 464 * order to get as small rounding effects as possible. We do not want
bogdanm 0:9b334a45a8ff 465 * to make too harsh restrictions on max fHFPERCLK value either.
bogdanm 0:9b334a45a8ff 466 *
bogdanm 0:9b334a45a8ff 467 * One can possibly factorize 128 and br. However, since the last
bogdanm 0:9b334a45a8ff 468 * 6 bits of CLKDIV are don't care, we can base our integer arithmetic
bogdanm 0:9b334a45a8ff 469 * on the below formula without loosing any extra precision:
bogdanm 0:9b334a45a8ff 470 *
bogdanm 0:9b334a45a8ff 471 * CLKDIV / 64 = (2 * fHFPERCLK)/br - 4
bogdanm 0:9b334a45a8ff 472 *
bogdanm 0:9b334a45a8ff 473 * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
bogdanm 0:9b334a45a8ff 474 * up to 2GHz without overflowing a 32 bit value!
bogdanm 0:9b334a45a8ff 475 */
bogdanm 0:9b334a45a8ff 476
bogdanm 0:9b334a45a8ff 477 /* HFPERCLK used to clock all USART/UART peripheral modules */
bogdanm 0:9b334a45a8ff 478 if (!refFreq)
bogdanm 0:9b334a45a8ff 479 {
bogdanm 0:9b334a45a8ff 480 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
bogdanm 0:9b334a45a8ff 481 }
bogdanm 0:9b334a45a8ff 482
bogdanm 0:9b334a45a8ff 483 /* Calculate and set CLKDIV with fractional bits */
bogdanm 0:9b334a45a8ff 484 clkdiv = 2 * refFreq;
bogdanm 0:9b334a45a8ff 485 clkdiv += baudrate - 1;
bogdanm 0:9b334a45a8ff 486 clkdiv /= baudrate;
bogdanm 0:9b334a45a8ff 487 clkdiv -= 4;
bogdanm 0:9b334a45a8ff 488 clkdiv *= 64;
bogdanm 0:9b334a45a8ff 489 /* Make sure we don't use fractional bits by rounding CLKDIV */
bogdanm 0:9b334a45a8ff 490 /* up (and thus reducing baudrate, not increasing baudrate above */
bogdanm 0:9b334a45a8ff 491 /* specified value). */
bogdanm 0:9b334a45a8ff 492 clkdiv += 0xc0;
bogdanm 0:9b334a45a8ff 493 clkdiv &= 0xffffff00;
bogdanm 0:9b334a45a8ff 494
bogdanm 0:9b334a45a8ff 495 /* Verify that resulting clock divider is within limits */
bogdanm 0:9b334a45a8ff 496 EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK);
bogdanm 0:9b334a45a8ff 497
bogdanm 0:9b334a45a8ff 498 /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */
bogdanm 0:9b334a45a8ff 499 clkdiv &= _USART_CLKDIV_DIV_MASK;
bogdanm 0:9b334a45a8ff 500
bogdanm 0:9b334a45a8ff 501 usart->CLKDIV = clkdiv;
bogdanm 0:9b334a45a8ff 502 }
bogdanm 0:9b334a45a8ff 503
bogdanm 0:9b334a45a8ff 504
bogdanm 0:9b334a45a8ff 505 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 506 * @brief
bogdanm 0:9b334a45a8ff 507 * Enable/disable USART/UART receiver and/or transmitter.
bogdanm 0:9b334a45a8ff 508 *
bogdanm 0:9b334a45a8ff 509 * @details
bogdanm 0:9b334a45a8ff 510 * Notice that this function does not do any configuration. Enabling should
bogdanm 0:9b334a45a8ff 511 * normally be done after initialization is done (if not enabled as part
bogdanm 0:9b334a45a8ff 512 * of init).
bogdanm 0:9b334a45a8ff 513 *
bogdanm 0:9b334a45a8ff 514 * @param[in] usart
bogdanm 0:9b334a45a8ff 515 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 516 *
bogdanm 0:9b334a45a8ff 517 * @param[in] enable
bogdanm 0:9b334a45a8ff 518 * Select status for receiver/transmitter.
bogdanm 0:9b334a45a8ff 519 ******************************************************************************/
bogdanm 0:9b334a45a8ff 520 void USART_Enable(USART_TypeDef *usart, USART_Enable_TypeDef enable)
bogdanm 0:9b334a45a8ff 521 {
bogdanm 0:9b334a45a8ff 522 uint32_t tmp;
bogdanm 0:9b334a45a8ff 523
bogdanm 0:9b334a45a8ff 524 /* Make sure the module exists on the selected chip */
bogdanm 0:9b334a45a8ff 525 EFM_ASSERT( USART_REF_VALID(usart)
bogdanm 0:9b334a45a8ff 526 || USARTRF_REF_VALID(usart)
bogdanm 0:9b334a45a8ff 527 || UART_REF_VALID(usart) );
bogdanm 0:9b334a45a8ff 528
bogdanm 0:9b334a45a8ff 529 /* Disable as specified */
bogdanm 0:9b334a45a8ff 530 tmp = ~((uint32_t) (enable));
bogdanm 0:9b334a45a8ff 531 tmp &= _USART_CMD_RXEN_MASK | _USART_CMD_TXEN_MASK;
bogdanm 0:9b334a45a8ff 532 usart->CMD = tmp << 1;
bogdanm 0:9b334a45a8ff 533
bogdanm 0:9b334a45a8ff 534 /* Enable as specified */
bogdanm 0:9b334a45a8ff 535 usart->CMD = (uint32_t) (enable);
bogdanm 0:9b334a45a8ff 536 }
bogdanm 0:9b334a45a8ff 537
bogdanm 0:9b334a45a8ff 538
bogdanm 0:9b334a45a8ff 539 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 540 * @brief
bogdanm 0:9b334a45a8ff 541 * Init USART/UART for normal asynchronous mode.
bogdanm 0:9b334a45a8ff 542 *
bogdanm 0:9b334a45a8ff 543 * @details
bogdanm 0:9b334a45a8ff 544 * This function will configure basic settings in order to operate in normal
bogdanm 0:9b334a45a8ff 545 * asynchronous mode.
bogdanm 0:9b334a45a8ff 546 *
bogdanm 0:9b334a45a8ff 547 * Special control setup not covered by this function must be done after
bogdanm 0:9b334a45a8ff 548 * using this function by direct modification of the CTRL register.
bogdanm 0:9b334a45a8ff 549 *
bogdanm 0:9b334a45a8ff 550 * Notice that pins used by the USART/UART module must be properly configured
bogdanm 0:9b334a45a8ff 551 * by the user explicitly, in order for the USART/UART to work as intended.
bogdanm 0:9b334a45a8ff 552 * (When configuring pins, one should remember to consider the sequence of
bogdanm 0:9b334a45a8ff 553 * configuration, in order to avoid unintended pulses/glitches on output
bogdanm 0:9b334a45a8ff 554 * pins.)
bogdanm 0:9b334a45a8ff 555 *
bogdanm 0:9b334a45a8ff 556 * @param[in] usart
bogdanm 0:9b334a45a8ff 557 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 558 *
bogdanm 0:9b334a45a8ff 559 * @param[in] init
bogdanm 0:9b334a45a8ff 560 * Pointer to initialization structure used to configure basic async setup.
bogdanm 0:9b334a45a8ff 561 ******************************************************************************/
bogdanm 0:9b334a45a8ff 562 void USART_InitAsync(USART_TypeDef *usart, const USART_InitAsync_TypeDef *init)
bogdanm 0:9b334a45a8ff 563 {
bogdanm 0:9b334a45a8ff 564 /* Make sure the module exists on the selected chip */
bogdanm 0:9b334a45a8ff 565 EFM_ASSERT( USART_REF_VALID(usart)
bogdanm 0:9b334a45a8ff 566 || USARTRF_REF_VALID(usart)
bogdanm 0:9b334a45a8ff 567 || UART_REF_VALID(usart) );
bogdanm 0:9b334a45a8ff 568
bogdanm 0:9b334a45a8ff 569 /* Init USART registers to HW reset state. */
bogdanm 0:9b334a45a8ff 570 USART_Reset(usart);
bogdanm 0:9b334a45a8ff 571
bogdanm 0:9b334a45a8ff 572 #if defined(USART_INPUT_RXPRS) && defined(USART_CTRL_MVDIS)
bogdanm 0:9b334a45a8ff 573 /* Disable majority vote if specified. */
bogdanm 0:9b334a45a8ff 574 if (init->mvdis)
bogdanm 0:9b334a45a8ff 575 {
bogdanm 0:9b334a45a8ff 576 usart->CTRL |= USART_CTRL_MVDIS;
bogdanm 0:9b334a45a8ff 577 }
bogdanm 0:9b334a45a8ff 578
bogdanm 0:9b334a45a8ff 579 /* Configure PRS input mode. */
bogdanm 0:9b334a45a8ff 580 if (init->prsRxEnable)
bogdanm 0:9b334a45a8ff 581 {
bogdanm 0:9b334a45a8ff 582 usart->INPUT = (uint32_t) init->prsRxCh | USART_INPUT_RXPRS;
bogdanm 0:9b334a45a8ff 583 }
bogdanm 0:9b334a45a8ff 584 #endif
bogdanm 0:9b334a45a8ff 585
bogdanm 0:9b334a45a8ff 586 /* Configure databits, stopbits and parity */
bogdanm 0:9b334a45a8ff 587 usart->FRAME = (uint32_t) (init->databits) |
bogdanm 0:9b334a45a8ff 588 (uint32_t) (init->stopbits) |
bogdanm 0:9b334a45a8ff 589 (uint32_t) (init->parity);
bogdanm 0:9b334a45a8ff 590
bogdanm 0:9b334a45a8ff 591 /* Configure baudrate */
bogdanm 0:9b334a45a8ff 592 USART_BaudrateAsyncSet(usart, init->refFreq, init->baudrate, init->oversampling);
bogdanm 0:9b334a45a8ff 593
bogdanm 0:9b334a45a8ff 594 /* Finally enable (as specified) */
bogdanm 0:9b334a45a8ff 595 usart->CMD = (uint32_t) (init->enable);
bogdanm 0:9b334a45a8ff 596 }
bogdanm 0:9b334a45a8ff 597
bogdanm 0:9b334a45a8ff 598
bogdanm 0:9b334a45a8ff 599 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 600 * @brief
bogdanm 0:9b334a45a8ff 601 * Init USART for synchronous mode.
bogdanm 0:9b334a45a8ff 602 *
bogdanm 0:9b334a45a8ff 603 * @details
bogdanm 0:9b334a45a8ff 604 * This function will configure basic settings in order to operate in
bogdanm 0:9b334a45a8ff 605 * synchronous mode.
bogdanm 0:9b334a45a8ff 606 *
bogdanm 0:9b334a45a8ff 607 * Special control setup not covered by this function must be done after
bogdanm 0:9b334a45a8ff 608 * using this function by direct modification of the CTRL register.
bogdanm 0:9b334a45a8ff 609 *
bogdanm 0:9b334a45a8ff 610 * Notice that pins used by the USART module must be properly configured
bogdanm 0:9b334a45a8ff 611 * by the user explicitly, in order for the USART to work as intended.
bogdanm 0:9b334a45a8ff 612 * (When configuring pins, one should remember to consider the sequence of
bogdanm 0:9b334a45a8ff 613 * configuration, in order to avoid unintended pulses/glitches on output
bogdanm 0:9b334a45a8ff 614 * pins.)
bogdanm 0:9b334a45a8ff 615 *
bogdanm 0:9b334a45a8ff 616 * @param[in] usart
bogdanm 0:9b334a45a8ff 617 * Pointer to USART peripheral register block. (UART does not support this
bogdanm 0:9b334a45a8ff 618 * mode.)
bogdanm 0:9b334a45a8ff 619 *
bogdanm 0:9b334a45a8ff 620 * @param[in] init
bogdanm 0:9b334a45a8ff 621 * Pointer to initialization structure used to configure basic async setup.
bogdanm 0:9b334a45a8ff 622 ******************************************************************************/
bogdanm 0:9b334a45a8ff 623 void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init)
bogdanm 0:9b334a45a8ff 624 {
bogdanm 0:9b334a45a8ff 625 /* Make sure the module exists on the selected chip */
bogdanm 0:9b334a45a8ff 626 EFM_ASSERT( USART_REF_VALID(usart) || USARTRF_REF_VALID(usart) );
bogdanm 0:9b334a45a8ff 627
bogdanm 0:9b334a45a8ff 628 /* Init USART registers to HW reset state. */
bogdanm 0:9b334a45a8ff 629 USART_Reset(usart);
bogdanm 0:9b334a45a8ff 630
bogdanm 0:9b334a45a8ff 631 /* Set bits for synchronous mode */
bogdanm 0:9b334a45a8ff 632 usart->CTRL |= (USART_CTRL_SYNC) |
bogdanm 0:9b334a45a8ff 633 ((uint32_t) init->clockMode) |
bogdanm 0:9b334a45a8ff 634 (init->msbf ? USART_CTRL_MSBF : 0);
bogdanm 0:9b334a45a8ff 635
bogdanm 0:9b334a45a8ff 636 #if defined(USART_INPUT_RXPRS) && defined(USART_TRIGCTRL_AUTOTXTEN)
bogdanm 0:9b334a45a8ff 637 usart->CTRL |= (init->prsRxEnable ? USART_INPUT_RXPRS : 0) |
bogdanm 0:9b334a45a8ff 638 (init->autoTx ? USART_CTRL_AUTOTX : 0);
bogdanm 0:9b334a45a8ff 639 #endif
bogdanm 0:9b334a45a8ff 640
bogdanm 0:9b334a45a8ff 641 /* Configure databits, leave stopbits and parity at reset default (not used) */
bogdanm 0:9b334a45a8ff 642 usart->FRAME = ((uint32_t) (init->databits)) |
bogdanm 0:9b334a45a8ff 643 (USART_FRAME_STOPBITS_DEFAULT) |
bogdanm 0:9b334a45a8ff 644 (USART_FRAME_PARITY_DEFAULT);
bogdanm 0:9b334a45a8ff 645
bogdanm 0:9b334a45a8ff 646 /* Configure baudrate */
bogdanm 0:9b334a45a8ff 647 USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate);
bogdanm 0:9b334a45a8ff 648
bogdanm 0:9b334a45a8ff 649 /* Finally enable (as specified) */
bogdanm 0:9b334a45a8ff 650 if (init->master)
bogdanm 0:9b334a45a8ff 651 {
bogdanm 0:9b334a45a8ff 652 usart->CMD = USART_CMD_MASTEREN;
bogdanm 0:9b334a45a8ff 653 }
bogdanm 0:9b334a45a8ff 654
bogdanm 0:9b334a45a8ff 655 usart->CMD = (uint32_t) (init->enable);
bogdanm 0:9b334a45a8ff 656 }
bogdanm 0:9b334a45a8ff 657
bogdanm 0:9b334a45a8ff 658
bogdanm 0:9b334a45a8ff 659 #if defined(USART0) || ((USART_COUNT == 1) && defined(USART1))
bogdanm 0:9b334a45a8ff 660 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 661 * @brief
bogdanm 0:9b334a45a8ff 662 * Init USART0 for asynchronous IrDA mode.
bogdanm 0:9b334a45a8ff 663 *
bogdanm 0:9b334a45a8ff 664 * @details
bogdanm 0:9b334a45a8ff 665 * This function will configure basic settings in order to operate in
bogdanm 0:9b334a45a8ff 666 * asynchronous IrDA mode.
bogdanm 0:9b334a45a8ff 667 *
bogdanm 0:9b334a45a8ff 668 * Special control setup not covered by this function must be done after
bogdanm 0:9b334a45a8ff 669 * using this function by direct modification of the CTRL and IRCTRL
bogdanm 0:9b334a45a8ff 670 * registers.
bogdanm 0:9b334a45a8ff 671 *
bogdanm 0:9b334a45a8ff 672 * Notice that pins used by the USART/UART module must be properly configured
bogdanm 0:9b334a45a8ff 673 * by the user explicitly, in order for the USART/UART to work as intended.
bogdanm 0:9b334a45a8ff 674 * (When configuring pins, one should remember to consider the sequence of
bogdanm 0:9b334a45a8ff 675 * configuration, in order to avoid unintended pulses/glitches on output
bogdanm 0:9b334a45a8ff 676 * pins.)
bogdanm 0:9b334a45a8ff 677 *
bogdanm 0:9b334a45a8ff 678 * @param[in] init
bogdanm 0:9b334a45a8ff 679 * Pointer to initialization structure used to configure async IrDA setup.
bogdanm 0:9b334a45a8ff 680 *
bogdanm 0:9b334a45a8ff 681 * @note
bogdanm 0:9b334a45a8ff 682 * This function only applies to USART0 as IrDA is not supported on the other
bogdanm 0:9b334a45a8ff 683 * USART modules.
bogdanm 0:9b334a45a8ff 684 *
bogdanm 0:9b334a45a8ff 685 ******************************************************************************/
bogdanm 0:9b334a45a8ff 686 void USART_InitIrDA(const USART_InitIrDA_TypeDef *init)
bogdanm 0:9b334a45a8ff 687 {
bogdanm 0:9b334a45a8ff 688 #if (USART_COUNT == 1) && defined(USART1)
bogdanm 0:9b334a45a8ff 689 USART_TypeDef *usart = USART1;
bogdanm 0:9b334a45a8ff 690 #else
bogdanm 0:9b334a45a8ff 691 USART_TypeDef *usart = USART0;
bogdanm 0:9b334a45a8ff 692 #endif
bogdanm 0:9b334a45a8ff 693
bogdanm 0:9b334a45a8ff 694 /* Init USART as async device */
bogdanm 0:9b334a45a8ff 695 USART_InitAsync(usart, &(init->async));
bogdanm 0:9b334a45a8ff 696
bogdanm 0:9b334a45a8ff 697 /* Set IrDA modulation to RZI (return-to-zero-inverted) */
bogdanm 0:9b334a45a8ff 698 usart->CTRL |= USART_CTRL_TXINV;
bogdanm 0:9b334a45a8ff 699
bogdanm 0:9b334a45a8ff 700 /* Invert Rx signal before demodulator if enabled */
bogdanm 0:9b334a45a8ff 701 if (init->irRxInv)
bogdanm 0:9b334a45a8ff 702 {
bogdanm 0:9b334a45a8ff 703 usart->CTRL |= USART_CTRL_RXINV;
bogdanm 0:9b334a45a8ff 704 }
bogdanm 0:9b334a45a8ff 705
bogdanm 0:9b334a45a8ff 706 /* Configure IrDA */
bogdanm 0:9b334a45a8ff 707 usart->IRCTRL |= (uint32_t) init->irPw |
bogdanm 0:9b334a45a8ff 708 (uint32_t) init->irPrsSel |
bogdanm 0:9b334a45a8ff 709 ((uint32_t) init->irFilt << _USART_IRCTRL_IRFILT_SHIFT) |
bogdanm 0:9b334a45a8ff 710 ((uint32_t) init->irPrsEn << _USART_IRCTRL_IRPRSEN_SHIFT);
bogdanm 0:9b334a45a8ff 711
bogdanm 0:9b334a45a8ff 712 /* Enable IrDA */
bogdanm 0:9b334a45a8ff 713 usart->IRCTRL |= USART_IRCTRL_IREN;
bogdanm 0:9b334a45a8ff 714 }
bogdanm 0:9b334a45a8ff 715 #endif
bogdanm 0:9b334a45a8ff 716
bogdanm 0:9b334a45a8ff 717
bogdanm 0:9b334a45a8ff 718 #if defined(_USART_I2SCTRL_MASK)
bogdanm 0:9b334a45a8ff 719 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 720 * @brief
bogdanm 0:9b334a45a8ff 721 * Init USART for I2S mode.
bogdanm 0:9b334a45a8ff 722 *
bogdanm 0:9b334a45a8ff 723 * @details
bogdanm 0:9b334a45a8ff 724 * This function will configure basic settings in order to operate in I2S
bogdanm 0:9b334a45a8ff 725 * mode.
bogdanm 0:9b334a45a8ff 726 *
bogdanm 0:9b334a45a8ff 727 * Special control setup not covered by this function must be done after
bogdanm 0:9b334a45a8ff 728 * using this function by direct modification of the CTRL and I2SCTRL
bogdanm 0:9b334a45a8ff 729 * registers.
bogdanm 0:9b334a45a8ff 730 *
bogdanm 0:9b334a45a8ff 731 * Notice that pins used by the USART module must be properly configured
bogdanm 0:9b334a45a8ff 732 * by the user explicitly, in order for the USART to work as intended.
bogdanm 0:9b334a45a8ff 733 * (When configuring pins, one should remember to consider the sequence of
bogdanm 0:9b334a45a8ff 734 * configuration, in order to avoid unintended pulses/glitches on output
bogdanm 0:9b334a45a8ff 735 * pins.)
bogdanm 0:9b334a45a8ff 736 *
bogdanm 0:9b334a45a8ff 737 * @param[in] usart
bogdanm 0:9b334a45a8ff 738 * Pointer to USART peripheral register block. (UART does not support this
bogdanm 0:9b334a45a8ff 739 * mode.)
bogdanm 0:9b334a45a8ff 740 *
bogdanm 0:9b334a45a8ff 741 * @param[in] init
bogdanm 0:9b334a45a8ff 742 * Pointer to initialization structure used to configure basic I2S setup.
bogdanm 0:9b334a45a8ff 743 *
bogdanm 0:9b334a45a8ff 744 * @note
bogdanm 0:9b334a45a8ff 745 * This function does not apply to all USART's. Refer to chip manuals.
bogdanm 0:9b334a45a8ff 746 *
bogdanm 0:9b334a45a8ff 747 ******************************************************************************/
bogdanm 0:9b334a45a8ff 748 void USART_InitI2s(USART_TypeDef *usart, USART_InitI2s_TypeDef *init)
bogdanm 0:9b334a45a8ff 749 {
bogdanm 0:9b334a45a8ff 750 USART_Enable_TypeDef enable;
bogdanm 0:9b334a45a8ff 751
bogdanm 0:9b334a45a8ff 752 /* Make sure the module exists on the selected chip */
bogdanm 0:9b334a45a8ff 753 EFM_ASSERT(USART_I2S_VALID(usart));
bogdanm 0:9b334a45a8ff 754
bogdanm 0:9b334a45a8ff 755 /* Override the enable setting. */
bogdanm 0:9b334a45a8ff 756 enable = init->sync.enable;
bogdanm 0:9b334a45a8ff 757 init->sync.enable = usartDisable;
bogdanm 0:9b334a45a8ff 758
bogdanm 0:9b334a45a8ff 759 /* Init USART as a sync device. */
bogdanm 0:9b334a45a8ff 760 USART_InitSync(usart, &init->sync);
bogdanm 0:9b334a45a8ff 761
bogdanm 0:9b334a45a8ff 762 /* Configure and enable I2CCTRL register acording to selected mode. */
bogdanm 0:9b334a45a8ff 763 usart->I2SCTRL = ((uint32_t) init->format) |
bogdanm 0:9b334a45a8ff 764 ((uint32_t) init->justify) |
bogdanm 0:9b334a45a8ff 765 (init->delay ? USART_I2SCTRL_DELAY : 0) |
bogdanm 0:9b334a45a8ff 766 (init->dmaSplit ? USART_I2SCTRL_DMASPLIT : 0) |
bogdanm 0:9b334a45a8ff 767 (init->mono ? USART_I2SCTRL_MONO : 0) |
bogdanm 0:9b334a45a8ff 768 (USART_I2SCTRL_EN);
bogdanm 0:9b334a45a8ff 769
bogdanm 0:9b334a45a8ff 770 if (enable != usartDisable)
bogdanm 0:9b334a45a8ff 771 {
bogdanm 0:9b334a45a8ff 772 USART_Enable(usart, enable);
bogdanm 0:9b334a45a8ff 773 }
bogdanm 0:9b334a45a8ff 774 }
bogdanm 0:9b334a45a8ff 775 #endif
bogdanm 0:9b334a45a8ff 776
bogdanm 0:9b334a45a8ff 777
bogdanm 0:9b334a45a8ff 778 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 779 * @brief
bogdanm 0:9b334a45a8ff 780 * Initialize automatic transmissions using PRS channel as trigger
bogdanm 0:9b334a45a8ff 781 * @note
bogdanm 0:9b334a45a8ff 782 * Initialize USART with USART_Init() before setting up PRS configuration
bogdanm 0:9b334a45a8ff 783 *
bogdanm 0:9b334a45a8ff 784 * @param[in] usart Pointer to USART to configure
bogdanm 0:9b334a45a8ff 785 * @param[in] init Pointer to initialization structure
bogdanm 0:9b334a45a8ff 786 ******************************************************************************/
bogdanm 0:9b334a45a8ff 787 void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init)
bogdanm 0:9b334a45a8ff 788 {
bogdanm 0:9b334a45a8ff 789 uint32_t trigctrl;
bogdanm 0:9b334a45a8ff 790
bogdanm 0:9b334a45a8ff 791 /* Clear values that will be reconfigured */
bogdanm 0:9b334a45a8ff 792 trigctrl = usart->TRIGCTRL & ~(_USART_TRIGCTRL_RXTEN_MASK |
bogdanm 0:9b334a45a8ff 793 _USART_TRIGCTRL_TXTEN_MASK |
bogdanm 0:9b334a45a8ff 794 #if defined(USART_TRIGCTRL_AUTOTXTEN)
bogdanm 0:9b334a45a8ff 795 _USART_TRIGCTRL_AUTOTXTEN_MASK |
bogdanm 0:9b334a45a8ff 796 #endif
bogdanm 0:9b334a45a8ff 797 _USART_TRIGCTRL_TSEL_MASK);
bogdanm 0:9b334a45a8ff 798
bogdanm 0:9b334a45a8ff 799 #if defined(USART_TRIGCTRL_AUTOTXTEN)
bogdanm 0:9b334a45a8ff 800 if (init->autoTxTriggerEnable)
bogdanm 0:9b334a45a8ff 801 {
bogdanm 0:9b334a45a8ff 802 trigctrl |= USART_TRIGCTRL_AUTOTXTEN;
bogdanm 0:9b334a45a8ff 803 }
bogdanm 0:9b334a45a8ff 804 #endif
bogdanm 0:9b334a45a8ff 805 if (init->txTriggerEnable)
bogdanm 0:9b334a45a8ff 806 {
bogdanm 0:9b334a45a8ff 807 trigctrl |= USART_TRIGCTRL_TXTEN;
bogdanm 0:9b334a45a8ff 808 }
bogdanm 0:9b334a45a8ff 809 if (init->rxTriggerEnable)
bogdanm 0:9b334a45a8ff 810 {
bogdanm 0:9b334a45a8ff 811 trigctrl |= USART_TRIGCTRL_RXTEN;
bogdanm 0:9b334a45a8ff 812 }
bogdanm 0:9b334a45a8ff 813 trigctrl |= init->prsTriggerChannel;
bogdanm 0:9b334a45a8ff 814
bogdanm 0:9b334a45a8ff 815 /* Enable new configuration */
bogdanm 0:9b334a45a8ff 816 usart->TRIGCTRL = trigctrl;
bogdanm 0:9b334a45a8ff 817 }
bogdanm 0:9b334a45a8ff 818
bogdanm 0:9b334a45a8ff 819
bogdanm 0:9b334a45a8ff 820 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 821 * @brief
bogdanm 0:9b334a45a8ff 822 * Reset USART/UART to same state as after a HW reset.
bogdanm 0:9b334a45a8ff 823 *
bogdanm 0:9b334a45a8ff 824 * @param[in] usart
bogdanm 0:9b334a45a8ff 825 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 826 ******************************************************************************/
bogdanm 0:9b334a45a8ff 827 void USART_Reset(USART_TypeDef *usart)
bogdanm 0:9b334a45a8ff 828 {
bogdanm 0:9b334a45a8ff 829 /* Make sure the module exists on the selected chip */
bogdanm 0:9b334a45a8ff 830 EFM_ASSERT( USART_REF_VALID(usart)
bogdanm 0:9b334a45a8ff 831 || USARTRF_REF_VALID(usart)
bogdanm 0:9b334a45a8ff 832 || UART_REF_VALID(usart) );
bogdanm 0:9b334a45a8ff 833
bogdanm 0:9b334a45a8ff 834 /* Make sure disabled first, before resetting other registers */
bogdanm 0:9b334a45a8ff 835 usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS |
bogdanm 0:9b334a45a8ff 836 USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX | USART_CMD_CLEARRX;
bogdanm 0:9b334a45a8ff 837 usart->CTRL = _USART_CTRL_RESETVALUE;
bogdanm 0:9b334a45a8ff 838 usart->FRAME = _USART_FRAME_RESETVALUE;
bogdanm 0:9b334a45a8ff 839 usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
bogdanm 0:9b334a45a8ff 840 usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
bogdanm 0:9b334a45a8ff 841 usart->IEN = _USART_IEN_RESETVALUE;
bogdanm 0:9b334a45a8ff 842 usart->IFC = _USART_IFC_MASK;
bogdanm 0:9b334a45a8ff 843 usart->ROUTE = _USART_ROUTE_RESETVALUE;
bogdanm 0:9b334a45a8ff 844
bogdanm 0:9b334a45a8ff 845 if (USART_IRDA_VALID(usart))
bogdanm 0:9b334a45a8ff 846 {
bogdanm 0:9b334a45a8ff 847 usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
bogdanm 0:9b334a45a8ff 848 }
bogdanm 0:9b334a45a8ff 849
bogdanm 0:9b334a45a8ff 850 #if defined(_USART_INPUT_RESETVALUE)
bogdanm 0:9b334a45a8ff 851 usart->INPUT = _USART_INPUT_RESETVALUE;
bogdanm 0:9b334a45a8ff 852 #endif
bogdanm 0:9b334a45a8ff 853
bogdanm 0:9b334a45a8ff 854 #if defined(_USART_I2SCTRL_RESETVALUE)
bogdanm 0:9b334a45a8ff 855 if (USART_I2S_VALID(usart))
bogdanm 0:9b334a45a8ff 856 {
bogdanm 0:9b334a45a8ff 857 usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
bogdanm 0:9b334a45a8ff 858 }
bogdanm 0:9b334a45a8ff 859 #endif
bogdanm 0:9b334a45a8ff 860 }
bogdanm 0:9b334a45a8ff 861
bogdanm 0:9b334a45a8ff 862
bogdanm 0:9b334a45a8ff 863 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 864 * @brief
bogdanm 0:9b334a45a8ff 865 * Receive one 4-8 bit frame, (or part of 10-16 bit frame).
bogdanm 0:9b334a45a8ff 866 *
bogdanm 0:9b334a45a8ff 867 * @details
bogdanm 0:9b334a45a8ff 868 * This function is normally used to receive one frame when operating with
bogdanm 0:9b334a45a8ff 869 * frame length 4-8 bits. Please refer to @ref USART_RxExt() for reception of
bogdanm 0:9b334a45a8ff 870 * 9 bit frames.
bogdanm 0:9b334a45a8ff 871 *
bogdanm 0:9b334a45a8ff 872 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 873 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 874 *
bogdanm 0:9b334a45a8ff 875 * @note
bogdanm 0:9b334a45a8ff 876 * This function will stall if the buffer is empty, until data is received.
bogdanm 0:9b334a45a8ff 877 * Alternatively the user can explicitly check whether data is available, and
bogdanm 0:9b334a45a8ff 878 * if data is avaliable, call @ref USART_RxDataGet() to read the RXDATA
bogdanm 0:9b334a45a8ff 879 * register directly.
bogdanm 0:9b334a45a8ff 880 *
bogdanm 0:9b334a45a8ff 881 * @param[in] usart
bogdanm 0:9b334a45a8ff 882 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 883 *
bogdanm 0:9b334a45a8ff 884 * @return
bogdanm 0:9b334a45a8ff 885 * Data received.
bogdanm 0:9b334a45a8ff 886 ******************************************************************************/
bogdanm 0:9b334a45a8ff 887 uint8_t USART_Rx(USART_TypeDef *usart)
bogdanm 0:9b334a45a8ff 888 {
bogdanm 0:9b334a45a8ff 889 while (!(usart->STATUS & USART_STATUS_RXDATAV))
bogdanm 0:9b334a45a8ff 890 ;
bogdanm 0:9b334a45a8ff 891
bogdanm 0:9b334a45a8ff 892 return (uint8_t) (usart->RXDATA);
bogdanm 0:9b334a45a8ff 893 }
bogdanm 0:9b334a45a8ff 894
bogdanm 0:9b334a45a8ff 895
bogdanm 0:9b334a45a8ff 896 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 897 * @brief
bogdanm 0:9b334a45a8ff 898 * Receive two 4-8 bit frames, or one 10-16 bit frame.
bogdanm 0:9b334a45a8ff 899 *
bogdanm 0:9b334a45a8ff 900 * @details
bogdanm 0:9b334a45a8ff 901 * This function is normally used to receive one frame when operating with
bogdanm 0:9b334a45a8ff 902 * frame length 10-16 bits. Please refer to @ref USART_RxDoubleExt() for
bogdanm 0:9b334a45a8ff 903 * reception of two 9 bit frames.
bogdanm 0:9b334a45a8ff 904 *
bogdanm 0:9b334a45a8ff 905 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 906 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 907 *
bogdanm 0:9b334a45a8ff 908 * @note
bogdanm 0:9b334a45a8ff 909 * This function will stall if buffer is empty, until data is received.
bogdanm 0:9b334a45a8ff 910 * Alternatively the user can explicitly check whether data is available, and
bogdanm 0:9b334a45a8ff 911 * if data is avaliable, call @ref USART_RxDoubleGet() to read the RXDOUBLE
bogdanm 0:9b334a45a8ff 912 * register directly.
bogdanm 0:9b334a45a8ff 913 *
bogdanm 0:9b334a45a8ff 914 * @param[in] usart
bogdanm 0:9b334a45a8ff 915 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 916 *
bogdanm 0:9b334a45a8ff 917 * @return
bogdanm 0:9b334a45a8ff 918 * Data received.
bogdanm 0:9b334a45a8ff 919 ******************************************************************************/
bogdanm 0:9b334a45a8ff 920 uint16_t USART_RxDouble(USART_TypeDef *usart)
bogdanm 0:9b334a45a8ff 921 {
bogdanm 0:9b334a45a8ff 922 while (!(usart->STATUS & USART_STATUS_RXFULL))
bogdanm 0:9b334a45a8ff 923 ;
bogdanm 0:9b334a45a8ff 924
bogdanm 0:9b334a45a8ff 925 return (uint16_t) (usart->RXDOUBLE);
bogdanm 0:9b334a45a8ff 926 }
bogdanm 0:9b334a45a8ff 927
bogdanm 0:9b334a45a8ff 928
bogdanm 0:9b334a45a8ff 929 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 930 * @brief
bogdanm 0:9b334a45a8ff 931 * Receive two 4-9 bit frames, or one 10-16 bit frame with extended
bogdanm 0:9b334a45a8ff 932 * information.
bogdanm 0:9b334a45a8ff 933 *
bogdanm 0:9b334a45a8ff 934 * @details
bogdanm 0:9b334a45a8ff 935 * This function is normally used to receive one frame when operating with
bogdanm 0:9b334a45a8ff 936 * frame length 10-16 bits and additional RX status information is required.
bogdanm 0:9b334a45a8ff 937 *
bogdanm 0:9b334a45a8ff 938 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 939 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 940 *
bogdanm 0:9b334a45a8ff 941 * @note
bogdanm 0:9b334a45a8ff 942 * This function will stall if buffer is empty, until data is received.
bogdanm 0:9b334a45a8ff 943 * Alternatively the user can explicitly check whether data is available, and
bogdanm 0:9b334a45a8ff 944 * if data is avaliable, call @ref USART_RxDoubleXGet() to read the RXDOUBLEX
bogdanm 0:9b334a45a8ff 945 * register directly.
bogdanm 0:9b334a45a8ff 946 *
bogdanm 0:9b334a45a8ff 947 * @param[in] usart
bogdanm 0:9b334a45a8ff 948 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 949 *
bogdanm 0:9b334a45a8ff 950 * @return
bogdanm 0:9b334a45a8ff 951 * Data received.
bogdanm 0:9b334a45a8ff 952 ******************************************************************************/
bogdanm 0:9b334a45a8ff 953 uint32_t USART_RxDoubleExt(USART_TypeDef *usart)
bogdanm 0:9b334a45a8ff 954 {
bogdanm 0:9b334a45a8ff 955 while (!(usart->STATUS & USART_STATUS_RXFULL))
bogdanm 0:9b334a45a8ff 956 ;
bogdanm 0:9b334a45a8ff 957
bogdanm 0:9b334a45a8ff 958 return usart->RXDOUBLEX;
bogdanm 0:9b334a45a8ff 959 }
bogdanm 0:9b334a45a8ff 960
bogdanm 0:9b334a45a8ff 961
bogdanm 0:9b334a45a8ff 962 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 963 * @brief
bogdanm 0:9b334a45a8ff 964 * Receive one 4-9 bit frame, (or part of 10-16 bit frame) with extended
bogdanm 0:9b334a45a8ff 965 * information.
bogdanm 0:9b334a45a8ff 966 *
bogdanm 0:9b334a45a8ff 967 * @details
bogdanm 0:9b334a45a8ff 968 * This function is normally used to receive one frame when operating with
bogdanm 0:9b334a45a8ff 969 * frame length 4-9 bits and additional RX status information is required.
bogdanm 0:9b334a45a8ff 970 *
bogdanm 0:9b334a45a8ff 971 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 972 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 973 *
bogdanm 0:9b334a45a8ff 974 * @note
bogdanm 0:9b334a45a8ff 975 * This function will stall if buffer is empty, until data is received.
bogdanm 0:9b334a45a8ff 976 * Alternatively the user can explicitly check whether data is available, and
bogdanm 0:9b334a45a8ff 977 * if data is avaliable, call @ref USART_RxDataXGet() to read the RXDATAX
bogdanm 0:9b334a45a8ff 978 * register directly.
bogdanm 0:9b334a45a8ff 979 *
bogdanm 0:9b334a45a8ff 980 * @param[in] usart
bogdanm 0:9b334a45a8ff 981 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 982 *
bogdanm 0:9b334a45a8ff 983 * @return
bogdanm 0:9b334a45a8ff 984 * Data received.
bogdanm 0:9b334a45a8ff 985 ******************************************************************************/
bogdanm 0:9b334a45a8ff 986 uint16_t USART_RxExt(USART_TypeDef *usart)
bogdanm 0:9b334a45a8ff 987 {
bogdanm 0:9b334a45a8ff 988 while (!(usart->STATUS & USART_STATUS_RXDATAV))
bogdanm 0:9b334a45a8ff 989 ;
bogdanm 0:9b334a45a8ff 990
bogdanm 0:9b334a45a8ff 991 return (uint16_t) (usart->RXDATAX);
bogdanm 0:9b334a45a8ff 992 }
bogdanm 0:9b334a45a8ff 993
bogdanm 0:9b334a45a8ff 994
bogdanm 0:9b334a45a8ff 995 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 996 * @brief
bogdanm 0:9b334a45a8ff 997 * Perform one 8 bit frame SPI transfer.
bogdanm 0:9b334a45a8ff 998 *
bogdanm 0:9b334a45a8ff 999 * @note
bogdanm 0:9b334a45a8ff 1000 * This function will stall if the transmit buffer is full. When a transmit
bogdanm 0:9b334a45a8ff 1001 * buffer becomes available, data is written and the function will wait until
bogdanm 0:9b334a45a8ff 1002 * the data is fully transmitted. The SPI return value is then read out and
bogdanm 0:9b334a45a8ff 1003 * returned.
bogdanm 0:9b334a45a8ff 1004 *
bogdanm 0:9b334a45a8ff 1005 * @param[in] usart
bogdanm 0:9b334a45a8ff 1006 * Pointer to USART peripheral register block.
bogdanm 0:9b334a45a8ff 1007 *
bogdanm 0:9b334a45a8ff 1008 * @param[in] data
bogdanm 0:9b334a45a8ff 1009 * Data to transmit.
bogdanm 0:9b334a45a8ff 1010 *
bogdanm 0:9b334a45a8ff 1011 * @return
bogdanm 0:9b334a45a8ff 1012 * Data received.
bogdanm 0:9b334a45a8ff 1013 ******************************************************************************/
bogdanm 0:9b334a45a8ff 1014 uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
bogdanm 0:9b334a45a8ff 1015 {
bogdanm 0:9b334a45a8ff 1016 while (!(usart->STATUS & USART_STATUS_TXBL))
bogdanm 0:9b334a45a8ff 1017 ;
bogdanm 0:9b334a45a8ff 1018 usart->TXDATA = (uint32_t) data;
bogdanm 0:9b334a45a8ff 1019 while (!(usart->STATUS & USART_STATUS_TXC))
bogdanm 0:9b334a45a8ff 1020 ;
bogdanm 0:9b334a45a8ff 1021 return (uint8_t) (usart->RXDATA);
bogdanm 0:9b334a45a8ff 1022 }
bogdanm 0:9b334a45a8ff 1023
bogdanm 0:9b334a45a8ff 1024
bogdanm 0:9b334a45a8ff 1025 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 1026 * @brief
bogdanm 0:9b334a45a8ff 1027 * Transmit one 4-9 bit frame.
bogdanm 0:9b334a45a8ff 1028 *
bogdanm 0:9b334a45a8ff 1029 * @details
bogdanm 0:9b334a45a8ff 1030 * Depending on frame length configuration, 4-8 (least significant) bits from
bogdanm 0:9b334a45a8ff 1031 * @p data are transmitted. If frame length is 9, 8 bits are transmitted from
bogdanm 0:9b334a45a8ff 1032 * @p data and one bit as specified by CTRL register, BIT8DV field. Please
bogdanm 0:9b334a45a8ff 1033 * refer to USART_TxExt() for transmitting 9 bit frame with full control of
bogdanm 0:9b334a45a8ff 1034 * all 9 bits.
bogdanm 0:9b334a45a8ff 1035 *
bogdanm 0:9b334a45a8ff 1036 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 1037 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 1038 *
bogdanm 0:9b334a45a8ff 1039 * @note
bogdanm 0:9b334a45a8ff 1040 * This function will stall if buffer is full, until buffer becomes available.
bogdanm 0:9b334a45a8ff 1041 *
bogdanm 0:9b334a45a8ff 1042 * @param[in] usart
bogdanm 0:9b334a45a8ff 1043 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 1044 *
bogdanm 0:9b334a45a8ff 1045 * @param[in] data
bogdanm 0:9b334a45a8ff 1046 * Data to transmit. See details above for further info.
bogdanm 0:9b334a45a8ff 1047 ******************************************************************************/
bogdanm 0:9b334a45a8ff 1048 void USART_Tx(USART_TypeDef *usart, uint8_t data)
bogdanm 0:9b334a45a8ff 1049 {
bogdanm 0:9b334a45a8ff 1050 /* Check that transmit buffer is empty */
bogdanm 0:9b334a45a8ff 1051 while (!(usart->STATUS & USART_STATUS_TXBL))
bogdanm 0:9b334a45a8ff 1052 ;
bogdanm 0:9b334a45a8ff 1053 usart->TXDATA = (uint32_t) data;
bogdanm 0:9b334a45a8ff 1054 }
bogdanm 0:9b334a45a8ff 1055
bogdanm 0:9b334a45a8ff 1056
bogdanm 0:9b334a45a8ff 1057 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 1058 * @brief
bogdanm 0:9b334a45a8ff 1059 * Transmit two 4-9 bit frames, or one 10-16 bit frame.
bogdanm 0:9b334a45a8ff 1060 *
bogdanm 0:9b334a45a8ff 1061 * @details
bogdanm 0:9b334a45a8ff 1062 * Depending on frame length configuration, 4-8 (least significant) bits from
bogdanm 0:9b334a45a8ff 1063 * each byte in @p data are transmitted. If frame length is 9, 8 bits are
bogdanm 0:9b334a45a8ff 1064 * transmitted from each byte in @p data adding one bit as specified by CTRL
bogdanm 0:9b334a45a8ff 1065 * register, BIT8DV field, to each byte. Please refer to USART_TxDoubleExt()
bogdanm 0:9b334a45a8ff 1066 * for transmitting two 9 bit frames with full control of all 9 bits.
bogdanm 0:9b334a45a8ff 1067 *
bogdanm 0:9b334a45a8ff 1068 * If frame length is 10-16, 10-16 (least significant) bits from @p data
bogdanm 0:9b334a45a8ff 1069 * are transmitted.
bogdanm 0:9b334a45a8ff 1070 *
bogdanm 0:9b334a45a8ff 1071 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 1072 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 1073 *
bogdanm 0:9b334a45a8ff 1074 * @note
bogdanm 0:9b334a45a8ff 1075 * This function will stall if buffer is full, until buffer becomes available.
bogdanm 0:9b334a45a8ff 1076 *
bogdanm 0:9b334a45a8ff 1077 * @param[in] usart
bogdanm 0:9b334a45a8ff 1078 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 1079 *
bogdanm 0:9b334a45a8ff 1080 * @param[in] data
bogdanm 0:9b334a45a8ff 1081 * Data to transmit, the least significant byte holds the frame transmitted
bogdanm 0:9b334a45a8ff 1082 * first. See details above for further info.
bogdanm 0:9b334a45a8ff 1083 ******************************************************************************/
bogdanm 0:9b334a45a8ff 1084 void USART_TxDouble(USART_TypeDef *usart, uint16_t data)
bogdanm 0:9b334a45a8ff 1085 {
bogdanm 0:9b334a45a8ff 1086 /* Check that transmit buffer is empty */
bogdanm 0:9b334a45a8ff 1087 while (!(usart->STATUS & USART_STATUS_TXBL))
bogdanm 0:9b334a45a8ff 1088 ;
bogdanm 0:9b334a45a8ff 1089 usart->TXDOUBLE = (uint32_t) data;
bogdanm 0:9b334a45a8ff 1090 }
bogdanm 0:9b334a45a8ff 1091
bogdanm 0:9b334a45a8ff 1092
bogdanm 0:9b334a45a8ff 1093 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 1094 * @brief
bogdanm 0:9b334a45a8ff 1095 * Transmit two 4-9 bit frames, or one 10-16 bit frame with extended control.
bogdanm 0:9b334a45a8ff 1096 *
bogdanm 0:9b334a45a8ff 1097 * @details
bogdanm 0:9b334a45a8ff 1098 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 1099 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 1100 *
bogdanm 0:9b334a45a8ff 1101 * @note
bogdanm 0:9b334a45a8ff 1102 * This function will stall if buffer is full, until buffer becomes available.
bogdanm 0:9b334a45a8ff 1103 *
bogdanm 0:9b334a45a8ff 1104 * @param[in] usart
bogdanm 0:9b334a45a8ff 1105 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 1106 *
bogdanm 0:9b334a45a8ff 1107 * @param[in] data
bogdanm 0:9b334a45a8ff 1108 * Data to transmit with extended control. Contains two 16 bit words
bogdanm 0:9b334a45a8ff 1109 * concatenated. Least significant word holds frame transitted first. If frame
bogdanm 0:9b334a45a8ff 1110 * length is 4-9, two frames with 4-9 least significant bits from each 16 bit
bogdanm 0:9b334a45a8ff 1111 * word are transmitted.
bogdanm 0:9b334a45a8ff 1112 * @par
bogdanm 0:9b334a45a8ff 1113 * If frame length is 10-16 bits, 8 data bits are taken from the least
bogdanm 0:9b334a45a8ff 1114 * significant 16 bit word, and the remaining bits from the other 16 bit word.
bogdanm 0:9b334a45a8ff 1115 * @par
bogdanm 0:9b334a45a8ff 1116 * Additional control bits are available as documented in the EFM32 reference
bogdanm 0:9b334a45a8ff 1117 * manual (set to 0 if not used). For 10-16 bit frame length, these control
bogdanm 0:9b334a45a8ff 1118 * bits are taken from the most significant 16 bit word.
bogdanm 0:9b334a45a8ff 1119 ******************************************************************************/
bogdanm 0:9b334a45a8ff 1120 void USART_TxDoubleExt(USART_TypeDef *usart, uint32_t data)
bogdanm 0:9b334a45a8ff 1121 {
bogdanm 0:9b334a45a8ff 1122 /* Check that transmit buffer is empty */
bogdanm 0:9b334a45a8ff 1123 while (!(usart->STATUS & USART_STATUS_TXBL))
bogdanm 0:9b334a45a8ff 1124 ;
bogdanm 0:9b334a45a8ff 1125 usart->TXDOUBLEX = data;
bogdanm 0:9b334a45a8ff 1126 }
bogdanm 0:9b334a45a8ff 1127
bogdanm 0:9b334a45a8ff 1128
bogdanm 0:9b334a45a8ff 1129 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 1130 * @brief
bogdanm 0:9b334a45a8ff 1131 * Transmit one 4-9 bit frame with extended control.
bogdanm 0:9b334a45a8ff 1132 *
bogdanm 0:9b334a45a8ff 1133 * @details
bogdanm 0:9b334a45a8ff 1134 * Notice that possible parity/stop bits in asynchronous mode are not
bogdanm 0:9b334a45a8ff 1135 * considered part of specified frame bit length.
bogdanm 0:9b334a45a8ff 1136 *
bogdanm 0:9b334a45a8ff 1137 * @note
bogdanm 0:9b334a45a8ff 1138 * This function will stall if buffer is full, until buffer becomes available.
bogdanm 0:9b334a45a8ff 1139 *
bogdanm 0:9b334a45a8ff 1140 * @param[in] usart
bogdanm 0:9b334a45a8ff 1141 * Pointer to USART/UART peripheral register block.
bogdanm 0:9b334a45a8ff 1142 *
bogdanm 0:9b334a45a8ff 1143 * @param[in] data
bogdanm 0:9b334a45a8ff 1144 * Data to transmit with extended control. Least significant bits contains
bogdanm 0:9b334a45a8ff 1145 * frame bits, and additional control bits are available as documented in
bogdanm 0:9b334a45a8ff 1146 * the EFM32 reference manual (set to 0 if not used).
bogdanm 0:9b334a45a8ff 1147 ******************************************************************************/
bogdanm 0:9b334a45a8ff 1148 void USART_TxExt(USART_TypeDef *usart, uint16_t data)
bogdanm 0:9b334a45a8ff 1149 {
bogdanm 0:9b334a45a8ff 1150 /* Check that transmit buffer is empty */
bogdanm 0:9b334a45a8ff 1151 while (!(usart->STATUS & USART_STATUS_TXBL))
bogdanm 0:9b334a45a8ff 1152 ;
bogdanm 0:9b334a45a8ff 1153 usart->TXDATAX = (uint32_t) data;
bogdanm 0:9b334a45a8ff 1154 }
bogdanm 0:9b334a45a8ff 1155
bogdanm 0:9b334a45a8ff 1156
bogdanm 0:9b334a45a8ff 1157 /** @} (end addtogroup USART) */
bogdanm 0:9b334a45a8ff 1158 /** @} (end addtogroup EM_Library) */
bogdanm 0:9b334a45a8ff 1159 #endif /* defined(USART_COUNT) && (USART_COUNT > 0) */