text: /***************************************************************************//**
   * @file
   * @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART)
   *   Peripheral API
   *******************************************************************************
   * # License
   * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
   *******************************************************************************
   *
   * SPDX-License-Identifier: Zlib
   *
   * The licensor of this software is Silicon Laboratories Inc.
   *
   * This software is provided 'as-is', without any express or implied
   * warranty. In no event will the authors be held liable for any damages
   * arising from the use of this software.
   *
   * 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. If you use this software
   *    in a product, an acknowledgment in the product documentation would be
   *    appreciated but is not required.
   * 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.
   *
   ******************************************************************************/
  
  #include "em_usart.h"
  #if defined(USART_COUNT) && (USART_COUNT > 0)
  
  #include "em_cmu.h"
  #include "em_bus.h"
  #include "em_assert.h"
  #if defined(USART_CTRLX_CTSEN)
  #include "em_gpio.h"
  #endif
  
  /*******************************************************************************
   *******************************   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 (_SILICON_LABS_32B_SERIES == 2)
    #define USART_IRDA_VALID(ref)      USART_REF_VALID(ref)
  #elif defined(_SILICON_LABS_32B_SERIES_1)
    #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100) || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
  // If GG11 or TG11
      #define USART_IRDA_VALID(ref)    (((ref) == USART0) || ((ref) == USART2))
    #elif defined(USART3)
      #define USART_IRDA_VALID(ref)    (((ref) == USART0) || ((ref) == USART1) || ((ref) == USART2) || ((ref) == USART3))
    #elif defined(USART2)
      #define USART_IRDA_VALID(ref)    (((ref) == USART0) || ((ref) == USART1) || ((ref) == USART2))
    #else
      #define USART_IRDA_VALID(ref)    (((ref) == USART0) || ((ref) == USART1))
    #endif
  #elif defined(_SILICON_LABS_32B_SERIES_0)
    #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)
    #elif defined(USARTRF0)
      #define USART_IRDA_VALID(ref)    ((ref) == USARTRF0)
    #else
      #define USART_IRDA_VALID(ref)    (0)
    #endif
  #endif
  
  #if (_SILICON_LABS_32B_SERIES == 2)
    #define USART_I2S_VALID(ref)      USART_REF_VALID(ref)
  #elif defined(_SILICON_LABS_32B_SERIES_1)
    #if defined(USART4)
      #define USART_I2S_VALID(ref)    (((ref) == USART1) || ((ref) == USART3) || ((ref) == USART4))
    #elif defined(USART3)
      #define USART_I2S_VALID(ref)    (((ref) == USART1) || ((ref) == USART3))
    #else
      #define USART_I2S_VALID(ref)    ((ref) == USART1)
    #endif
  #elif defined(_SILICON_LABS_32B_SERIES_0)
    #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)
      #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
  #endif
  
  #if (UART_COUNT == 1) && !defined(_UART_IPVERSION_MASK)
    #define UART_REF_VALID(ref)    ((ref) == UART0)
  #elif (UART_COUNT == 2) && !defined(_UART_IPVERSION_MASK)
    #define UART_REF_VALID(ref)    (((ref) == UART0) || ((ref) == UART1))
  #else
    #define UART_REF_VALID(ref)    (0)
  #endif
  
  #if defined(_USART_CLKDIV_DIVEXT_MASK)
    #define CLKDIV_MASK  (_USART_CLKDIV_DIV_MASK | _USART_CLKDIV_DIVEXT_MASK)
  #else
    #define CLKDIV_MASK  _USART_CLKDIV_DIV_MASK
  #endif
  
  /** @endcond */
  
  /*******************************************************************************
   **************************   LOCAL FUNCTIONS   ********************************
   ******************************************************************************/
  
  #if !defined(_EFM32_GECKO_FAMILY)
  /***************************************************************************//**
   * @brief
   *   Configure a PRS channel as USART Rx input
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] ch
   *   PRS channel.
   ******************************************************************************/
  static void prsRxInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
  {
  #if defined(_USART_INPUT_MASK)
    usart->INPUT = ((uint32_t)ch << _USART_INPUT_RXPRSSEL_SHIFT)
                   | USART_INPUT_RXPRS;
  #elif defined(USART_CTRLX_RXPRSEN)
    if (usart == USART0) {
      PRS->CONSUMER_USART0_RX = ch;
    }
  #if defined(USART1)
    else if (usart == USART1) {
      PRS->CONSUMER_USART1_RX = ch;
    }
  #endif
  #if defined(USART2)
    else if (usart == USART2) {
      PRS->CONSUMER_USART2_RX = ch;
    }
  #endif
    usart->CTRLX |= USART_CTRLX_RXPRSEN;
  #endif
  }
  #endif
  
  #if defined(USART_IRCTRL_IRPRSEN)
  /***************************************************************************//**
   * @brief
   *   Configure a PRS channel as USART Ir input
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] ch
   *   PRS channel.
   ******************************************************************************/
  static void prsIrInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
  {
  #if defined(_USART_IRCTRL_IRPRSSEL_SHIFT)
    usart->IRCTRL |= ((uint32_t)ch << _USART_IRCTRL_IRPRSSEL_SHIFT)
                     | USART_IRCTRL_IRPRSEN;
  #else
    (void)ch;
    usart->IRCTRL |= USART_IRCTRL_IRPRSEN;
  #endif
  }
  #endif
  
  #if defined(USART_IRCTRL_IRPRSEN) && defined(CONSUMER_USART0_IR)
  /***************************************************************************//**
   * @brief
   *   Configure a PRS channel as USART Ir input
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] ch
   *   PRS channel.
   ******************************************************************************/
  static void prsIrInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
  {
    if (usart == USART0) {
      PRS->CONSUMER_USART0_IR = ch;
    }
  #if defined(USART1)
    else if (usart == USART1) {
      PRS->CONSUMER_USART1_IR = ch;
    }
  #endif
  #if defined(USART2)
    else if (usart == USART2) {
      PRS->CONSUMER_USART2_IR = ch;
    }
  #endif
    usart->IRCTRL |= USART_IRCTRL_IRPRSEN;
  }
  #endif
  
  /***************************************************************************//**
   * @brief
   *   Configure a PRS channel as USART Trigger input
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] ch
   *   PRS channel.
   ******************************************************************************/
  static void prsTriggerInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
  {
  #if defined(_USART_IRCTRL_IRPRSSEL_MASK)
    usart->TRIGCTRL = (usart->TRIGCTRL & ~_USART_TRIGCTRL_TSEL_MASK)
                      | (ch << _USART_TRIGCTRL_TSEL_SHIFT);
  #else
    if (usart == USART0) {
      PRS->CONSUMER_USART0_TRIGGER = ch;
    }
  #if USART_COUNT > 1
    else if (usart == USART1) {
      PRS->CONSUMER_USART1_TRIGGER = ch;
    }
  #endif
  #if USART_COUNT > 2
    else if (usart == USART2) {
      PRS->CONSUMER_USART2_TRIGGER = ch;
    }
  #endif
  #endif
  }
  
  /*******************************************************************************
   **************************   GLOBAL FUNCTIONS   *******************************
   ******************************************************************************/
  
  /***************************************************************************//**
   * @addtogroup usart
   * @{
   ******************************************************************************/
  
  /***************************************************************************//**
   * @brief
   *   Configure USART/UART operating in asynchronous mode to use a given
   *   baudrate (or as close as possible to a specified baudrate).
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] refFreq
   *   USART/UART reference clock frequency in Hz. 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 the channel more
   *   vulnerable to bit faults during reception due to clock inaccuracies
   *   compared to the link partner.
   ******************************************************************************/
  void USART_BaudrateAsyncSet(USART_TypeDef *usart,
                              uint32_t refFreq,
                              uint32_t baudrate,
                              USART_OVS_TypeDef ovs)
  {
    uint32_t clkdiv;
    uint32_t oversample = 0;
  
    /* Inhibit divide by 0 */
    EFM_ASSERT(baudrate);
  
    /*
     * 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 the dividend first before dividing
     * to get as small rounding effects as possible.
     * Too harsh restrictions on maximum fHFPERCLK value should not be made.
     *
     * It is possible to factorize 256 and oversample/br. However,
     * since the last 6 or 3 bits of CLKDIV are don't care, base the
     * 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 1 GHz without overflowing a 32 bit value.
     */
  
    /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
    if (!refFreq) {
  #if defined(_SILICON_LABS_32B_SERIES_2)
      refFreq = CMU_ClockFreqGet(cmuClock_PCLK);
  #else
  #if defined(_CMU_HFPERPRESCB_MASK)
      if (usart == USART2) {
        refFreq = CMU_ClockFreqGet(cmuClock_HFPERB);
      } else {
        refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
      }
  #else
      refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
  #endif
  #endif
    }
  
    /* Map oversampling. */
    switch (ovs) {
      case usartOVS16:
        EFM_ASSERT(baudrate <= (refFreq / 16));
        oversample = 16;
        break;
  
      case usartOVS8:
        EFM_ASSERT(baudrate <= (refFreq / 8));
        oversample = 8;
        break;
  
      case usartOVS6:
        EFM_ASSERT(baudrate <= (refFreq / 6));
        oversample = 6;
        break;
  
      case usartOVS4:
        EFM_ASSERT(baudrate <= (refFreq / 4));
        oversample = 4;
        break;
  
      default:
        /* Invalid input */
        EFM_ASSERT(0);
        break;
    }
  
    if (oversample > 0U) {
      /* Calculate and set CLKDIV with fractional bits.
       * The added (oversample*baudrate)/2 in the first line is to round the
       * divisor to the nearest fractional divisor. */
    #if defined(_SILICON_LABS_32B_SERIES_0) && !defined(_EFM32_HAPPY_FAMILY)
      /* Devices with 2 fractional bits. CLKDIV[7:6] */
      clkdiv  = 4 * refFreq + (oversample * baudrate) / 2;
      clkdiv /= oversample * baudrate;
      clkdiv -= 4;
      clkdiv *= 64;
    #else
      /* Devices with 5 fractional bits. CLKDIV[7:3] */
      clkdiv  = 32 * refFreq + (oversample * baudrate) / 2;
      clkdiv /= oversample * baudrate;
      clkdiv -= 32;
      clkdiv *= 8;
    #endif
  
      /* Verify that the resulting clock divider is within limits. */
      EFM_ASSERT(clkdiv <= CLKDIV_MASK);
  
      /* Make sure that reserved bits are not written to. */
      clkdiv &= 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 the hardware configuration. It can be used
   *   to determine if a given configuration is sufficiently accurate for the
   *   application.
   *
   * @param[in] refFreq
   *   USART/UART HF peripheral frequency used.
   *
   * @param[in] clkdiv
   *   A 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 in 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;
  
    /* Out of bound clkdiv. */
    EFM_ASSERT(clkdiv <= CLKDIV_MASK);
  
    /* Mask out unused bits */
    clkdiv &= CLKDIV_MASK;
  
    /* 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, i.e., 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))
       *
       * 256 factor of the dividend is reduced with a
       * (part of) oversample part of the divisor.
       */
  
      switch (ovs) {
        case usartOVS16:
          oversample = 1;
          factor     = 256 / 16;
          break;
  
        case usartOVS8:
          oversample = 1;
          factor     = 256 / 8;
          break;
  
        case usartOVS6:
          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 the dividend first before dividing
     * to get as small rounding effects as possible. Too harsh restrictions
     * should not be made on the maximum fHFPERCLK value either.
     *
     * For division a/b,
     *
     * a = qb + r
     *
     * where q is the quotient and r is the remainder, both integers.
     *
     * The original 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.
     */
  
    /*
     * The divisor will never exceed max 32 bit value since
     * clkdiv <= _USART_CLKDIV_DIV_MASK (currently 0x1FFFC0 or 0x7FFFF8)
     * and 'oversample' has been reduced to <= 3.
     */
    divisor = (uint64_t)(oversample * (256 + clkdiv));
  
    quotient  = refFreq / divisor;
    remainder = refFreq % divisor;
  
    /* The factor <= 128 and since divisor >= 256, the below cannot exceed the maximum */
    /* 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);
  
    /*
     * The 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 the 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
   *   A pointer to the USART/UART peripheral register block.
   *
   * @return
   *   The 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/HFPERBCLK used to clock all USART/UART peripheral modules. */
  #if defined(_SILICON_LABS_32B_SERIES_2)
    freq = CMU_ClockFreqGet(cmuClock_PCLK);
  #else
  #if defined(_CMU_HFPERPRESCB_MASK)
    if (usart == USART2) {
      freq = CMU_ClockFreqGet(cmuClock_HFPERB);
    } else {
      freq = CMU_ClockFreqGet(cmuClock_HFPER);
    }
  #else
    freq = CMU_ClockFreqGet(cmuClock_HFPER);
  #endif
  #endif
    ovs  = (USART_OVS_TypeDef)(usart->CTRL & _USART_CTRL_OVS_MASK);
    return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs);
  }
  
  /***************************************************************************//**
   * @brief
   *   Configure the USART operating in synchronous mode to use a given baudrate
   *   (or as close as possible to a specified baudrate).
   *
   * @details
   *   The configuration will be set to use a baudrate <= the specified baudrate
   *   to ensure that the baudrate does not exceed the specified value.
   *
   *   The fractional clock division is suppressed, although the hardware design allows it.
   *   It could cause half clock cycles to exceed a specified limit and thus
   *   potentially violate specifications for the slave device. In some special
   *   situations, a 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
   *   A pointer to the USART peripheral register block. (Cannot be used on UART
   *   modules.)
   *
   * @param[in] refFreq
   *   A 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;
  
    /* Prevent dividing by 0. */
    EFM_ASSERT(baudrate);
  
    /*
     * CLKDIV in synchronous mode is given by:
     *
     * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
     */
  
    /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
    if (!refFreq) {
  #if defined(_SILICON_LABS_32B_SERIES_2)
      refFreq = CMU_ClockFreqGet(cmuClock_PCLK);
  #else
  #if defined(_CMU_HFPERPRESCB_MASK)
      if (usart == USART2) {
        refFreq = CMU_ClockFreqGet(cmuClock_HFPERB);
      } else {
        refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
      }
  #else
      refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
  #endif
  #endif
    }
  
    clkdiv = (refFreq - 1) / (2 * baudrate);
    clkdiv = clkdiv << 8;
  
    /* Verify that resulting clock divider is within limits. */
    EFM_ASSERT(!(clkdiv & ~CLKDIV_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 (if not enabled as part
   *   of initialization).
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] enable
   *   Select the status for the 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));
  
  #if defined(USART_EN_EN)
    usart->EN_SET = USART_EN_EN;
  #endif
  
    /* 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;
  
  #if defined(USART_EN_EN)
    if (enable == usartDisable) {
      usart->EN_CLR = USART_EN_EN;
    }
  #endif
  }
  
  /***************************************************************************//**
   * @brief
   *   Initialize USART/UART for normal asynchronous mode.
   *
   * @details
   *   This function will configure basic settings to operate in normal
   *   asynchronous mode.
   *
   *   A 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 for the USART/UART to work as intended.
   *   (When configuring pins, remember to consider the sequence of
   *   configuration to avoid unintended pulses/glitches on output
   *   pins.)
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] init
   *   A pointer to the initialization structure used to configure the 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));
  
    /* Initialize USART registers to hardware reset state. */
    USART_Reset(usart);
  
  #if defined(USART_EN_EN)
    usart->EN_SET = USART_EN_EN;
  #endif
  
  #if defined(USART_CTRL_MVDIS)
    /* Disable the majority vote if specified. */
    if (init->mvdis) {
      usart->CTRL |= USART_CTRL_MVDIS;
    }
  #endif
  
  #if !defined(_EFM32_GECKO_FAMILY)
    /* Configure the PRS input mode. */
    if (init->prsRxEnable) {
      prsRxInput(usart, init->prsRxCh);
    }
  #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 (init->autoCsEnable) {
      usart->CTRL |= USART_CTRL_AUTOCS;
    }
  #if defined(_USART_TIMING_CSHOLD_MASK)
    usart->TIMING = (((uint32_t)init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
                     & _USART_TIMING_CSHOLD_MASK)
                    | (((uint32_t)init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
                       & _USART_TIMING_CSSETUP_MASK);
  
  #endif
  
  #if defined(_USART_ROUTEPEN_RTSPEN_MASK) && defined(_USART_ROUTEPEN_CTSPEN_MASK)
    usart->ROUTEPEN &= ~(_USART_ROUTEPEN_RTSPEN_MASK | _USART_ROUTEPEN_CTSPEN_MASK);
    usart->ROUTEPEN |= init->hwFlowControl;
  
  #elif defined(USART_CTRLX_CTSEN)
    if ((init->hwFlowControl == usartHwFlowControlRts)
        || (init->hwFlowControl == usartHwFlowControlCtsAndRts)) {
  #if USART_COUNT > 1
      GPIO->USARTROUTE_SET[USART_NUM(usart)].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
  #else
      //! @todo cleanup when ADM is updated to have USART_NUM macros
      GPIO->USARTROUTE_SET[0].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
  #endif
    } else {
  #if USART_COUNT > 1
      GPIO->USARTROUTE_CLR[USART_NUM(usart)].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
  #else
      //! @todo cleanup when ADM is updated to have USART_NUM macros
      GPIO->USARTROUTE_CLR[0].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
  #endif
    }
  
    if ((init->hwFlowControl == usartHwFlowControlCts)
        || (init->hwFlowControl == usartHwFlowControlCtsAndRts)) {
      usart->CTRLX_SET = USART_CTRLX_CTSEN;
    } else {
      usart->CTRLX_CLR = USART_CTRLX_CTSEN;
    }
  #endif
  
    /* Finally, enable (as specified). */
    usart->CMD = (uint32_t)init->enable;
  }
  
  /***************************************************************************//**
   * @brief
   *   Initialize USART for synchronous mode.
   *
   * @details
   *   This function will configure basic settings to operate in
   *   synchronous mode.
   *
   *   A 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 for the USART to work as intended.
   *   (When configuring pins remember to consider the sequence of
   *   configuration to avoid unintended pulses/glitches on output
   *   pins.)
   *
   * @param[in] usart
   *   A pointer to the USART peripheral register block. (UART does not support this
   *   mode.)
   *
   * @param[in] init
   *   A pointer to the 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) );
  
    /* Initialize USART registers to hardware reset state. */
    USART_Reset(usart);
  
  #if defined(USART_EN_EN)
    usart->EN_SET = USART_EN_EN;
  #endif
  
    /* 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(_EFM32_GECKO_FAMILY)
    if (init->prsRxEnable) {
      prsRxInput(usart, init->prsRxCh);
    }
  #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 the baudrate. */
    USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate);
  
    /* Finally, enable (as specified). */
    if (init->master) {
      usart->CMD = USART_CMD_MASTEREN;
    }
  
    if (init->autoCsEnable) {
      usart->CTRL |= USART_CTRL_AUTOCS;
    }
  #if defined(_USART_TIMING_CSHOLD_MASK)
    usart->TIMING = (((uint32_t)init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
                     & _USART_TIMING_CSHOLD_MASK)
                    | (((uint32_t)init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
                       & _USART_TIMING_CSSETUP_MASK);
  #endif
  
    usart->CMD = (uint32_t)init->enable;
  }
  
  /***************************************************************************//**
   * @brief
   *   Initialize USART for asynchronous IrDA mode.
   *
   * @details
   *   This function will configure basic settings to operate in
   *   asynchronous IrDA mode.
   *
   *   A 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 for the USART/UART to work as intended.
   *   (When configuring pins, remember to consider the sequence of
   *   configuration to avoid unintended pulses/glitches on output
   *   pins.)
   *
   * @param[in] usart
   *   A pointer to the USART peripheral register block.
   *
   * @param[in] init
   *   A pointer to the initialization structure used to configure async IrDA setup.
   *
   * @note
   *   Not all USART instances support IrDA. See the data sheet for your device.
   *
   ******************************************************************************/
  void USARTn_InitIrDA(USART_TypeDef *usart, const USART_InitIrDA_TypeDef *init)
  {
    EFM_ASSERT(USART_IRDA_VALID(usart));
  
    /* Initialize USART as an async device. */
    USART_InitAsync(usart, &(init->async));
  
    /* Set IrDA modulation to RZI (return-to-zero-inverted). */
    usart->CTRL |= USART_CTRL_TXINV;
  
    /* Invert the Rx signal before the demodulator if enabled. */
    if (init->irRxInv) {
      usart->CTRL |= USART_CTRL_RXINV;
    }
  
    /* Configure IrDA. */
    usart->IRCTRL = (uint32_t)init->irPw
                    | ((init->irFilt ? 1UL : 0UL) << _USART_IRCTRL_IRFILT_SHIFT);
  
  #if defined(USART_IRCTRL_IRPRSEN)
    if (init->irPrsEn) {
      prsIrInput(usart, init->irPrsSel);
    }
  #endif
  
    /* Enable IrDA. */
    usart->IRCTRL |= USART_IRCTRL_IREN;
  }
  
  #if defined(_USART_I2SCTRL_MASK)
  /***************************************************************************//**
   * @brief
   *   Initialize USART for I2S mode.
   *
   * @details
   *   This function will configure basic settings to operate in I2S
   *   mode.
   *
   *   A 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 for the USART to work as intended.
   *   (When configuring pins, remember to consider the sequence of
   *   configuration to avoid unintended pulses/glitches on output
   *   pins.)
   *
   * @param[in] usart
   *   A pointer to the USART peripheral register block. (UART does not support this
   *   mode.)
   *
   * @param[in] init
   *   A pointer to the initialization structure used to configure the basic I2S setup.
   *
   * @note
   *   This function does not apply to all USART's. See the chip Reference Manual.
   *
   ******************************************************************************/
  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;
  
    /* Initialize USART as a sync device. */
    USART_InitSync(usart, &init->sync);
  
    /* Configure and enable I2CCTRL register according to the 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 the automatic transmissions using PRS channel as a trigger.
   * @note
   *   Initialize USART with USART_Init() before setting up the PRS configuration.
   *
   * @param[in] usart
   *   A pointer to USART to configure.
   *
   * @param[in] init
   *   A pointer to the initialization structure.
   ******************************************************************************/
  void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init)
  {
    uint32_t trigctrl;
  
    prsTriggerInput(usart, init->prsTriggerChannel);
    /* 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
                                   );
  
  #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;
    }
    usart->TRIGCTRL = trigctrl;
  }
  
  /***************************************************************************//**
   * @brief
   *   Reset USART/UART to the same state that it was in after a hardware reset.
   *
   * @param[in] usart
   *   A 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) );
  
  #if defined(USART_EN_EN)
    usart->EN_SET = USART_EN_EN;
    /* 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->CTRLX     = _USART_CTRLX_RESETVALUE;
    usart->FRAME     = _USART_FRAME_RESETVALUE;
    usart->TRIGCTRL  = _USART_TRIGCTRL_RESETVALUE;
    usart->CLKDIV    = _USART_CLKDIV_RESETVALUE;
    usart->IEN       = _USART_IEN_RESETVALUE;
    usart->IF_CLR    = _USART_IF_MASK;
    usart->TIMING    = _USART_TIMING_RESETVALUE;
  
    if (USART_IRDA_VALID(usart)) {
      usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
    }
  
    if (USART_I2S_VALID(usart)) {
      usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
    }
    usart->EN_CLR = USART_EN_EN;
  
  #else
    /* 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_TIMING_MASK)
    usart->TIMING    = _USART_TIMING_RESETVALUE;
  #endif
  #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
  #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. See @ref USART_RxExt() for reception of
   *   9 bit frames.
   *
   *   Notice that possible parity/stop bits in asynchronous mode are not
   *   considered part of a 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.
   *   If data is available, call @ref USART_RxDataGet() to read the RXDATA
   *   register directly.
   *
   * @param[in] usart
   *   A pointer to the 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. See @ref USART_RxDoubleExt() for
   *   reception of two 9 bit frames.
   *
   *   Notice that possible parity/stop bits in asynchronous mode are not
   *   considered part of a 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.
   *   If data is available, call @ref USART_RxDoubleGet() to read the RXDOUBLE
   *   register directly.
   *
   * @param[in] usart
   *   A pointer to the 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 a 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.
   *   If data is available, call @ref USART_RxDoubleXGet() to read the RXDOUBLEX
   *   register directly.
   *
   * @param[in] usart
   *   A pointer to the 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 a 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.
   *   If data is available, call @ref USART_RxDataXGet() to read the RXDATAX
   *   register directly.
   *
   * @param[in] usart
   *   A pointer to the 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
   *   data is fully transmitted. The SPI return value is then read out and
   *   returned.
   *
   * @param[in] usart
   *   A pointer to the 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 the frame length configuration, 4-8 (least significant) bits from
   *   @p data are transmitted. If the frame length is 9, 8 bits are transmitted from
   *   @p data and one bit as specified by CTRL register, BIT8DV field.
   *   See 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 a specified frame bit length.
   *
   * @note
   *   This function will stall if the buffer is full until the buffer becomes available.
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] data
   *   Data to transmit. See details above for more information.
   ******************************************************************************/
  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 the 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 the CTRL
   *   register, BIT8DV field, to each byte. See USART_TxDoubleExt()
   *   for transmitting two 9 bit frames with full control of all 9 bits.
   *
   *   If the 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 a specified frame bit length.
   *
   * @note
   *   This function will stall if the buffer is full until the buffer becomes available.
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] data
   *   Data to transmit, the least significant byte holds the frame transmitted
   *   first. See details above for more 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 a specified frame bit length.
   *
   * @note
   *   This function will stall if the buffer is full until the buffer becomes available.
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] data
   *   Data to transmit with extended control. Contains two 16 bit words
   *   concatenated. Least significant word holds the frame transmitted first. If the frame
   *   length is 4-9, two frames with 4-9 least significant bits from each 16 bit
   *   word are transmitted.
   * @par
   *   If the 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 a specified frame bit length.
   *
   * @note
   *   This function will stall if the buffer is full until the buffer becomes available.
   *
   * @param[in] usart
   *   A pointer to the USART/UART peripheral register block.
   *
   * @param[in] data
   *   Data to transmit with extended control. Least significant bit contains
   *   frame bits. 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 the transmit buffer is empty. */
    while (!(usart->STATUS & USART_STATUS_TXBL)) {
    }
    usart->TXDATAX = (uint32_t)data;
  }
  
  /** @} (end addtogroup usart) */
  #endif /* defined(USART_COUNT) && (USART_COUNT > 0) */
  