added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_usart.c
- Revision:
- 0:9b334a45a8ff
- Child:
- 50:a417edff4437
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_usart.c Thu Oct 01 15:25:22 2015 +0300 @@ -0,0 +1,1159 @@ +/***************************************************************************//** + * @file em_usart.c + * @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART) + * Peripheral API + * @version 3.20.12 + ******************************************************************************* + * @section License + * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> + ******************************************************************************* + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no + * obligation to support this Software. Silicon Labs is providing the + * Software "AS IS", with no express or implied warranties of any kind, + * including, but not limited to, any implied warranties of merchantability + * or fitness for any particular purpose or warranties against infringement + * of any proprietary rights of a third party. + * + * Silicon Labs will not be liable for any consequential, incidental, or + * special damages, or any other relief, or for any claim by any third party, + * arising from your use of this Software. + * + ******************************************************************************/ + + +#include "em_usart.h" +#if defined(USART_COUNT) && (USART_COUNT > 0) + +#include "em_cmu.h" +#include "em_assert.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup USART + * @brief Universal Synchronous/Asynchronous Receiver/Transmitter + * Peripheral API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + + +/** Validation of USART register block pointer reference for assert statements. */ +#if (USART_COUNT == 1) && defined(USART0) +#define USART_REF_VALID(ref) ((ref) == USART0) + +#elif (USART_COUNT == 1) && defined(USART1) +#define USART_REF_VALID(ref) ((ref) == USART1) + +#elif (USART_COUNT == 2) && defined(USART2) +#define USART_REF_VALID(ref) (((ref) == USART1) || ((ref) == USART2)) + +#elif (USART_COUNT == 2) +#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1)) + +#elif (USART_COUNT == 3) +#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \ + ((ref) == USART2)) +#elif (USART_COUNT == 4) +#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \ + ((ref) == USART2) || ((ref) == USART3)) +#else +#error Undefined number of USARTs. +#endif + +#if (USARTRF_COUNT == 1) && defined(USARTRF0) +#define USARTRF_REF_VALID(ref) ((ref) == USARTRF0) +#else +#define USARTRF_REF_VALID(ref) (0) +#endif + +#if defined( _EFM32_HAPPY_FAMILY ) +#define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1)) +#elif defined(USART0) +#define USART_IRDA_VALID(ref) ((ref) == USART0) +#elif (USART_COUNT == 1) && defined(USART1) +#define USART_IRDA_VALID(ref) ((ref) == USART1) +#else +#define USART_IRDA_VALID(ref) (0) +#endif + +#if defined( _EFM32_HAPPY_FAMILY ) +#define USART_I2S_VALID(ref) (((ref) == USART0) || ((ref) == USART1)) +#elif defined(_EFM32_TINY_FAMILY) || defined(_EFM32_ZERO_FAMILY) +#define USART_I2S_VALID(ref) ((ref) == USART1) +#elif defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) +#define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART2)) +#endif + +#if (UART_COUNT == 1) +#define UART_REF_VALID(ref) ((ref) == UART0) +#elif (UART_COUNT == 2) +#define UART_REF_VALID(ref) (((ref) == UART0) || ((ref) == UART1)) +#else +#define UART_REF_VALID(ref) (0) +#endif + +/** @endcond */ + + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Configure USART/UART operating in asynchronous mode to use a given + * baudrate (or as close as possible to specified baudrate). + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] refFreq + * USART/UART reference clock frequency in Hz that will be used. If set to 0, + * the currently configured reference clock is assumed. + * + * @param[in] baudrate + * Baudrate to try to achieve for USART/UART. + * + * @param[in] ovs + * Oversampling to be used. Normal is 16x oversampling, but lower oversampling + * may be used to achieve higher rates or better baudrate accuracy in some + * cases. Notice that lower oversampling frequency makes channel more + * vulnerable to bit faults during reception due to clock inaccuracies + * compared to link partner. + ******************************************************************************/ +void USART_BaudrateAsyncSet(USART_TypeDef *usart, + uint32_t refFreq, + uint32_t baudrate, + USART_OVS_TypeDef ovs) +{ + uint32_t clkdiv; + uint32_t oversample; + + /* Inhibit divide by 0 */ + EFM_ASSERT(baudrate); + + /* + * We want to use integer division to avoid forcing in float division + * utils, and yet keep rounding effect errors to a minimum. + * + * CLKDIV in asynchronous mode is given by: + * + * CLKDIV = 256 * (fHFPERCLK/(oversample * br) - 1) + * or + * CLKDIV = (256 * fHFPERCLK)/(oversample * br) - 256 + * + * The basic problem with integer division in the above formula is that + * the dividend (256 * fHFPERCLK) may become higher than max 32 bit + * integer. Yet, we want to evaluate dividend first before dividing in + * order to get as small rounding effects as possible. We do not want + * to make too harsh restrictions on max fHFPERCLK value either. + * + * One can possibly factorize 256 and oversample/br. However, + * since the last 6 bits of CLKDIV are don't care, we can base our + * integer arithmetic on the below formula + * + * CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4 + * + * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK + * up to 1GHz without overflowing a 32 bit value! + */ + + /* HFPERCLK used to clock all USART/UART peripheral modules */ + if (!refFreq) + { + refFreq = CMU_ClockFreqGet(cmuClock_HFPER); + } + + /* Map oversampling */ + switch (ovs) + { + case USART_CTRL_OVS_X16: + EFM_ASSERT(baudrate <= (refFreq / 16)); + oversample = 16; + break; + + case USART_CTRL_OVS_X8: + EFM_ASSERT(baudrate <= (refFreq / 8)); + oversample = 8; + break; + + case USART_CTRL_OVS_X6: + EFM_ASSERT(baudrate <= (refFreq / 6)); + oversample = 6; + break; + + case USART_CTRL_OVS_X4: + EFM_ASSERT(baudrate <= (refFreq / 4)); + oversample = 4; + break; + + default: + /* Invalid input */ + EFM_ASSERT(0); + return; + } + + /* Calculate and set CLKDIV with fractional bits. + * The addend (oversample*baudrate)/2 in the first line is to round the + * divisor up by half the divisor before the division in order to reduce the + * integer division error, which consequently results in a higher baudrate + * than desired. */ + clkdiv = 4 * refFreq + (oversample * baudrate) / 2; + clkdiv /= (oversample * baudrate); + clkdiv -= 4; + clkdiv *= 64; + + /* Verify that resulting clock divider is within limits */ + EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK); + + /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */ + clkdiv &= _USART_CLKDIV_MASK; + + usart->CTRL &= ~_USART_CTRL_OVS_MASK; + usart->CTRL |= ovs; + usart->CLKDIV = clkdiv; +} + + +/***************************************************************************//** + * @brief + * Calculate baudrate for USART/UART given reference frequency, clock division + * and oversampling rate (if async mode). + * + * @details + * This function returns the baudrate that a USART/UART module will use if + * configured with the given frequency, clock divisor and mode. Notice that + * this function will not use actual HW configuration. It can be used + * to determinate if a given configuration is sufficiently accurate for the + * application. + * + * @param[in] refFreq + * USART/UART HF peripheral frequency used. + * + * @param[in] clkdiv + * Clock division factor to be used. + * + * @param[in] syncmode + * @li true - synchronous mode operation. + * @li false - asynchronous mode operation. + * + * @param[in] ovs + * Oversampling used if asynchronous mode. Not used if @p syncmode is true. + * + * @return + * Baudrate with given settings. + ******************************************************************************/ +uint32_t USART_BaudrateCalc(uint32_t refFreq, + uint32_t clkdiv, + bool syncmode, + USART_OVS_TypeDef ovs) +{ + uint32_t oversample; + uint32_t divisor; + uint32_t factor; + uint32_t remainder; + uint32_t quotient; + uint32_t br; + + /* Mask out unused bits */ + clkdiv &= _USART_CLKDIV_MASK; + + /* We want to use integer division to avoid forcing in float division */ + /* utils, and yet keep rounding effect errors to a minimum. */ + + /* Baudrate calculation depends on if synchronous or asynchronous mode */ + if (syncmode) + { + /* + * Baudrate is given by: + * + * br = fHFPERCLK/(2 * (1 + (CLKDIV / 256))) + * + * which can be rewritten to + * + * br = (128 * fHFPERCLK)/(256 + CLKDIV) + */ + oversample = 1; /* Not used in sync mode, ie 1 */ + factor = 128; + } + else + { + /* + * Baudrate in asynchronous mode is given by: + * + * br = fHFPERCLK/(oversample * (1 + (CLKDIV / 256))) + * + * which can be rewritten to + * + * br = (256 * fHFPERCLK)/(oversample * (256 + CLKDIV)) + * + * First of all we can reduce the 256 factor of the dividend with + * (part of) oversample part of the divisor. + */ + + switch (ovs) + { + case USART_CTRL_OVS_X16: + oversample = 1; + factor = 256 / 16; + break; + + case USART_CTRL_OVS_X8: + oversample = 1; + factor = 256 / 8; + break; + + case USART_CTRL_OVS_X6: + oversample = 3; + factor = 256 / 2; + break; + + default: + oversample = 1; + factor = 256 / 4; + break; + } + } + + /* + * The basic problem with integer division in the above formula is that + * the dividend (factor * fHFPERCLK) may become higher than max 32 bit + * integer. Yet we want to evaluate dividend first before dividing in + * order to get as small rounding effects as possible. We do not want + * to make too harsh restrictions on max fHFPERCLK value either. + * + * For division a/b, we can write + * + * a = qb + r + * + * where q is the quotient and r is the remainder, both integers. + * + * The orignal baudrate formula can be rewritten as + * + * br = xa / b = x(qb + r)/b = xq + xr/b + * + * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to + * variable names. + */ + + /* Divisor will never exceed max 32 bit value since clkdiv <= 0x1fffc0 */ + /* and 'oversample' has been reduced to <= 3. */ + divisor = oversample * (256 + clkdiv); + + quotient = refFreq / divisor; + remainder = refFreq % divisor; + + /* factor <= 128 and since divisor >= 256, the below cannot exceed max */ + /* 32 bit value. */ + br = factor * quotient; + + /* + * factor <= 128 and remainder < (oversample*(256 + clkdiv)), which + * means dividend (factor * remainder) worst case is + * 128*(3 * (256 + 0x1fffc0)) = 0x30012000. + */ + br += (factor * remainder) / divisor; + + return br; +} + + +/***************************************************************************//** + * @brief + * Get current baudrate for USART/UART. + * + * @details + * This function returns the actual baudrate (not considering oscillator + * inaccuracies) used by a USART/UART peripheral. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @return + * Current baudrate. + ******************************************************************************/ +uint32_t USART_BaudrateGet(USART_TypeDef *usart) +{ + uint32_t freq; + USART_OVS_TypeDef ovs; + bool syncmode; + + if (usart->CTRL & USART_CTRL_SYNC) + { + syncmode = true; + } + else + { + syncmode = false; + } + + /* HFPERCLK used to clock all USART/UART peripheral modules */ + freq = CMU_ClockFreqGet(cmuClock_HFPER); + ovs = (USART_OVS_TypeDef) (usart->CTRL & _USART_CTRL_OVS_MASK); + return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs); +} + + +/***************************************************************************//** + * @brief + * Configure USART operating in synchronous mode to use a given baudrate + * (or as close as possible to specified baudrate). + * + * @details + * The configuration will be set to use a baudrate <= the specified baudrate + * in order to ensure that the baudrate does not exceed the specified value. + * + * Fractional clock division is suppressed, although the HW design allows it. + * It could cause half clock cycles to exceed specified limit, and thus + * potentially violate specifications for the slave device. In some special + * situations fractional clock division may be useful even in synchronous + * mode, but in those cases it must be directly adjusted, possibly assisted + * by USART_BaudrateCalc(): + * + * @param[in] usart + * Pointer to USART peripheral register block. (Cannot be used on UART + * modules.) + * + * @param[in] refFreq + * USART reference clock frequency in Hz that will be used. If set to 0, + * the currently configured reference clock is assumed. + * + * @param[in] baudrate + * Baudrate to try to achieve for USART. + ******************************************************************************/ +void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate) +{ + uint32_t clkdiv; + + /* Inhibit divide by 0 */ + EFM_ASSERT(baudrate); + + /* + * We want to use integer division to avoid forcing in float division + * utils, and yet keep rounding effect errors to a minimum. + * + * CLKDIV in synchronous mode is given by: + * + * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1) + * or + * CLKDIV = (256 * fHFPERCLK)/(2 * br) - 256 = (128 * fHFPERCLK)/br - 256 + * + * The basic problem with integer division in the above formula is that + * the dividend (128 * fHFPERCLK) may become higher than max 32 bit + * integer. Yet, we want to evaluate dividend first before dividing in + * order to get as small rounding effects as possible. We do not want + * to make too harsh restrictions on max fHFPERCLK value either. + * + * One can possibly factorize 128 and br. However, since the last + * 6 bits of CLKDIV are don't care, we can base our integer arithmetic + * on the below formula without loosing any extra precision: + * + * CLKDIV / 64 = (2 * fHFPERCLK)/br - 4 + * + * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK + * up to 2GHz without overflowing a 32 bit value! + */ + + /* HFPERCLK used to clock all USART/UART peripheral modules */ + if (!refFreq) + { + refFreq = CMU_ClockFreqGet(cmuClock_HFPER); + } + + /* Calculate and set CLKDIV with fractional bits */ + clkdiv = 2 * refFreq; + clkdiv += baudrate - 1; + clkdiv /= baudrate; + clkdiv -= 4; + clkdiv *= 64; + /* Make sure we don't use fractional bits by rounding CLKDIV */ + /* up (and thus reducing baudrate, not increasing baudrate above */ + /* specified value). */ + clkdiv += 0xc0; + clkdiv &= 0xffffff00; + + /* Verify that resulting clock divider is within limits */ + EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK); + + /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */ + clkdiv &= _USART_CLKDIV_DIV_MASK; + + usart->CLKDIV = clkdiv; +} + + +/***************************************************************************//** + * @brief + * Enable/disable USART/UART receiver and/or transmitter. + * + * @details + * Notice that this function does not do any configuration. Enabling should + * normally be done after initialization is done (if not enabled as part + * of init). + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] enable + * Select status for receiver/transmitter. + ******************************************************************************/ +void USART_Enable(USART_TypeDef *usart, USART_Enable_TypeDef enable) +{ + uint32_t tmp; + + /* Make sure the module exists on the selected chip */ + EFM_ASSERT( USART_REF_VALID(usart) + || USARTRF_REF_VALID(usart) + || UART_REF_VALID(usart) ); + + /* Disable as specified */ + tmp = ~((uint32_t) (enable)); + tmp &= _USART_CMD_RXEN_MASK | _USART_CMD_TXEN_MASK; + usart->CMD = tmp << 1; + + /* Enable as specified */ + usart->CMD = (uint32_t) (enable); +} + + +/***************************************************************************//** + * @brief + * Init USART/UART for normal asynchronous mode. + * + * @details + * This function will configure basic settings in order to operate in normal + * asynchronous mode. + * + * Special control setup not covered by this function must be done after + * using this function by direct modification of the CTRL register. + * + * Notice that pins used by the USART/UART module must be properly configured + * by the user explicitly, in order for the USART/UART to work as intended. + * (When configuring pins, one should remember to consider the sequence of + * configuration, in order to avoid unintended pulses/glitches on output + * pins.) + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] init + * Pointer to initialization structure used to configure basic async setup. + ******************************************************************************/ +void USART_InitAsync(USART_TypeDef *usart, const USART_InitAsync_TypeDef *init) +{ + /* Make sure the module exists on the selected chip */ + EFM_ASSERT( USART_REF_VALID(usart) + || USARTRF_REF_VALID(usart) + || UART_REF_VALID(usart) ); + + /* Init USART registers to HW reset state. */ + USART_Reset(usart); + +#if defined(USART_INPUT_RXPRS) && defined(USART_CTRL_MVDIS) + /* Disable majority vote if specified. */ + if (init->mvdis) + { + usart->CTRL |= USART_CTRL_MVDIS; + } + + /* Configure PRS input mode. */ + if (init->prsRxEnable) + { + usart->INPUT = (uint32_t) init->prsRxCh | USART_INPUT_RXPRS; + } +#endif + + /* Configure databits, stopbits and parity */ + usart->FRAME = (uint32_t) (init->databits) | + (uint32_t) (init->stopbits) | + (uint32_t) (init->parity); + + /* Configure baudrate */ + USART_BaudrateAsyncSet(usart, init->refFreq, init->baudrate, init->oversampling); + + /* Finally enable (as specified) */ + usart->CMD = (uint32_t) (init->enable); +} + + +/***************************************************************************//** + * @brief + * Init USART for synchronous mode. + * + * @details + * This function will configure basic settings in order to operate in + * synchronous mode. + * + * Special control setup not covered by this function must be done after + * using this function by direct modification of the CTRL register. + * + * Notice that pins used by the USART module must be properly configured + * by the user explicitly, in order for the USART to work as intended. + * (When configuring pins, one should remember to consider the sequence of + * configuration, in order to avoid unintended pulses/glitches on output + * pins.) + * + * @param[in] usart + * Pointer to USART peripheral register block. (UART does not support this + * mode.) + * + * @param[in] init + * Pointer to initialization structure used to configure basic async setup. + ******************************************************************************/ +void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init) +{ + /* Make sure the module exists on the selected chip */ + EFM_ASSERT( USART_REF_VALID(usart) || USARTRF_REF_VALID(usart) ); + + /* Init USART registers to HW reset state. */ + USART_Reset(usart); + + /* Set bits for synchronous mode */ + usart->CTRL |= (USART_CTRL_SYNC) | + ((uint32_t) init->clockMode) | + (init->msbf ? USART_CTRL_MSBF : 0); + +#if defined(USART_INPUT_RXPRS) && defined(USART_TRIGCTRL_AUTOTXTEN) + usart->CTRL |= (init->prsRxEnable ? USART_INPUT_RXPRS : 0) | + (init->autoTx ? USART_CTRL_AUTOTX : 0); +#endif + + /* Configure databits, leave stopbits and parity at reset default (not used) */ + usart->FRAME = ((uint32_t) (init->databits)) | + (USART_FRAME_STOPBITS_DEFAULT) | + (USART_FRAME_PARITY_DEFAULT); + + /* Configure baudrate */ + USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate); + + /* Finally enable (as specified) */ + if (init->master) + { + usart->CMD = USART_CMD_MASTEREN; + } + + usart->CMD = (uint32_t) (init->enable); +} + + +#if defined(USART0) || ((USART_COUNT == 1) && defined(USART1)) +/***************************************************************************//** + * @brief + * Init USART0 for asynchronous IrDA mode. + * + * @details + * This function will configure basic settings in order to operate in + * asynchronous IrDA mode. + * + * Special control setup not covered by this function must be done after + * using this function by direct modification of the CTRL and IRCTRL + * registers. + * + * Notice that pins used by the USART/UART module must be properly configured + * by the user explicitly, in order for the USART/UART to work as intended. + * (When configuring pins, one should remember to consider the sequence of + * configuration, in order to avoid unintended pulses/glitches on output + * pins.) + * + * @param[in] init + * Pointer to initialization structure used to configure async IrDA setup. + * + * @note + * This function only applies to USART0 as IrDA is not supported on the other + * USART modules. + * + ******************************************************************************/ +void USART_InitIrDA(const USART_InitIrDA_TypeDef *init) +{ + #if (USART_COUNT == 1) && defined(USART1) + USART_TypeDef *usart = USART1; + #else + USART_TypeDef *usart = USART0; + #endif + + /* Init USART as async device */ + USART_InitAsync(usart, &(init->async)); + + /* Set IrDA modulation to RZI (return-to-zero-inverted) */ + usart->CTRL |= USART_CTRL_TXINV; + + /* Invert Rx signal before demodulator if enabled */ + if (init->irRxInv) + { + usart->CTRL |= USART_CTRL_RXINV; + } + + /* Configure IrDA */ + usart->IRCTRL |= (uint32_t) init->irPw | + (uint32_t) init->irPrsSel | + ((uint32_t) init->irFilt << _USART_IRCTRL_IRFILT_SHIFT) | + ((uint32_t) init->irPrsEn << _USART_IRCTRL_IRPRSEN_SHIFT); + + /* Enable IrDA */ + usart->IRCTRL |= USART_IRCTRL_IREN; +} +#endif + + +#if defined(_USART_I2SCTRL_MASK) +/***************************************************************************//** + * @brief + * Init USART for I2S mode. + * + * @details + * This function will configure basic settings in order to operate in I2S + * mode. + * + * Special control setup not covered by this function must be done after + * using this function by direct modification of the CTRL and I2SCTRL + * registers. + * + * Notice that pins used by the USART module must be properly configured + * by the user explicitly, in order for the USART to work as intended. + * (When configuring pins, one should remember to consider the sequence of + * configuration, in order to avoid unintended pulses/glitches on output + * pins.) + * + * @param[in] usart + * Pointer to USART peripheral register block. (UART does not support this + * mode.) + * + * @param[in] init + * Pointer to initialization structure used to configure basic I2S setup. + * + * @note + * This function does not apply to all USART's. Refer to chip manuals. + * + ******************************************************************************/ +void USART_InitI2s(USART_TypeDef *usart, USART_InitI2s_TypeDef *init) +{ + USART_Enable_TypeDef enable; + + /* Make sure the module exists on the selected chip */ + EFM_ASSERT(USART_I2S_VALID(usart)); + + /* Override the enable setting. */ + enable = init->sync.enable; + init->sync.enable = usartDisable; + + /* Init USART as a sync device. */ + USART_InitSync(usart, &init->sync); + + /* Configure and enable I2CCTRL register acording to selected mode. */ + usart->I2SCTRL = ((uint32_t) init->format) | + ((uint32_t) init->justify) | + (init->delay ? USART_I2SCTRL_DELAY : 0) | + (init->dmaSplit ? USART_I2SCTRL_DMASPLIT : 0) | + (init->mono ? USART_I2SCTRL_MONO : 0) | + (USART_I2SCTRL_EN); + + if (enable != usartDisable) + { + USART_Enable(usart, enable); + } +} +#endif + + +/***************************************************************************//** + * @brief + * Initialize automatic transmissions using PRS channel as trigger + * @note + * Initialize USART with USART_Init() before setting up PRS configuration + * + * @param[in] usart Pointer to USART to configure + * @param[in] init Pointer to initialization structure + ******************************************************************************/ +void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init) +{ + uint32_t trigctrl; + + /* Clear values that will be reconfigured */ + trigctrl = usart->TRIGCTRL & ~(_USART_TRIGCTRL_RXTEN_MASK | + _USART_TRIGCTRL_TXTEN_MASK | +#if defined(USART_TRIGCTRL_AUTOTXTEN) + _USART_TRIGCTRL_AUTOTXTEN_MASK | +#endif + _USART_TRIGCTRL_TSEL_MASK); + +#if defined(USART_TRIGCTRL_AUTOTXTEN) + if (init->autoTxTriggerEnable) + { + trigctrl |= USART_TRIGCTRL_AUTOTXTEN; + } +#endif + if (init->txTriggerEnable) + { + trigctrl |= USART_TRIGCTRL_TXTEN; + } + if (init->rxTriggerEnable) + { + trigctrl |= USART_TRIGCTRL_RXTEN; + } + trigctrl |= init->prsTriggerChannel; + + /* Enable new configuration */ + usart->TRIGCTRL = trigctrl; +} + + +/***************************************************************************//** + * @brief + * Reset USART/UART to same state as after a HW reset. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + ******************************************************************************/ +void USART_Reset(USART_TypeDef *usart) +{ + /* Make sure the module exists on the selected chip */ + EFM_ASSERT( USART_REF_VALID(usart) + || USARTRF_REF_VALID(usart) + || UART_REF_VALID(usart) ); + + /* Make sure disabled first, before resetting other registers */ + usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS | + USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX | USART_CMD_CLEARRX; + usart->CTRL = _USART_CTRL_RESETVALUE; + usart->FRAME = _USART_FRAME_RESETVALUE; + usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE; + usart->CLKDIV = _USART_CLKDIV_RESETVALUE; + usart->IEN = _USART_IEN_RESETVALUE; + usart->IFC = _USART_IFC_MASK; + usart->ROUTE = _USART_ROUTE_RESETVALUE; + + if (USART_IRDA_VALID(usart)) + { + usart->IRCTRL = _USART_IRCTRL_RESETVALUE; + } + +#if defined(_USART_INPUT_RESETVALUE) + usart->INPUT = _USART_INPUT_RESETVALUE; +#endif + +#if defined(_USART_I2SCTRL_RESETVALUE) + if (USART_I2S_VALID(usart)) + { + usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE; + } +#endif +} + + +/***************************************************************************//** + * @brief + * Receive one 4-8 bit frame, (or part of 10-16 bit frame). + * + * @details + * This function is normally used to receive one frame when operating with + * frame length 4-8 bits. Please refer to @ref USART_RxExt() for reception of + * 9 bit frames. + * + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if the buffer is empty, until data is received. + * Alternatively the user can explicitly check whether data is available, and + * if data is avaliable, call @ref USART_RxDataGet() to read the RXDATA + * register directly. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @return + * Data received. + ******************************************************************************/ +uint8_t USART_Rx(USART_TypeDef *usart) +{ + while (!(usart->STATUS & USART_STATUS_RXDATAV)) + ; + + return (uint8_t) (usart->RXDATA); +} + + +/***************************************************************************//** + * @brief + * Receive two 4-8 bit frames, or one 10-16 bit frame. + * + * @details + * This function is normally used to receive one frame when operating with + * frame length 10-16 bits. Please refer to @ref USART_RxDoubleExt() for + * reception of two 9 bit frames. + * + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is empty, until data is received. + * Alternatively the user can explicitly check whether data is available, and + * if data is avaliable, call @ref USART_RxDoubleGet() to read the RXDOUBLE + * register directly. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @return + * Data received. + ******************************************************************************/ +uint16_t USART_RxDouble(USART_TypeDef *usart) +{ + while (!(usart->STATUS & USART_STATUS_RXFULL)) + ; + + return (uint16_t) (usart->RXDOUBLE); +} + + +/***************************************************************************//** + * @brief + * Receive two 4-9 bit frames, or one 10-16 bit frame with extended + * information. + * + * @details + * This function is normally used to receive one frame when operating with + * frame length 10-16 bits and additional RX status information is required. + * + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is empty, until data is received. + * Alternatively the user can explicitly check whether data is available, and + * if data is avaliable, call @ref USART_RxDoubleXGet() to read the RXDOUBLEX + * register directly. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @return + * Data received. + ******************************************************************************/ +uint32_t USART_RxDoubleExt(USART_TypeDef *usart) +{ + while (!(usart->STATUS & USART_STATUS_RXFULL)) + ; + + return usart->RXDOUBLEX; +} + + +/***************************************************************************//** + * @brief + * Receive one 4-9 bit frame, (or part of 10-16 bit frame) with extended + * information. + * + * @details + * This function is normally used to receive one frame when operating with + * frame length 4-9 bits and additional RX status information is required. + * + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is empty, until data is received. + * Alternatively the user can explicitly check whether data is available, and + * if data is avaliable, call @ref USART_RxDataXGet() to read the RXDATAX + * register directly. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @return + * Data received. + ******************************************************************************/ +uint16_t USART_RxExt(USART_TypeDef *usart) +{ + while (!(usart->STATUS & USART_STATUS_RXDATAV)) + ; + + return (uint16_t) (usart->RXDATAX); +} + + +/***************************************************************************//** + * @brief + * Perform one 8 bit frame SPI transfer. + * + * @note + * This function will stall if the transmit buffer is full. When a transmit + * buffer becomes available, data is written and the function will wait until + * the data is fully transmitted. The SPI return value is then read out and + * returned. + * + * @param[in] usart + * Pointer to USART peripheral register block. + * + * @param[in] data + * Data to transmit. + * + * @return + * Data received. + ******************************************************************************/ +uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data) +{ + while (!(usart->STATUS & USART_STATUS_TXBL)) + ; + usart->TXDATA = (uint32_t) data; + while (!(usart->STATUS & USART_STATUS_TXC)) + ; + return (uint8_t) (usart->RXDATA); +} + + +/***************************************************************************//** + * @brief + * Transmit one 4-9 bit frame. + * + * @details + * Depending on frame length configuration, 4-8 (least significant) bits from + * @p data are transmitted. If frame length is 9, 8 bits are transmitted from + * @p data and one bit as specified by CTRL register, BIT8DV field. Please + * refer to USART_TxExt() for transmitting 9 bit frame with full control of + * all 9 bits. + * + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is full, until buffer becomes available. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] data + * Data to transmit. See details above for further info. + ******************************************************************************/ +void USART_Tx(USART_TypeDef *usart, uint8_t data) +{ + /* Check that transmit buffer is empty */ + while (!(usart->STATUS & USART_STATUS_TXBL)) + ; + usart->TXDATA = (uint32_t) data; +} + + +/***************************************************************************//** + * @brief + * Transmit two 4-9 bit frames, or one 10-16 bit frame. + * + * @details + * Depending on frame length configuration, 4-8 (least significant) bits from + * each byte in @p data are transmitted. If frame length is 9, 8 bits are + * transmitted from each byte in @p data adding one bit as specified by CTRL + * register, BIT8DV field, to each byte. Please refer to USART_TxDoubleExt() + * for transmitting two 9 bit frames with full control of all 9 bits. + * + * If frame length is 10-16, 10-16 (least significant) bits from @p data + * are transmitted. + * + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is full, until buffer becomes available. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] data + * Data to transmit, the least significant byte holds the frame transmitted + * first. See details above for further info. + ******************************************************************************/ +void USART_TxDouble(USART_TypeDef *usart, uint16_t data) +{ + /* Check that transmit buffer is empty */ + while (!(usart->STATUS & USART_STATUS_TXBL)) + ; + usart->TXDOUBLE = (uint32_t) data; +} + + +/***************************************************************************//** + * @brief + * Transmit two 4-9 bit frames, or one 10-16 bit frame with extended control. + * + * @details + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is full, until buffer becomes available. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] data + * Data to transmit with extended control. Contains two 16 bit words + * concatenated. Least significant word holds frame transitted first. If frame + * length is 4-9, two frames with 4-9 least significant bits from each 16 bit + * word are transmitted. + * @par + * If frame length is 10-16 bits, 8 data bits are taken from the least + * significant 16 bit word, and the remaining bits from the other 16 bit word. + * @par + * Additional control bits are available as documented in the EFM32 reference + * manual (set to 0 if not used). For 10-16 bit frame length, these control + * bits are taken from the most significant 16 bit word. + ******************************************************************************/ +void USART_TxDoubleExt(USART_TypeDef *usart, uint32_t data) +{ + /* Check that transmit buffer is empty */ + while (!(usart->STATUS & USART_STATUS_TXBL)) + ; + usart->TXDOUBLEX = data; +} + + +/***************************************************************************//** + * @brief + * Transmit one 4-9 bit frame with extended control. + * + * @details + * Notice that possible parity/stop bits in asynchronous mode are not + * considered part of specified frame bit length. + * + * @note + * This function will stall if buffer is full, until buffer becomes available. + * + * @param[in] usart + * Pointer to USART/UART peripheral register block. + * + * @param[in] data + * Data to transmit with extended control. Least significant bits contains + * frame bits, and additional control bits are available as documented in + * the EFM32 reference manual (set to 0 if not used). + ******************************************************************************/ +void USART_TxExt(USART_TypeDef *usart, uint16_t data) +{ + /* Check that transmit buffer is empty */ + while (!(usart->STATUS & USART_STATUS_TXBL)) + ; + usart->TXDATAX = (uint32_t) data; +} + + +/** @} (end addtogroup USART) */ +/** @} (end addtogroup EM_Library) */ +#endif /* defined(USART_COUNT) && (USART_COUNT > 0) */