mirror of
https://github.com/QuantumLeaps/qpc.git
synced 2025-01-28 07:03:10 +08:00
1214 lines
40 KiB
C
1214 lines
40 KiB
C
/***************************************************************************//**
|
|
* @file em_usart.c
|
|
* @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART)
|
|
* Peripheral API
|
|
* @version 4.3.0
|
|
*******************************************************************************
|
|
* @section License
|
|
* <b>Copyright 2016 Silicon Laboratories, Inc. 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_bus.h"
|
|
#include "em_assert.h"
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup emlib
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup USART
|
|
* @brief Universal Synchronous/Asynchronous Receiver/Transmitter
|
|
* Peripheral API
|
|
* @details
|
|
* This module contains functions to control the USART peripheral of Silicon
|
|
* Labs 32-bit MCUs and SoCs. The USART handles high-speed UART, SPI bus,
|
|
* SmartCards and IrDA communication.
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
******************************* 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))
|
|
#elif (USART_COUNT == 5)
|
|
#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \
|
|
((ref) == USART2) || ((ref) == USART3) || \
|
|
((ref) == USART4))
|
|
#elif (USART_COUNT == 6)
|
|
#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \
|
|
((ref) == USART2) || ((ref) == USART3) || \
|
|
((ref) == USART4) || ((ref) == USART5))
|
|
#else
|
|
#error "Undefined number of USARTs."
|
|
#endif
|
|
|
|
#if defined(USARTRF_COUNT) && (USARTRF_COUNT > 0)
|
|
#if (USARTRF_COUNT == 1) && defined(USARTRF0)
|
|
#define USARTRF_REF_VALID(ref) ((ref) == USARTRF0)
|
|
#elif (USARTRF_COUNT == 1) && defined(USARTRF1)
|
|
#define USARTRF_REF_VALID(ref) ((ref) == USARTRF1)
|
|
#else
|
|
#define USARTRF_REF_VALID(ref) (0)
|
|
#endif
|
|
#else
|
|
#define USARTRF_REF_VALID(ref) (0)
|
|
#endif
|
|
|
|
#if defined(_EZR32_HAPPY_FAMILY)
|
|
#define USART_IRDA_VALID(ref) ((ref) == USART0)
|
|
#elif 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(_EZR32_HAPPY_FAMILY)
|
|
#define USART_I2S_VALID(ref) ((ref) == USART0)
|
|
#elif defined(_EFM32_HAPPY_FAMILY)
|
|
#define USART_I2S_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
|
|
#elif defined(_EFM32_TINY_FAMILY) || defined(_EFM32_ZERO_FAMILY) || defined(_SILICON_LABS_32B_PLATFORM_2)
|
|
#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 or 3 bits of CLKDIV are don't care, we can base our
|
|
* integer arithmetic on the below formula
|
|
*
|
|
* CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4 (3 bits dont care)
|
|
* or
|
|
* CLKDIV / 8 = (32 * fHFPERCLK)/(oversample * br) - 32 (6 bits dont care)
|
|
*
|
|
* 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. */
|
|
#if defined(_USART_CLKDIV_DIV_MASK) && (_USART_CLKDIV_DIV_MASK >= 0x7FFFF8UL)
|
|
clkdiv = 32 * refFreq + (oversample * baudrate) / 2;
|
|
clkdiv /= (oversample * baudrate);
|
|
clkdiv -= 32;
|
|
clkdiv *= 8;
|
|
#else
|
|
clkdiv = 4 * refFreq + (oversample * baudrate) / 2;
|
|
clkdiv /= (oversample * baudrate);
|
|
clkdiv -= 4;
|
|
clkdiv *= 64;
|
|
#endif
|
|
|
|
/* Verify that resulting clock divider is within limits */
|
|
EFM_ASSERT(clkdiv <= _USART_CLKDIV_DIV_MASK);
|
|
|
|
/* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */
|
|
clkdiv &= _USART_CLKDIV_DIV_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;
|
|
uint64_t divisor;
|
|
uint64_t factor;
|
|
uint64_t remainder;
|
|
uint64_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 larger than a 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 <= 0xFFFFF8 */
|
|
/* 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. However, factor * remainder can become larger than 32-bit */
|
|
/* because of the size of _USART_CLKDIV_DIV_MASK on some families. */
|
|
br = (uint32_t)(factor * quotient);
|
|
|
|
/*
|
|
* factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
|
|
* means dividend (factor * remainder) worst case is
|
|
* 128 * (3 * (256 + _USART_CLKDIV_DIV_MASK)) = 0x1_8001_7400.
|
|
*/
|
|
br += (uint32_t)((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)
|
|
{
|
|
#if defined(_USART_CLKDIV_DIV_MASK) && (_USART_CLKDIV_DIV_MASK >= 0x7FFFF8UL)
|
|
uint64_t clkdiv;
|
|
#else
|
|
uint32_t clkdiv;
|
|
#endif
|
|
|
|
/* Inhibit divide by 0 */
|
|
EFM_ASSERT(baudrate);
|
|
|
|
/*
|
|
* CLKDIV in synchronous mode is given by:
|
|
*
|
|
* CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
|
|
*/
|
|
|
|
/* HFPERCLK used to clock all USART/UART peripheral modules */
|
|
if (!refFreq)
|
|
{
|
|
refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
|
|
}
|
|
|
|
#if defined(_USART_CLKDIV_DIV_MASK) && (_USART_CLKDIV_DIV_MASK >= 0x7FFFF8UL)
|
|
/* Calculate and set CLKDIV without fractional bits */
|
|
clkdiv = 2 * baudrate;
|
|
clkdiv = (0x100ULL * (uint64_t)refFreq) / clkdiv;
|
|
|
|
/* Round up by not subtracting 256 and mask off fractional part */
|
|
clkdiv &= ~0xFF;
|
|
#else
|
|
/* 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;
|
|
#endif
|
|
|
|
/* Verify that resulting clock divider is within limits */
|
|
EFM_ASSERT(!(clkdiv & ~_USART_CLKDIV_DIV_MASK));
|
|
|
|
/* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */
|
|
clkdiv &= _USART_CLKDIV_DIV_MASK;
|
|
|
|
BUS_RegMaskedWrite(&usart->CLKDIV, _USART_CLKDIV_DIV_MASK, 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);
|
|
|
|
#if defined(_USART_TIMING_CSHOLD_MASK)
|
|
usart->TIMING = ((init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
|
|
& _USART_TIMING_CSHOLD_MASK)
|
|
| ((init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
|
|
& _USART_TIMING_CSSETUP_MASK);
|
|
if (init->autoCsEnable)
|
|
{
|
|
usart->CTRL |= USART_CTRL_AUTOCS;
|
|
}
|
|
#endif
|
|
/* 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_CTRL_AUTOTX_MASK)
|
|
usart->CTRL |= init->autoTx ? USART_CTRL_AUTOTX : 0;
|
|
#endif
|
|
|
|
#if defined(_USART_INPUT_RXPRS_MASK)
|
|
/* Configure PRS input mode. */
|
|
if (init->prsRxEnable)
|
|
{
|
|
usart->INPUT = (uint32_t)init->prsRxCh | USART_INPUT_RXPRS;
|
|
}
|
|
#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;
|
|
}
|
|
|
|
#if defined(_USART_TIMING_CSHOLD_MASK)
|
|
usart->TIMING = ((init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
|
|
& _USART_TIMING_CSHOLD_MASK)
|
|
| ((init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
|
|
& _USART_TIMING_CSSETUP_MASK);
|
|
if (init->autoCsEnable)
|
|
{
|
|
usart->CTRL |= USART_CTRL_AUTOCS;
|
|
}
|
|
#endif
|
|
|
|
usart->CMD = (uint32_t)init->enable;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Init USART 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] usart
|
|
* Pointer to USART peripheral register block.
|
|
*
|
|
* @param[in] init
|
|
* Pointer to initialization structure used to configure async IrDA setup.
|
|
*
|
|
* @note
|
|
* Not all USART instances support IrDA. See the datasheet for your device.
|
|
*
|
|
******************************************************************************/
|
|
void USARTn_InitIrDA(USART_TypeDef *usart, const USART_InitIrDA_TypeDef *init)
|
|
{
|
|
EFM_ASSERT(USART_IRDA_VALID(usart));
|
|
|
|
/* 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;
|
|
}
|
|
|
|
#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;
|
|
#if defined(_USART_ROUTEPEN_MASK) || defined(_UART_ROUTEPEN_MASK)
|
|
usart->ROUTEPEN = _USART_ROUTEPEN_RESETVALUE;
|
|
usart->ROUTELOC0 = _USART_ROUTELOC0_RESETVALUE;
|
|
usart->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE;
|
|
#else
|
|
usart->ROUTE = _USART_ROUTE_RESETVALUE;
|
|
#endif
|
|
|
|
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 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 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 emlib) */
|
|
#endif /* defined(USART_COUNT) && (USART_COUNT > 0) */
|