mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Revision:
144:ef7eb2e8f9f7
Parent:
52:4ce9155acc4d
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c	Tue Aug 02 14:07:36 2016 +0000
+++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c	Fri Sep 02 15:07:44 2016 +0100
@@ -1,2201 +1,2194 @@
-/***************************************************************************//**
- * @file serial_api.c
- *******************************************************************************
- * @section License
- * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
- *******************************************************************************
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
- * obligation to support this Software. Silicon Labs is providing the
- * Software "AS IS", with no express or implied warranties of any kind,
- * including, but not limited to, any implied warranties of merchantability
- * or fitness for any particular purpose or warranties against infringement
- * of any proprietary rights of a third party.
- *
- * Silicon Labs will not be liable for any consequential, incidental, or
- * special damages, or any other relief, or for any claim by any third party,
- * arising from your use of this Software.
- *
- ******************************************************************************/
-
-#include "device.h"
-#include "clocking.h"
-#if DEVICE_SERIAL
-
-#include "mbed_assert.h"
-#include "serial_api.h"
-#include "serial_api_HAL.h"
-#include <string.h>
-#include <stdbool.h>
-
-#include "pinmap.h"
-#include "pinmap_function.h"
-#include "PeripheralPins.h"
-#include "PeripheralNames.h"
-
-#include "em_usart.h"
-#include "em_leuart.h"
-#include "em_cmu.h"
-#include "em_dma.h"
-#include "dma_api_HAL.h"
-#include "dma_api.h"
-#include "sleep_api.h"
-#include "buffer.h"
-#include "sleepmodes.h"
-
-#define SERIAL_LEAST_ACTIVE_SLEEPMODE EM1
-#define SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART EM2
-
-/** Validation of LEUART register block pointer reference
- *  for assert statements. */
-#if !defined(LEUART_COUNT)
-#define LEUART_REF_VALID(ref)    (0)
-#elif (LEUART_COUNT == 1)
-#define LEUART_REF_VALID(ref)    ((ref) == LEUART0)
-#elif (LEUART_COUNT == 2)
-#define LEUART_REF_VALID(ref)    (((ref) == LEUART0) || ((ref) == LEUART1))
-#else
-#error Undefined number of low energy UARTs (LEUART).
-#endif
-
-/* Store IRQ id for each UART */
-static uint32_t serial_irq_ids[MODULES_SIZE_SERIAL] = { 0 };
-/* Interrupt handler from mbed common */
-static uart_irq_handler irq_handler;
-/* Keep track of incoming DMA IRQ's */
-static bool serial_dma_irq_fired[DMACTRL_CH_CNT] = { false };
-
-/* Serial interface on USBTX/USBRX retargets stdio */
-int stdio_uart_inited = 0;
-serial_t stdio_uart;
-
-static void uart_irq(UARTName, SerialIrq);
-static uint8_t serial_get_index(serial_t *obj);
-static void serial_enable(serial_t *obj, uint8_t enable);
-static void serial_enable_pins(serial_t *obj, uint8_t enable);
-static void serial_set_route(serial_t *obj);
-static IRQn_Type serial_get_rx_irq_index(serial_t *obj);
-static IRQn_Type serial_get_tx_irq_index(serial_t *obj);
-static CMU_Clock_TypeDef serial_get_clock(serial_t *obj);
-static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx);
-static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
-static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
-static void serial_block_sleep(serial_t *obj);
-static void serial_unblock_sleep(serial_t *obj);
-static void serial_leuart_baud(serial_t *obj, int baudrate);
-
-/* ISRs for RX and TX events */
-#ifdef UART0
-static void uart0_rx_irq() { uart_irq(UART_0, RxIrq); }
-static void uart0_tx_irq() { uart_irq(UART_0, TxIrq); USART_IntClear((USART_TypeDef*)UART_0, USART_IFC_TXC);}
-#endif
-#ifdef UART1
-static void uart1_rx_irq() { uart_irq(UART_1, RxIrq); }
-static void uart1_tx_irq() { uart_irq(UART_1, TxIrq); USART_IntClear((USART_TypeDef*)UART_1, USART_IFC_TXC);}
-#endif
-#ifdef USART0
-static void usart0_rx_irq() { uart_irq(USART_0, RxIrq); }
-static void usart0_tx_irq() { uart_irq(USART_0, TxIrq); USART_IntClear((USART_TypeDef*)USART_0, USART_IFC_TXC);}
-#endif
-#ifdef USART1
-static void usart1_rx_irq() { uart_irq(USART_1, RxIrq); }
-static void usart1_tx_irq() { uart_irq(USART_1, TxIrq); USART_IntClear((USART_TypeDef*)USART_1, USART_IFC_TXC);}
-#endif
-#ifdef USART2
-static void usart2_rx_irq() { uart_irq(USART_2, RxIrq); }
-static void usart2_tx_irq() { uart_irq(USART_2, TxIrq); USART_IntClear((USART_TypeDef*)USART_2, USART_IFC_TXC);}
-#endif
-#ifdef LEUART0
-static void leuart0_irq()
-{
-    if(LEUART_IntGetEnabled(LEUART0) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) {
-        uart_irq(LEUART_0, RxIrq);
-    }
-
-    if(LEUART_IntGetEnabled(LEUART0) & (LEUART_IF_TXC | LEUART_IF_TXBL | LEUART_IF_TXOF)) {
-        uart_irq(LEUART_0, TxIrq);
-        LEUART_IntClear(LEUART0, LEUART_IFC_TXC);
-    }
-}
-#endif
-#ifdef LEUART1
-static void leuart1_irq()
-{
-    if(LEUART_IntGetEnabled(LEUART1) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) {
-        uart_irq(LEUART_1, RxIrq);
-    }
-
-    if(LEUART_IntGetEnabled(LEUART1) & (LEUART_IF_TXC | LEUART_IF_TXBL | LEUART_IF_TXOF)) {
-        uart_irq(LEUART_1, TxIrq);
-        LEUART_IntClear(LEUART1, LEUART_IFC_TXC);
-    }
-}
-#endif
-
-/**
- * Initialize the UART using default settings, overridden by settings from serial object
- *
- * @param obj pointer to serial object
- */
-static void uart_init(serial_t *obj, uint32_t baudrate, SerialParity parity, int stop_bits)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
-
-        if (stop_bits == 2) {
-            init.stopbits = leuartStopbits2;
-        } else {
-            init.stopbits = leuartStopbits1;
-        }
-
-        switch (parity) {
-            case ParityOdd:
-            case ParityForced0:
-                init.parity = leuartOddParity;
-                break;
-            case ParityEven:
-            case ParityForced1:
-                init.parity = leuartEvenParity;
-                break;
-            default: /* ParityNone */
-                init.parity = leuartNoParity;
-                break;
-        }
-
-        init.enable = leuartDisable;
-        init.baudrate = 9600;
-        init.databits = leuartDatabits8;
-#ifdef LEUART_USING_LFXO
-        init.refFreq = LEUART_LF_REF_FREQ;
-#else
-        init.refFreq = LEUART_REF_FREQ;
-#endif
-        LEUART_Init(obj->serial.periph.leuart, &init);
-
-        if (baudrate != 9600) {
-            serial_baud(obj, baudrate);
-        }
-    } else {
-        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
-
-        if (stop_bits == 2) {
-            init.stopbits = usartStopbits2;
-        } else {
-            init.stopbits = usartStopbits1;
-        }
-        switch (parity) {
-            case ParityOdd:
-            case ParityForced0:
-                init.parity = usartOddParity;
-                break;
-            case ParityEven:
-            case ParityForced1:
-                init.parity = usartEvenParity;
-                break;
-            default: /* ParityNone */
-                init.parity = usartNoParity;
-                break;
-        }
-
-        init.enable = usartDisable;
-        init.baudrate = baudrate;
-        init.oversampling = usartOVS16;
-        init.databits = usartDatabits8;
-        init.refFreq = REFERENCE_FREQUENCY;
-
-        USART_InitAsync(obj->serial.periph.uart, &init);
-    }
-}
-/**
-* Get index of serial object, relating it to the physical peripheral.
-*
-* @param obj pointer to serial peripheral (= base address of periph)
-* @return internal index of U(S)ART peripheral
-*/
-static inline uint8_t serial_pointer_get_index(uint32_t serial_ptr)
-{
-    uint8_t index = 0;
-#ifdef UART0
-    if (serial_ptr == UART_0) return index;
-    index++;
-#endif
-#ifdef UART1
-    if (serial_ptr == UART_1) return index;
-    index++;
-#endif
-#ifdef USART0
-    if (serial_ptr == USART_0) return index;
-    index++;
-#endif
-#ifdef USART1
-    if (serial_ptr == USART_1) return index;
-    index++;
-#endif
-#ifdef USART2
-    if (serial_ptr == USART_2) return index;
-    index++;
-#endif
-#ifdef LEUART0
-    if (serial_ptr == LEUART_0) return index;
-    index++;
-#endif
-#ifdef LEUART1
-    if (serial_ptr == LEUART_1) return index;
-    index++;
-#endif
-    return 0;
-}
-
-/**
-* Get index of serial object, relating it to the physical peripheral.
-*
-* @param obj pointer to serial object (mbed object)
-* @return internal index of U(S)ART peripheral
-*/
-static inline uint8_t serial_get_index(serial_t *obj)
-{
-    return serial_pointer_get_index((uint32_t)obj->serial.periph.uart);
-}
-
-/**
-* Get index of serial object RX IRQ, relating it to the physical peripheral.
-*
-* @param obj pointer to serial object
-* @return internal NVIC RX IRQ index of U(S)ART peripheral
-*/
-static inline IRQn_Type serial_get_rx_irq_index(serial_t *obj)
-{
-    switch ((uint32_t)obj->serial.periph.uart) {
-#ifdef UART0
-        case UART_0:
-            return UART0_RX_IRQn;
-#endif
-#ifdef UART1
-        case UART_1:
-            return UART1_RX_IRQn;
-#endif
-#ifdef USART0
-        case USART_0:
-            return USART0_RX_IRQn;
-#endif
-#ifdef USART1
-        case USART_1:
-            return USART1_RX_IRQn;
-#endif
-#ifdef USART2
-        case USART_2:
-            return USART2_RX_IRQn;
-#endif
-#ifdef LEUART0
-        case LEUART_0:
-            return LEUART0_IRQn;
-#endif
-#ifdef LEUART1
-        case LEUART_1:
-            return LEUART1_IRQn;
-#endif
-        default:
-            MBED_ASSERT(0);
-    }
-    return (IRQn_Type)0;
-}
-
-/**
-* Get index of serial object TX IRQ, relating it to the physical peripheral.
-*
-* @param obj pointer to serial object
-* @return internal NVIC TX IRQ index of U(S)ART peripheral
-*/
-static inline IRQn_Type serial_get_tx_irq_index(serial_t *obj)
-{
-    switch ((uint32_t)obj->serial.periph.uart) {
-#ifdef UART0
-        case UART_0:
-            return UART0_TX_IRQn;
-#endif
-#ifdef UART1
-        case UART_1:
-            return UART1_TX_IRQn;
-#endif
-#ifdef USART0
-        case USART_0:
-            return USART0_TX_IRQn;
-#endif
-#ifdef USART1
-        case USART_1:
-            return USART1_TX_IRQn;
-#endif
-#ifdef USART2
-        case USART_2:
-            return USART2_TX_IRQn;
-#endif
-#ifdef LEUART0
-        case LEUART_0:
-            return LEUART0_IRQn;
-#endif
-#ifdef LEUART1
-        case LEUART_1:
-            return LEUART1_IRQn;
-#endif
-        default:
-            MBED_ASSERT(0);
-    }
-    return (IRQn_Type)0;
-}
-
-/**
-* Get clock tree for serial peripheral pointed to by obj.
-*
-* @param obj pointer to serial object
-* @return CMU_Clock_TypeDef for U(S)ART
-*/
-inline CMU_Clock_TypeDef serial_get_clock(serial_t *obj)
-{
-    switch ((uint32_t)obj->serial.periph.uart) {
-#ifdef UART0
-        case UART_0:
-            return cmuClock_UART0;
-#endif
-#ifdef UART1
-        case UART_1:
-            return cmuClock_UART1;
-#endif
-#ifdef USART0
-        case USART_0:
-            return cmuClock_USART0;
-#endif
-#ifdef USART1
-        case USART_1:
-            return cmuClock_USART1;
-#endif
-#ifdef USART2
-        case USART_2:
-            return cmuClock_USART2;
-#endif
-#ifdef LEUART0
-        case LEUART_0:
-            return cmuClock_LEUART0;
-#endif
-#ifdef LEUART1
-        case LEUART_1:
-            return cmuClock_LEUART1;
-#endif
-        default:
-            return cmuClock_HFPER;
-    }
-}
-
-void serial_preinit(serial_t *obj, PinName tx, PinName rx)
-{
-    /* Get UART object connected to the given pins */
-    UARTName uart_tx = (UARTName) pinmap_peripheral(tx, PinMap_UART_TX);
-    UARTName uart_rx = (UARTName) pinmap_peripheral(rx, PinMap_UART_RX);
-    /* Check that pins are connected to same UART */
-    UARTName uart = (UARTName) pinmap_merge(uart_tx, uart_rx);
-    MBED_ASSERT((int) uart != NC);
-
-    obj->serial.periph.uart = (USART_TypeDef *) uart;
-
-    /* Get location */
-    uint32_t uart_tx_loc = pin_location(tx, PinMap_UART_TX);
-    uint32_t uart_rx_loc = pin_location(rx, PinMap_UART_RX);
-
-#if defined(_SILICON_LABS_32B_PLATFORM_1)
-    /* Check that pins are used by same location for the given UART */
-    obj->serial.location = pinmap_merge(uart_tx_loc, uart_rx_loc);
-    MBED_ASSERT(obj->serial.location != (uint32_t)NC);
-#else
-    obj->serial.location_tx = uart_tx_loc;
-    obj->serial.location_rx = uart_rx_loc;
-#endif
-
-    /* Store pins in object for easy disabling in serial_free() */
-    //TODO: replace all usages with AF_USARTx_TX_PORT(location) macro to save 8 bytes from struct
-    obj->serial.rx_pin = rx;
-    obj->serial.tx_pin = tx;
-
-    /* Select interrupt */
-    switch ((uint32_t)obj->serial.periph.uart) {
-#ifdef UART0
-        case UART_0:
-            NVIC_SetVector(UART0_RX_IRQn, (uint32_t) &uart0_rx_irq);
-            NVIC_SetVector(UART0_TX_IRQn, (uint32_t) &uart0_tx_irq);
-            NVIC_SetPriority(UART0_TX_IRQn, 1);
-            break;
-#endif
-#ifdef UART1
-        case UART_1:
-            NVIC_SetVector(UART1_RX_IRQn, (uint32_t) &uart1_rx_irq);
-            NVIC_SetVector(UART1_TX_IRQn, (uint32_t) &uart1_tx_irq);
-            NVIC_SetPriority(UART1_TX_IRQn, 1);
-            break;
-#endif
-#ifdef USART0
-        case USART_0:
-            NVIC_SetVector(USART0_RX_IRQn, (uint32_t) &usart0_rx_irq);
-            NVIC_SetVector(USART0_TX_IRQn, (uint32_t) &usart0_tx_irq);
-            NVIC_SetPriority(USART0_TX_IRQn, 1);
-            break;
-#endif
-#ifdef USART1
-        case USART_1:
-            NVIC_SetVector(USART1_RX_IRQn, (uint32_t) &usart1_rx_irq);
-            NVIC_SetVector(USART1_TX_IRQn, (uint32_t) &usart1_tx_irq);
-            NVIC_SetPriority(USART1_TX_IRQn, 1);
-            break;
-#endif
-#ifdef USART2
-        case USART_2:
-            NVIC_SetVector(USART2_RX_IRQn, (uint32_t) &usart2_rx_irq);
-            NVIC_SetVector(USART2_TX_IRQn, (uint32_t) &usart2_tx_irq);
-            NVIC_SetPriority(USART2_TX_IRQn, 1);
-            break;
-#endif
-#ifdef LEUART0
-        case LEUART_0:
-            NVIC_SetVector(LEUART0_IRQn, (uint32_t) &leuart0_irq);
-            break;
-#endif
-#ifdef LEUART1
-        case LEUART_1:
-            NVIC_SetVector(LEUART1_IRQn, (uint32_t) &leuart1_irq);
-            break;
-#endif
-    }
-}
-
-static void serial_enable_pins(serial_t *obj, uint8_t enable)
-{
-    if (enable) {
-        /* Configure GPIO pins*/
-        if(obj->serial.rx_pin != NC) {
-            pin_mode(obj->serial.rx_pin, Input);
-        }
-        /* Set DOUT first to prevent glitches */
-        if(obj->serial.tx_pin != NC) {
-            GPIO_PinOutSet((GPIO_Port_TypeDef)(obj->serial.tx_pin >> 4 & 0xF), obj->serial.tx_pin & 0xF);
-            pin_mode(obj->serial.tx_pin, PushPull);
-        }
-    } else {
-        if(obj->serial.rx_pin != NC) {
-            pin_mode(obj->serial.rx_pin, Disabled);
-        }
-        if(obj->serial.tx_pin != NC) {
-            pin_mode(obj->serial.tx_pin, Disabled);
-        }
-    }
-}
-
-static void serial_set_route(serial_t *obj)
-{
-    /* Enable pins for UART at correct location */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-#ifdef _LEUART_ROUTE_LOCATION_SHIFT
-        obj->serial.periph.leuart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
-        if(obj->serial.tx_pin != (uint32_t)NC) {
-            obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_TXPEN;
-        } else {
-            obj->serial.periph.leuart->ROUTE &= ~LEUART_ROUTE_TXPEN;
-        }
-        if(obj->serial.rx_pin != (uint32_t)NC) {
-            obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_RXPEN;
-        } else {
-            obj->serial.periph.leuart->CMD    = LEUART_CMD_RXBLOCKEN;
-            obj->serial.periph.leuart->ROUTE &= ~LEUART_ROUTE_RXPEN;
-        }
-#else
-        if(obj->serial.location_tx != NC) {
-            obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT);
-            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK)) | LEUART_ROUTEPEN_TXPEN;
-        } else {
-            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK));
-        }
-        if(obj->serial.location_rx != NC) {
-            obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
-            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK)) | LEUART_ROUTEPEN_RXPEN;
-        } else {
-            obj->serial.periph.leuart->CMD       = LEUART_CMD_RXBLOCKEN;
-            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK));
-        }
-#endif
-    } else {
-#ifdef _USART_ROUTE_LOCATION_SHIFT
-        obj->serial.periph.uart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
-        if(obj->serial.tx_pin != (uint32_t)NC) {
-            obj->serial.periph.uart->ROUTE |= USART_ROUTE_TXPEN;
-        } else {
-            obj->serial.periph.uart->ROUTE &= ~USART_ROUTE_TXPEN;
-        }
-        if(obj->serial.rx_pin != (uint32_t)NC) {
-            obj->serial.periph.uart->ROUTE |= USART_ROUTE_RXPEN;
-        } else {
-            obj->serial.periph.uart->CMD    = USART_CMD_RXBLOCKEN;
-            obj->serial.periph.uart->ROUTE &= ~USART_ROUTE_RXPEN;
-        }
-#else
-        if(obj->serial.location_tx != NC) {
-            obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT);
-            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK)) | USART_ROUTEPEN_TXPEN;
-        } else {
-            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK));
-        }
-        if(obj->serial.location_rx != NC) {
-            obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
-            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK)) | USART_ROUTEPEN_RXPEN;
-        } else {
-            obj->serial.periph.uart->CMD       = USART_CMD_RXBLOCKEN;
-            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK));
-        }
-#endif
-    }
-}
-
-void serial_init(serial_t *obj, PinName tx, PinName rx)
-{
-    uint32_t baudrate;
-    uint32_t uart_for_stdio = false;
-
-    serial_preinit(obj, tx, rx);
-
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        // Set up LEUART clock tree
-#ifdef LEUART_USING_LFXO
-        //set to use LFXO
-        CMU_ClockEnable(cmuClock_CORELE, true);
-        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
-#else
-        //set to use high-speed clock
-#ifdef _SILICON_LABS_32B_PLATFORM_2
-        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);
-#else
-        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
-#endif
-#endif
-    }
-
-    CMU_ClockEnable(serial_get_clock(obj), true);
-
-    /* Limitations of board controller: CDC port only supports 115kbaud */
-    if(((tx == STDIO_UART_TX) || (rx == STDIO_UART_RX))
-       && (obj->serial.periph.uart == (USART_TypeDef*)STDIO_UART )
-      ) {
-        baudrate = 115200;
-        uart_for_stdio = true;
-    } else {
-        baudrate = 9600;
-    }
-
-    /* Configure UART for async operation */
-    uart_init(obj, baudrate, ParityNone, 1);
-
-    /* Enable pins for UART at correct location */
-    serial_set_route(obj);
-
-    /* Reset interrupts */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
-        obj->serial.periph.leuart->CTRL |= LEUART_CTRL_RXDMAWU | LEUART_CTRL_TXDMAWU;
-    } else {
-        obj->serial.periph.uart->IFC = USART_IFC_TXC;
-    }
-
-    /* If this is the UART to be used for stdio, copy it to the stdio_uart struct */
-    if(uart_for_stdio) {
-        stdio_uart_inited = 1;
-        memcpy(&stdio_uart, obj, sizeof(serial_t));
-    }
-
-    serial_enable_pins(obj, true);
-    serial_enable(obj, true);
-
-    obj->serial.dmaOptionsTX.dmaChannel = -1;
-    obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
-
-    obj->serial.dmaOptionsRX.dmaChannel = -1;
-    obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
-
-}
-
-void serial_free(serial_t *obj)
-{
-    if( LEUART_REF_VALID(obj->serial.periph.leuart) ) {
-        LEUART_Enable(obj->serial.periph.leuart, leuartDisable);
-    } else {
-        USART_Enable(obj->serial.periph.uart, usartDisable);
-    }
-    serial_enable_pins(obj, false);
-}
-
-static void serial_enable(serial_t *obj, uint8_t enable)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        if (enable) {
-            LEUART_Enable(obj->serial.periph.leuart, leuartEnable);
-        } else {
-            LEUART_Enable(obj->serial.periph.leuart, leuartDisable);
-        }
-    } else {
-        if (enable) {
-            USART_Enable(obj->serial.periph.uart, usartEnable);
-        } else {
-            USART_Enable(obj->serial.periph.uart, usartDisable);
-        }
-    }
-    serial_irq_ids[serial_get_index(obj)] = 0;
-}
-
-/**
- * Set UART baud rate
- */
-void serial_baud(serial_t *obj, int baudrate)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        serial_leuart_baud(obj, baudrate);
-    } else {
-        USART_BaudrateAsyncSet(obj->serial.periph.uart, REFERENCE_FREQUENCY, (uint32_t)baudrate, usartOVS16);
-    }
-}
-
-/**
- * Set LEUART baud rate
- * Calculate whether LF or HF clock should be used.
- */
-static void serial_leuart_baud(serial_t *obj, int baudrate)
-{
-#ifdef LEUART_USING_LFXO
-    /* check if baudrate is within allowed range */
-#if defined(_SILICON_LABS_32B_PLATFORM_2)
-    // P2 has 9 bits + 5 fractional bits in LEUART CLKDIV register
-    MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 9));
-#else
-    // P1 has 7 bits + 5 fractional bits in LEUART CLKDIV register
-    MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 7));
-#endif
-
-    if(baudrate > (LEUART_LF_REF_FREQ >> 1)){
-        // Baudrate is bigger than LFCLK/2 - we need to use the HF clock
-        uint8_t divisor = 1;
-
-#if defined(_SILICON_LABS_32B_PLATFORM_2)
-        /* Check if baudrate is within allowed range: (HFCLK/4096, HFCLK/2] */
-        MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 12)));
-
-        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);
-
-        if(baudrate > (LEUART_HF_REF_FREQ >> 9)){
-            divisor = 1;
-        }else if(baudrate > (LEUART_HF_REF_FREQ >> 10)){
-            divisor = 2;
-        }else if(baudrate > (LEUART_HF_REF_FREQ >> 11)){
-            divisor = 4;
-        }else{
-            divisor = 8;
-        }
-#else // P1
-        /* Check if baudrate is within allowed range */
-        MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 10)));
-
-        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
-
-        if(baudrate > (LEUART_HF_REF_FREQ >> 7)){
-            divisor = 1;
-        }else if(baudrate > (LEUART_HF_REF_FREQ >> 8)){
-            divisor = 2;
-        }else if(baudrate > (LEUART_HF_REF_FREQ >> 9)){
-            divisor = 4;
-        }else{
-            divisor = 8;
-        }
-#endif
-        CMU_ClockDivSet(serial_get_clock(obj), divisor);
-        LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_HF_REF_FREQ/divisor, (uint32_t)baudrate);
-    }else{
-        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
-        CMU_ClockDivSet(serial_get_clock(obj), 1);
-        LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_LF_REF_FREQ, (uint32_t)baudrate);
-    }
-#else
-    /* check if baudrate is within allowed range */
-    MBED_ASSERT((baudrate > (LEUART_REF_FREQ >> 10)) && (baudrate <= (LEUART_REF_FREQ >> 1)));
-    uint8_t divisor = 1;
-    if(baudrate > (LEUART_REF_FREQ >> 7)){
-        divisor = 1;
-    }else if(baudrate > (LEUART_REF_FREQ >> 8)){
-        divisor = 2;
-    }else if(baudrate > (LEUART_REF_FREQ >> 9)){
-        divisor = 4;
-    }else{
-        divisor = 8;
-    }
-    CMU_ClockDivSet(serial_get_clock(obj), divisor);
-    LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_REF_FREQ/divisor, (uint32_t)baudrate);
-#endif
-}
-
-/**
- * Set UART format by re-initializing the peripheral.
- */
-void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        /* Save the serial state */
-        uint8_t     was_enabled = LEUART_StatusGet(obj->serial.periph.leuart) & (LEUART_STATUS_TXENS | LEUART_STATUS_RXENS);
-        uint32_t    enabled_interrupts = obj->serial.periph.leuart->IEN;
-
-        LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
-
-        /* We support 8 data bits ONLY on LEUART*/
-        MBED_ASSERT(data_bits == 8);
-
-        /* Re-init the UART */
-        init.enable = (was_enabled == 0 ? leuartDisable : leuartEnable);
-        init.baudrate = LEUART_BaudrateGet(obj->serial.periph.leuart);
-        if (stop_bits == 2) {
-            init.stopbits = leuartStopbits2;
-        } else {
-            init.stopbits = leuartStopbits1;
-        }
-        switch (parity) {
-            case ParityOdd:
-            case ParityForced0:
-                init.parity = leuartOddParity;
-                break;
-            case ParityEven:
-            case ParityForced1:
-                init.parity = leuartEvenParity;
-                break;
-            default: /* ParityNone */
-                init.parity = leuartNoParity;
-                break;
-        }
-
-        LEUART_Init(obj->serial.periph.leuart, &init);
-
-        /* Re-enable pins for UART at correct location */
-        serial_set_route(obj);
-
-        /* Re-enable interrupts */
-        if(was_enabled != 0) {
-            obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
-            obj->serial.periph.leuart->IEN = enabled_interrupts;
-        }
-    } else {
-        /* Save the serial state */
-        uint8_t     was_enabled = USART_StatusGet(obj->serial.periph.uart) & (USART_STATUS_TXENS | USART_STATUS_RXENS);
-        uint32_t    enabled_interrupts = obj->serial.periph.uart->IEN;
-
-
-        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
-
-        /* We support 4 to 8 data bits */
-        MBED_ASSERT(data_bits >= 4 && data_bits <= 8);
-
-        /* Re-init the UART */
-        init.enable = (was_enabled == 0 ? usartDisable : usartEnable);
-        init.baudrate = USART_BaudrateGet(obj->serial.periph.uart);
-        init.oversampling = usartOVS16;
-        init.databits = (USART_Databits_TypeDef)((data_bits - 3) << _USART_FRAME_DATABITS_SHIFT);
-        if (stop_bits == 2) {
-            init.stopbits = usartStopbits2;
-        } else {
-            init.stopbits = usartStopbits1;
-        }
-        switch (parity) {
-            case ParityOdd:
-            case ParityForced0:
-                init.parity = usartOddParity;
-                break;
-            case ParityEven:
-            case ParityForced1:
-                init.parity = usartEvenParity;
-                break;
-            default: /* ParityNone */
-                init.parity = usartNoParity;
-                break;
-        }
-
-        USART_InitAsync(obj->serial.periph.uart, &init);
-
-        /* Re-enable pins for UART at correct location */
-        serial_set_route(obj);
-
-        /* Re-enable interrupts */
-        if(was_enabled != 0) {
-            obj->serial.periph.uart->IFC = USART_IFC_TXC;
-            obj->serial.periph.uart->IEN = enabled_interrupts;
-        }
-    }
-}
-
-/******************************************************************************
- *                               INTERRUPTS                                   *
- ******************************************************************************/
-uint8_t serial_tx_ready(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL) ? true : false;
-    } else {
-        return (obj->serial.periph.uart->STATUS & USART_STATUS_TXBL) ? true : false;
-    }
-}
-
-uint8_t serial_rx_ready(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (obj->serial.periph.leuart->STATUS & LEUART_STATUS_RXDATAV) ? true : false;
-    } else {
-        return (obj->serial.periph.uart->STATUS & USART_STATUS_RXDATAV) ? true : false;
-    }
-}
-
-void serial_write_asynch(serial_t *obj, int data)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        obj->serial.periph.leuart->TXDATA = (uint32_t)data;
-    } else {
-        obj->serial.periph.uart->TXDATA = (uint32_t)data;
-    }
-}
-
-int serial_read_asynch(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (int)obj->serial.periph.leuart->RXDATA;
-    } else {
-        return (int)obj->serial.periph.uart->RXDATA;
-    }
-}
-
-uint8_t serial_tx_int_flag(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (obj->serial.periph.leuart->IF & LEUART_IF_TXBL) ? true : false;
-    } else {
-        return (obj->serial.periph.uart->IF & USART_IF_TXBL) ? true : false;
-    }
-}
-
-uint8_t serial_rx_int_flag(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (obj->serial.periph.leuart->IF & LEUART_IF_RXDATAV) ? true : false;
-    } else {
-        return (obj->serial.periph.uart->IF & USART_IF_RXDATAV) ? true : false;
-    }
-}
-
-void serial_read_asynch_complete(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        obj->serial.periph.leuart->IFC |= LEUART_IFC_RXOF; // in case it got full
-    } else {
-        obj->serial.periph.uart->IFC |= USART_IFC_RXFULL; // in case it got full
-    }
-}
-
-void serial_write_asynch_complete(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        obj->serial.periph.leuart->IFC |= LEUART_IFC_TXC;
-    } else {
-        obj->serial.periph.uart->IFC |= USART_IFC_TXC;
-    }
-}
-
-/** Enable and set the interrupt handler for write (TX)
- *
- * @param obj     The serial object
- * @param address The address of TX handler
- * @param enable  Set to non-zero to enable or zero to disable
- */
-void serial_write_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable)
-{
-    NVIC_SetVector(serial_get_tx_irq_index(obj), address);
-    serial_irq_set(obj, (SerialIrq)1, enable);
-}
-
-/** Enable and set the interrupt handler for read (RX)
- *
- * @param obj     The serial object
- * @param address The address of RX handler
- * @param enable  Set to non-zero to enable or zero to disable
- */
-void serial_read_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable)
-{
-    NVIC_SetVector(serial_get_rx_irq_index(obj), address);
-    serial_irq_set(obj, (SerialIrq)0, enable);
-}
-
-uint8_t serial_interrupt_enabled(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (obj->serial.periph.leuart->IEN & (LEUART_IEN_RXDATAV | LEUART_IEN_TXBL)) ? true : false;
-    } else {
-        return (obj->serial.periph.uart->IEN & (USART_IEN_RXDATAV | USART_IEN_TXBL)) ? true : false;
-    }
-}
-
-/**
- * Set handler for all serial interrupts (is probably SerialBase::_handler())
- * and store IRQ ID to be returned to the handler upon interrupt. ID is
- * probably a pointer to the calling Serial object.
- */
-void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
-{
-    irq_handler = handler;
-    serial_irq_ids[serial_get_index(obj)] = id;
-}
-
-/**
- * Generic ISR for all UARTs, both TX and RX
- */
-static void uart_irq(UARTName name, SerialIrq irq)
-{
-    uint8_t index = serial_pointer_get_index((uint32_t)name);
-    if (serial_irq_ids[index] != 0) {
-        /* Pass interrupt on to mbed common handler */
-        irq_handler(serial_irq_ids[index], irq);
-        /* Clearing interrupt not necessary */
-    }
-}
-
-/**
- * Set ISR for a given UART and interrupt event (TX or RX)
- */
-void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        /* Enable or disable interrupt */
-        if (enable) {
-            if (irq == RxIrq) { /* RX */
-                obj->serial.periph.leuart->IEN |= LEUART_IEN_RXDATAV;
-                NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj));
-                NVIC_EnableIRQ(serial_get_rx_irq_index(obj));
-            } else { /* TX */
-                obj->serial.periph.leuart->IEN |= LEUART_IEN_TXC;
-                NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj));
-                NVIC_SetPriority(serial_get_tx_irq_index(obj), 1);
-                NVIC_EnableIRQ(serial_get_tx_irq_index(obj));
-            }
-        } else {
-            if (irq == RxIrq) { /* RX */
-                obj->serial.periph.leuart->IEN &= ~LEUART_IEN_RXDATAV;
-                NVIC_DisableIRQ(serial_get_rx_irq_index(obj));
-            } else { /* TX */
-                obj->serial.periph.leuart->IEN &= ~LEUART_IEN_TXC;
-                NVIC_DisableIRQ(serial_get_tx_irq_index(obj));
-            }
-        }
-    } else {
-        /* Enable or disable interrupt */
-        if (enable) {
-            if (irq == RxIrq) { /* RX */
-                obj->serial.periph.uart->IEN |= USART_IEN_RXDATAV;
-                NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj));
-                NVIC_EnableIRQ(serial_get_rx_irq_index(obj));
-            } else { /* TX */
-                obj->serial.periph.uart->IEN |= USART_IEN_TXC;
-                NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj));
-                NVIC_SetPriority(serial_get_tx_irq_index(obj), 1);
-                NVIC_EnableIRQ(serial_get_tx_irq_index(obj));
-            }
-        } else {
-            if (irq == RxIrq) { /* RX */
-                obj->serial.periph.uart->IEN &= ~USART_IEN_RXDATAV;
-                NVIC_DisableIRQ(serial_get_rx_irq_index(obj));
-            } else { /* TX */
-                obj->serial.periph.uart->IEN &= ~USART_IEN_TXC;
-                NVIC_DisableIRQ(serial_get_tx_irq_index(obj));
-            }
-        }
-    }
-}
-
-/******************************************************************************
- *                               READ/WRITE                                   *
- ******************************************************************************/
-
-/**
- *  Get one char from serial link
- */
-int serial_getc(serial_t *obj)
-{
-    /* Emlib USART_Rx blocks until data is available, so we don't need to use
-     * serial_readable(). Use USART_RxDataGet() to read register directly. */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return LEUART_Rx(obj->serial.periph.leuart);
-    } else {
-        return USART_Rx(obj->serial.periph.uart);
-    }
-}
-
-/*
- * Send one char over serial link
- */
-void serial_putc(serial_t *obj, int c)
-{
-    /* Emlib USART_Tx blocks until buffer is writable (non-full), so we don't
-     * need to use serial_writable(). */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        LEUART_Tx(obj->serial.periph.leuart, (uint8_t)(c));
-        while (!(obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXC));
-    } else {
-        USART_Tx(obj->serial.periph.uart, (uint8_t)(c));
-        while (!(obj->serial.periph.uart->STATUS & USART_STATUS_TXC));
-    }
-}
-
-/**
- * Check if data is available in RX data vector
- */
-int serial_readable(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return obj->serial.periph.leuart->STATUS & LEUART_STATUS_RXDATAV;
-    } else {
-        return obj->serial.periph.uart->STATUS & USART_STATUS_RXDATAV;
-    }
-}
-
-/**
- * Check if TX buffer is empty
- */
-int serial_writable(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL;
-    } else {
-        return obj->serial.periph.uart->STATUS & USART_STATUS_TXBL;
-    }
-}
-
-/**
- * Clear UART interrupts
- */
-void serial_clear(serial_t *obj)
-{
-    /* Interrupts automatically clear when condition is not met anymore */
-}
-
-void serial_break_set(serial_t *obj)
-{
-    /* Send transmission break */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        obj->serial.periph.leuart->TXDATAX = LEUART_TXDATAX_TXBREAK;
-    } else {
-        obj->serial.periph.uart->TXDATAX = USART_TXDATAX_TXBREAK;
-    }
-}
-
-void serial_break_clear(serial_t *obj)
-{
-    /* No need to clear break, it is automatically cleared after one frame.
-     * From the reference manual:
-     *
-     * By setting TXBREAK, the output will be held low during the stop-bit
-     * period to generate a framing error. A receiver that supports break
-     * detection detects this state, allowing it to be used e.g. for framing
-     * of larger data packets. The line is driven high before the next frame
-     * is transmitted so the next start condition can be identified correctly
-     * by the recipient. Continuous breaks lasting longer than a USART frame
-     * are thus not supported by the USART. GPIO can be used for this.
-     */
-}
-
-void serial_pinout_tx(PinName tx)
-{
-    /* 0x10 sets DOUT high. Prevents false start. */
-    pin_mode(tx, PushPull | 0x10);
-}
-
-/************************************************************************************
- *          DMA helper functions                                                    *
- ************************************************************************************/
-/******************************************
-* static void serial_dmaTransferComplete(uint channel, bool primary, void* user)
-*
-* Callback function which gets called upon DMA transfer completion
-* the user-defined pointer is pointing to the CPP-land thunk
-******************************************/
-static void serial_dmaTransferComplete(unsigned int channel, bool primary, void *user)
-{
-    /* Store information about which channel triggered because CPP doesn't take arguments */
-    serial_dma_irq_fired[channel] = true;
-
-    /* User pointer should be a thunk to CPP land */
-    if (user != NULL) {
-        ((DMACallback)user)();
-    }
-}
-
-#ifndef LDMA_PRESENT
-
-/******************************************
-* static void serial_setupDmaChannel(serial_t *obj, bool tx_nrx)
-*
-* Sets up the DMA configuration block for the assigned channel
-* tx_nrx: true if configuring TX, false if configuring RX.
-******************************************/
-static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx)
-{
-    DMA_CfgChannel_TypeDef  channelConfig;
-
-    if(tx_nrx) {
-        //setup TX channel
-        channelConfig.highPri = false;
-        channelConfig.enableInt = true;
-        channelConfig.cb = &(obj->serial.dmaOptionsTX.dmaCallback);
-
-        switch((uint32_t)(obj->serial.periph.uart)) {
-#ifdef UART0
-            case UART_0:
-                channelConfig.select = DMAREQ_UART0_TXBL;
-                break;
-#endif
-#ifdef UART1
-            case UART_1:
-                channelConfig.select = DMAREQ_UART1_TXBL;
-                break;
-#endif
-#ifdef USART0
-            case USART_0:
-                channelConfig.select = DMAREQ_USART0_TXBL;
-                break;
-#endif
-#ifdef USART1
-            case USART_1:
-                channelConfig.select = DMAREQ_USART1_TXBL;
-                break;
-#endif
-#ifdef USART2
-            case USART_2:
-                channelConfig.select = DMAREQ_USART2_TXBL;
-                break;
-#endif
-#ifdef LEUART0
-            case LEUART_0:
-                channelConfig.select = DMAREQ_LEUART0_TXBL;
-                break;
-#endif
-#ifdef LEUART1
-            case LEUART_1:
-                channelConfig.select = DMAREQ_LEUART1_TXBL;
-                break;
-#endif
-        }
-
-        DMA_CfgChannel(obj->serial.dmaOptionsTX.dmaChannel, &channelConfig);
-    } else {
-        //setup RX channel
-        channelConfig.highPri = true;
-        channelConfig.enableInt = true;
-        channelConfig.cb = &(obj->serial.dmaOptionsRX.dmaCallback);
-
-        switch((uint32_t)(obj->serial.periph.uart)) {
-#ifdef UART0
-            case UART_0:
-                channelConfig.select = DMAREQ_UART0_RXDATAV;
-                break;
-#endif
-#ifdef UART1
-            case UART_1:
-                channelConfig.select = DMAREQ_UART1_RXDATAV;
-                break;
-#endif
-#ifdef USART0
-            case USART_0:
-                channelConfig.select = DMAREQ_USART0_RXDATAV;
-                break;
-#endif
-#ifdef USART1
-            case USART_1:
-                channelConfig.select = DMAREQ_USART1_RXDATAV;
-                break;
-#endif
-#ifdef USART2
-            case USART_2:
-                channelConfig.select = DMAREQ_USART2_RXDATAV;
-                break;
-#endif
-#ifdef LEUART0
-            case LEUART_0:
-                channelConfig.select = DMAREQ_LEUART0_RXDATAV;
-                break;
-#endif
-#ifdef LEUART1
-            case LEUART_1:
-                channelConfig.select = DMAREQ_LEUART1_RXDATAV;
-                break;
-#endif
-        }
-
-        DMA_CfgChannel(obj->serial.dmaOptionsRX.dmaChannel, &channelConfig);
-    }
-}
-
-#endif /* LDMA_PRESENT */
-
-/******************************************
-* static void serial_dmaTrySetState(DMA_OPTIONS_t *obj, DMAUsage requestedState)
-*
-* Tries to set the passed DMA state to the requested state.
-*
-* requested state possibilities:
-*   * NEVER:
-*       if the previous state was always, will deallocate the channel
-*   * OPPORTUNISTIC:
-*       If the previous state was always, will reuse that channel but free upon next completion.
-*       If not, will try to acquire a channel.
-*       When allocated, state changes to DMA_USAGE_TEMPORARY_ALLOCATED.
-*   * ALWAYS:
-*       Will try to allocate a channel and keep it.
-*       If succesfully allocated, state changes to DMA_USAGE_ALLOCATED.
-******************************************/
-static void serial_dmaTrySetState(DMA_OPTIONS_t *obj, DMAUsage requestedState, serial_t *serialPtr, bool tx_nrx)
-{
-    DMAUsage currentState = obj->dmaUsageState;
-    int tempDMAChannel = -1;
-
-    if ((requestedState == DMA_USAGE_ALWAYS) && (currentState != DMA_USAGE_ALLOCATED)) {
-        /* Try to allocate channel */
-        tempDMAChannel = dma_channel_allocate(DMA_CAP_NONE);
-        if(tempDMAChannel >= 0) {
-            obj->dmaChannel = tempDMAChannel;
-            obj->dmaUsageState = DMA_USAGE_ALLOCATED;
-            dma_init();
-            serial_dmaSetupChannel(serialPtr, tx_nrx);
-        }
-    } else if (requestedState == DMA_USAGE_OPPORTUNISTIC) {
-        if (currentState == DMA_USAGE_ALLOCATED) {
-            /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
-            obj->dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
-        } else {
-            /* Try to allocate channel */
-            tempDMAChannel = dma_channel_allocate(DMA_CAP_NONE);
-            if(tempDMAChannel >= 0) {
-                obj->dmaChannel = tempDMAChannel;
-                obj->dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
-                dma_init();
-                serial_dmaSetupChannel(serialPtr, tx_nrx);
-            }
-        }
-    } else if (requestedState == DMA_USAGE_NEVER) {
-        /* If channel is allocated, get rid of it */
-        dma_channel_free(obj->dmaChannel);
-        obj->dmaChannel = -1;
-        obj->dmaUsageState = DMA_USAGE_NEVER;
-    }
-}
-
-#ifndef LDMA_PRESENT
-
-static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length, bool tx_nrx)
-{
-    DMA_CfgDescr_TypeDef channelConfig;
-
-    if(tx_nrx) {
-        // Set DMA callback
-        obj->serial.dmaOptionsTX.dmaCallback.cbFunc = serial_dmaTransferComplete;
-        obj->serial.dmaOptionsTX.dmaCallback.userPtr = NULL;
-
-        // Set up configuration structure
-        channelConfig.dstInc = dmaDataIncNone;
-        channelConfig.srcInc = dmaDataInc1;
-        channelConfig.size = dmaDataSize1;
-        channelConfig.arbRate = dmaArbitrate1;
-        channelConfig.hprot = 0;
-
-        // Clear TXC
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC);
-        } else {
-            USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
-        }
-
-        // Set callback and enable TXC. This will fire once the
-        // serial transfer finishes
-        NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)cb);
-        serial_irq_set(obj, TxIrq, true);
-
-        DMA_CfgDescr(obj->serial.dmaOptionsTX.dmaChannel, true, &channelConfig);
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            // Activate TX and clear TX buffer (note that clear must be done
-            // separately and before TXEN or DMA will die on some platforms)
-            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX;
-            obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN;
-            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-
-            // Kick off TX DMA
-            DMA_ActivateBasic(obj->serial.dmaOptionsTX.dmaChannel, true, false, (void*) &(obj->serial.periph.leuart->TXDATA), buffer, length - 1);
-        } else {
-            // Activate TX amd clear TX buffer
-            obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
-
-            // Kick off TX DMA
-            DMA_ActivateBasic(obj->serial.dmaOptionsTX.dmaChannel, true, false, (void*) &(obj->serial.periph.uart->TXDATA), buffer, length - 1);
-        }
-
-
-    } else {
-        // Set DMA callback
-        obj->serial.dmaOptionsRX.dmaCallback.cbFunc = serial_dmaTransferComplete;
-        obj->serial.dmaOptionsRX.dmaCallback.userPtr = cb;
-
-        // Set up configuration structure
-        channelConfig.dstInc = dmaDataInc1;
-        channelConfig.srcInc = dmaDataIncNone;
-        channelConfig.size = dmaDataSize1;
-        channelConfig.arbRate = dmaArbitrate1;
-        channelConfig.hprot = 0;
-
-        DMA_CfgDescr(obj->serial.dmaOptionsRX.dmaChannel, true, &channelConfig);
-
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            // Activate RX and clear RX buffer
-            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX;
-            obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN;
-            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-
-            // Kick off RX DMA
-            DMA_ActivateBasic(obj->serial.dmaOptionsRX.dmaChannel, true, false, buffer, (void*) &(obj->serial.periph.leuart->RXDATA), length - 1);
-        } else {
-            // Activate RX and clear RX buffer
-            obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
-
-            // Kick off RX DMA
-            DMA_ActivateBasic(obj->serial.dmaOptionsRX.dmaChannel, true, false, buffer, (void*) &(obj->serial.periph.uart->RXDATA), length - 1);
-        }
-    }
-}
-
-#endif
-
-
-#ifdef LDMA_PRESENT
-
-static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx)
-{
-}
-
-static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length, bool tx_nrx)
-{
-    LDMA_PeripheralSignal_t dma_periph;
-
-    obj->serial.dmaOptionsRX.dmaCallback.userPtr = cb;
-
-    if( tx_nrx ) {
-        volatile void *target_addr;
-
-        // Clear TXC
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC);
-        } else {
-            USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
-        }
-
-        switch((uint32_t)(obj->serial.periph.uart)) {
-#ifdef USART0
-            case USART_0:
-                dma_periph = ldmaPeripheralSignal_USART0_TXBL;
-                target_addr = &USART0->TXDATA;
-                obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
-                break;
-#endif
-#ifdef USART1
-            case USART_1:
-                dma_periph = ldmaPeripheralSignal_USART1_TXBL;
-                target_addr = &USART1->TXDATA;
-                obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
-                break;
-#endif
-#ifdef LEUART0
-            case LEUART_0:
-                dma_periph = ldmaPeripheralSignal_LEUART0_TXBL;
-                target_addr = &LEUART0->TXDATA;
-                obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX;
-                obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN;
-                while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-                break;
-#endif
-            default:
-                MBED_ASSERT(0);
-                while(1);
-                break;
-        }
-
-        // Set callback and enable TXC. This will fire once the
-        // serial transfer finishes
-        NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)cb);
-        serial_irq_set(obj, TxIrq, true);
-
-        // Start DMA transfer
-        LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
-        LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(buffer, target_addr, length);
-        LDMAx_StartTransfer(obj->serial.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete, NULL);
-
-    } else {
-        volatile const void *source_addr;
-
-        switch((uint32_t)(obj->serial.periph.uart)) {
-#ifdef USART0
-            case USART_0:
-                dma_periph = ldmaPeripheralSignal_USART0_RXDATAV;
-                source_addr = &USART0->RXDATA;
-                obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
-                break;
-#endif
-#ifdef USART1
-            case USART_1:
-                dma_periph = ldmaPeripheralSignal_USART1_RXDATAV;
-                source_addr = &USART1->RXDATA;
-                obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
-                break;
-#endif
-#ifdef LEUART0
-            case LEUART_0:
-                dma_periph = ldmaPeripheralSignal_LEUART0_RXDATAV;
-                source_addr = &LEUART0->RXDATA;
-                obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX;
-                obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN;
-                while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-                break;
-#endif
-            default:
-                MBED_ASSERT(0);
-                while(1);
-                break;
-        }
-
-        LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
-        LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(source_addr, buffer, length);
-        LDMAx_StartTransfer(obj->serial.dmaOptionsRX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete, cb);
-    }
-}
-
-#endif /* LDMA_PRESENT */
-
-/************************************************************************************
- *          ASYNCHRONOUS HAL                                                        *
- ************************************************************************************/
-
-#if DEVICE_SERIAL_ASYNCH
-
-/************************************
- * HELPER FUNCTIONS                 *
- ***********************************/
-
-/** Configure TX events
- *
- * @param obj    The serial object
- * @param event  The logical OR of the TX events to configure
- * @param enable Set to non-zero to enable events, or zero to disable them
- */
-void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable)
-{
-    // Shouldn't have to enable TX interrupt here, just need to keep track of the requested events.
-    if(enable) obj->serial.events |= event;
-    else obj->serial.events &= ~event;
-}
-
-/**
- * @param obj    The serial object.
- * @param event  The logical OR of the RX events to configure
- * @param enable Set to non-zero to enable events, or zero to disable them
- */
-void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable)
-{
-    if(enable) {
-        obj->serial.events |= event;
-    } else {
-        obj->serial.events &= ~event;
-    }
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        if(event & SERIAL_EVENT_RX_FRAMING_ERROR) {
-            //FERR interrupt source
-            if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_FERR;
-            else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_FERR;
-        }
-        if(event & SERIAL_EVENT_RX_PARITY_ERROR) {
-            //PERR interrupt source
-            if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_PERR;
-            else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_PERR;
-        }
-        if(event & SERIAL_EVENT_RX_OVERFLOW) {
-            //RXOF interrupt source
-            if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_RXOF;
-            else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_RXOF;
-        }
-    } else {
-        if(event & SERIAL_EVENT_RX_FRAMING_ERROR) {
-            //FERR interrupt source
-            if(enable) obj->serial.periph.uart->IEN |= USART_IEN_FERR;
-            else obj->serial.periph.uart->IEN &= ~USART_IEN_FERR;
-        }
-        if(event & SERIAL_EVENT_RX_PARITY_ERROR) {
-            //PERR interrupt source
-            if(enable) obj->serial.periph.uart->IEN |= USART_IEN_PERR;
-            else obj->serial.periph.uart->IEN &= ~USART_IEN_PERR;
-        }
-        if(event & SERIAL_EVENT_RX_OVERFLOW) {
-            //RXOF interrupt source
-            if(enable) obj->serial.periph.uart->IEN |= USART_IEN_RXOF;
-            else obj->serial.periph.uart->IEN &= ~USART_IEN_RXOF;
-        }
-    }
-}
-
-/** Configure the TX buffer for an asynchronous write serial transaction
- *
- * @param obj       The serial object.
- * @param tx        The buffer for sending.
- * @param tx_length The number of words to transmit.
- */
-void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width)
-{
-    // We only support byte buffers for now
-    MBED_ASSERT(width == 8);
-
-    if(serial_tx_active(obj)) return;
-
-    obj->tx_buff.buffer = tx;
-    obj->tx_buff.length = tx_length;
-    obj->tx_buff.pos = 0;
-
-    return;
-}
-
-/** Configure the TX buffer for an asynchronous read serial transaction
- *
- * @param obj       The serial object.
- * @param rx        The buffer for receiving.
- * @param rx_length The number of words to read.
- */
-void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width)
-{
-    // We only support byte buffers for now
-    MBED_ASSERT(width == 8);
-
-    if(serial_rx_active(obj)) return;
-
-    obj->rx_buff.buffer = rx;
-    obj->rx_buff.length = rx_length;
-    obj->rx_buff.pos = 0;
-
-    return;
-}
-
-/************************************
- * TRANSFER FUNCTIONS               *
- ***********************************/
-
-/** Begin asynchronous TX transfer. The used buffer is specified in the serial object,
- *  tx_buff
- *
- * @param obj  The serial object
- * @param cb   The function to call when an event occurs
- * @param hint A suggestion for how to use DMA with this transfer
- * @return Returns number of data transfered, or 0 otherwise
- */
-int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
-{
-   // Check that a buffer has indeed been set up
-    MBED_ASSERT(tx != (void*)0);
-    if(tx_length == 0) return 0;
-
-    // Set up buffer
-    serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width);
-
-    // Set up events
-    serial_tx_enable_event(obj, SERIAL_EVENT_TX_ALL, false);
-    serial_tx_enable_event(obj, event, true);
-
-    // Set up sleepmode
-    serial_block_sleep(obj);
-
-    // Determine DMA strategy
-    serial_dmaTrySetState(&(obj->serial.dmaOptionsTX), hint, obj, true);
-
-    // If DMA, kick off DMA transfer
-    if(obj->serial.dmaOptionsTX.dmaChannel >= 0) {
-        serial_dmaActivate(obj, (void*)handler, obj->tx_buff.buffer, obj->tx_buff.length, true);
-    }
-    // Else, activate interrupt. TXBL will take care of buffer filling through ISR.
-    else {
-        // Store callback
-        NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj));
-        NVIC_DisableIRQ(serial_get_tx_irq_index(obj));
-        NVIC_SetPriority(serial_get_tx_irq_index(obj), 1);
-        NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)handler);
-        NVIC_EnableIRQ(serial_get_tx_irq_index(obj));
-
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            // Activate TX and clear TX buffer
-            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX;
-            obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN;
-            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-
-            // Enable interrupt
-            LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_TXBL);
-        } else {
-            // Activate TX and clear TX buffer
-            obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
-
-            // Enable interrupt
-            USART_IntEnable(obj->serial.periph.uart, USART_IEN_TXBL);
-        }
-    }
-
-    return 0;
-}
-
-/** Begin asynchronous RX transfer (enable interrupt for data collecting)
- *  The used buffer is specified in the serial object - rx_buff
- *
- * @param obj  The serial object
- * @param cb   The function to call when an event occurs
- * @param hint A suggestion for how to use DMA with this transfer
- */
-void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
-{
-    // Check that a buffer has indeed been set up
-    MBED_ASSERT(rx != (void*)0);
-    if(rx_length == 0) return;
-
-    // Set up buffer
-    serial_rx_buffer_set(obj,(void*) rx, rx_length, rx_width);
-
-    //disable character match if no character is specified
-    if(char_match == SERIAL_RESERVED_CHAR_MATCH){
-        event &= ~SERIAL_EVENT_RX_CHARACTER_MATCH;
-    }
-
-    /*clear all set interrupts*/
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR | LEUART_IFC_FERR | LEUART_IFC_RXOF);
-    }else{
-        USART_IntClear(obj->serial.periph.uart,  USART_IFC_PERR | USART_IFC_FERR | USART_IFC_RXOF);
-    }
-
-    // Set up events
-    serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, false);
-    serial_rx_enable_event(obj, event, true);
-    obj->char_match = char_match;
-
-    // Set up sleepmode
-    serial_block_sleep(obj);
-
-    // Determine DMA strategy
-    // If character match is enabled, we can't use DMA, sadly. We could when using LEUART though, but that support is not in here yet.
-    // TODO: add DMA support for character matching with leuart
-    if(!(event & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
-        serial_dmaTrySetState(&(obj->serial.dmaOptionsRX), hint, obj, false);
-    }else{
-        serial_dmaTrySetState(&(obj->serial.dmaOptionsRX), DMA_USAGE_NEVER, obj, false);
-    }
-
-    // If DMA, kick off DMA
-    if(obj->serial.dmaOptionsRX.dmaChannel >= 0) {
-        serial_dmaActivate(obj, (void*)handler, obj->rx_buff.buffer, obj->rx_buff.length, false);
-    }
-    // Else, activate interrupt. RXDATAV is responsible for incoming data notification.
-    else {
-        // Store callback
-        NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj));
-        NVIC_SetVector(serial_get_rx_irq_index(obj), (uint32_t)handler);
-        NVIC_EnableIRQ(serial_get_rx_irq_index(obj));
-
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            // Activate RX and clear RX buffer
-            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX;
-            obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN;
-            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-
-            // Enable interrupt
-            LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_RXDATAV);
-        } else {
-            // Activate RX and clear RX buffer
-            obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
-
-            // Clear RXFULL
-            USART_IntClear(obj->serial.periph.uart, USART_IFC_RXFULL);
-
-            // Enable interrupt
-            USART_IntEnable(obj->serial.periph.uart, USART_IEN_RXDATAV);
-        }
-    }
-
-    return;
-}
-
-/** Attempts to determine if the serial peripheral is already in use for TX
- *
- * @param obj The serial object
- * @return Non-zero if the TX transaction is ongoing, 0 otherwise
- */
-uint8_t serial_tx_active(serial_t *obj)
-{
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        return (obj->serial.periph.leuart->IEN & (LEUART_IEN_TXBL|LEUART_IEN_TXC)) ? true : false;
-    } else {
-        return (obj->serial.periph.uart->IEN & (USART_IEN_TXBL|USART_IEN_TXC)) ? true : false;
-    }
-}
-
-/** Attempts to determine if the serial peripheral is already in use for RX
- *
- * @param obj The serial object
- * @return Non-zero if the RX transaction is ongoing, 0 otherwise
- */
-uint8_t serial_rx_active(serial_t *obj)
-{
-    switch(obj->serial.dmaOptionsRX.dmaUsageState) {
-        case DMA_USAGE_TEMPORARY_ALLOCATED:
-            /* Temporary allocation always means its active, as this state gets cleared afterwards */
-            return 1;
-        case DMA_USAGE_ALLOCATED:
-            /* Check whether the allocated DMA channel is active by checking the DMA transfer */
-#ifndef LDMA_PRESENT
-            return DMA_ChannelEnabled(obj->serial.dmaOptionsRX.dmaChannel);
-#else
-            // LDMA_TransferDone does not work since the CHDONE bits get cleared,
-            // so just check if the channel is enabled
-            return LDMA->CHEN & (1 << obj->serial.dmaOptionsRX.dmaChannel);
-#endif
-        default:
-            /* Check whether interrupt for serial TX is enabled */
-            if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-                return (obj->serial.periph.leuart->IEN & (LEUART_IEN_RXDATAV)) ? true : false;
-            } else {
-                return (obj->serial.periph.uart->IEN & (USART_IEN_RXDATAV)) ? true : false;
-            }
-    }
-}
-
-/** The asynchronous TX handler. Writes to the TX FIFO and checks for events.
- *  If any TX event has occured, the TX abort function is called.
- *
- * @param obj The serial object
- * @return Returns event flags if a TX transfer termination condition was met or 0 otherwise
- */
-int serial_tx_irq_handler_asynch(serial_t *obj)
-{
-    /* This interrupt handler is called from USART irq */
-    uint8_t *buf = obj->tx_buff.buffer;
-
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        if(obj->serial.periph.leuart->IEN & LEUART_IEN_TXBL){
-            /* There is still data to send */
-            while((LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_TXBL) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
-                while (obj->serial.periph.leuart->SYNCBUSY);
-                LEUART_Tx(obj->serial.periph.leuart, buf[obj->tx_buff.pos]);
-                obj->tx_buff.pos++;
-            }
-            if(obj->tx_buff.pos >= obj->tx_buff.length){
-                /* Last byte has been put in TX, set up TXC interrupt */
-                LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXBL);
-                LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_TXC);
-                while (obj->serial.periph.leuart->SYNCBUSY);
-            }
-        }else if (obj->serial.periph.leuart->IF & LEUART_IF_TXC){
-            /* Last byte has been successfully transmitted. Stop the procedure */
-            serial_tx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
-        }
-    } else {
-        if(obj->serial.periph.uart->IEN & USART_IEN_TXBL){
-            /* There is still data to send */
-            while((USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_TXBL) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
-                USART_Tx(obj->serial.periph.uart, buf[obj->tx_buff.pos]);
-                obj->tx_buff.pos++;
-            }
-            if(obj->tx_buff.pos >= obj->tx_buff.length){
-                /* Last byte has been put in TX, set up TXC interrupt */
-                USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXBL);
-                USART_IntEnable(obj->serial.periph.uart, USART_IEN_TXC);
-            }
-        } else if (obj->serial.periph.uart->IF & USART_IF_TXC) {
-            /* Last byte has been successfully transmitted. Stop the procedure */
-            serial_tx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
-        }
-    }
-    return 0;
-}
-
-/** The asynchronous RX handler. Reads from the RX FIFOF and checks for events.
- *  If any RX event has occured, the RX abort function is called.
- *
- * @param obj The serial object
- * @return Returns event flags if a RX transfer termination condition was met or 0 otherwise
- */
-int serial_rx_irq_handler_asynch(serial_t *obj)
-{
-    int event = 0;
-
-    /* This interrupt handler is called from USART irq */
-    uint8_t *buf = (uint8_t*)obj->rx_buff.buffer;
-
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        /* Determine the source of the interrupt */
-        if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_PERR) {
-            /* Parity error has occurred, and we are notifying. */
-            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR);
-            serial_rx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_RX_PARITY_ERROR;
-        }
-
-        if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_FERR) {
-            /* Framing error has occurred, and we are notifying */
-            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_FERR);
-            serial_rx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_RX_FRAMING_ERROR;
-        }
-
-        if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_RXOF) {
-            /* RX buffer overflow has occurred, and we are notifying */
-            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_RXOF);
-            serial_rx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_RX_OVERFLOW;
-        }
-
-        if((LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_RXDATAV) || (LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_RXDATAV)) {
-            /* Valid data in buffer. Determine course of action: continue receiving or interrupt */
-            if(obj->rx_buff.pos >= (obj->rx_buff.length - 1)) {
-                /* Last char, transfer complete. Switch off interrupt and return event. */
-                buf[obj->rx_buff.pos] = LEUART_RxDataGet(obj->serial.periph.leuart);
-
-                event |= SERIAL_EVENT_RX_COMPLETE;
-
-                if((buf[obj->rx_buff.pos] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
-
-                serial_rx_abort_asynch_intern(obj, 1);
-                return event & obj->serial.events;
-            } else {
-                /* There's still space in the receive buffer */
-                while((LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_RXDATAV) && (obj->rx_buff.pos <= (obj->rx_buff.length - 1))) {
-                    bool aborting = false;
-                    buf[obj->rx_buff.pos] = LEUART_RxDataGet(obj->serial.periph.leuart);
-                    obj->rx_buff.pos++;
-
-                    /* Check for character match event */
-                    if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
-                        aborting = true;
-                        event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
-                    }
-
-                    /* Check for final char event */
-                    if(obj->rx_buff.pos >= (obj->rx_buff.length)) {
-                        aborting = true;
-                        event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
-                    }
-
-                    if(aborting) {
-                        serial_rx_abort_asynch_intern(obj, 1);
-                        return event & obj->serial.events;
-                    }
-                }
-            }
-        }
-    } else {
-        /* Determine the source of the interrupt */
-        if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_PERR) {
-            /* Parity error has occurred, and we are notifying. */
-            USART_IntClear(obj->serial.periph.uart, USART_IFC_PERR);
-            serial_rx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_RX_PARITY_ERROR;
-        }
-
-        if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_FERR) {
-            /* Framing error has occurred, and we are notifying */
-            USART_IntClear(obj->serial.periph.uart, USART_IFC_FERR);
-            serial_rx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_RX_FRAMING_ERROR;
-        }
-
-        if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_RXOF) {
-            /* RX buffer overflow has occurred, and we are notifying */
-            USART_IntClear(obj->serial.periph.uart, USART_IFC_RXOF);
-            serial_rx_abort_asynch_intern(obj, 1);
-            return SERIAL_EVENT_RX_OVERFLOW;
-        }
-
-        if((USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_RXDATAV) || (USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_RXFULL)) {
-            /* Valid data in buffer. Determine course of action: continue receiving or interrupt */
-            if(obj->rx_buff.pos >= (obj->rx_buff.length - 1)) {
-                /* Last char, transfer complete. Switch off interrupt and return event. */
-                buf[obj->rx_buff.pos] = USART_RxDataGet(obj->serial.periph.uart);
-
-                event |= SERIAL_EVENT_RX_COMPLETE;
-
-                if((buf[obj->rx_buff.pos] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
-
-                serial_rx_abort_asynch_intern(obj, 1);
-                return event & obj->serial.events;
-            } else {
-                /* There's still space in the receive buffer */
-                while(((USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_RXDATAV) || (USART_StatusGet(obj->serial.periph.uart) & USART_IF_RXFULL)) && (obj->rx_buff.pos <= (obj->rx_buff.length - 1))) {
-                    bool aborting = false;
-                    buf[obj->rx_buff.pos] = USART_RxDataGet(obj->serial.periph.uart);
-                    obj->rx_buff.pos++;
-
-                    /* Check for character match event */
-                    if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
-                        aborting = true;
-                        event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
-                    }
-
-                    /* Check for final char event */
-                    if(obj->rx_buff.pos >= (obj->rx_buff.length)) {
-                        aborting = true;
-                        event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
-                    }
-
-                    if(aborting) {
-                        serial_rx_abort_asynch_intern(obj, 1);
-                        return event & obj->serial.events;
-                    }
-                }
-            }
-        }
-    }
-
-    /* All events should have generated a return, if no return has happened, no event has been caught */
-    return 0;
-}
-
-/** Unified IRQ handler. Determines the appropriate handler to execute and returns the flags.
- *
- * WARNING: this code should be stateless, as re-entrancy is very possible in interrupt-based mode.
- */
-int serial_irq_handler_asynch(serial_t *obj)
-{
-    uint32_t txc_int;
-
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        txc_int = LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_TXC;
-    } else {
-        txc_int = USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_TXC;
-    }
-
-    /* First, check if we're running in DMA mode */
-    if( (obj->serial.dmaOptionsRX.dmaChannel != -1) &&
-        serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel]) {
-        /* Clean up */
-        serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel] = false;
-        serial_rx_abort_asynch_intern(obj, 1);
-
-        /* Notify CPP land of RX completion */
-        return SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
-    } else if (txc_int && (obj->serial.dmaOptionsTX.dmaChannel != -1) &&
-               serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel]) {
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            /* Clean up */
-            serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false;
-            serial_tx_abort_asynch_intern(obj, 1);
-            /* Notify CPP land of completion */
-            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
-        }else{
-            /* Clean up */
-            serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false;
-            serial_tx_abort_asynch_intern(obj, 1);
-            /* Notify CPP land of completion */
-            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
-        }
-    } else {
-        /* Check the NVIC to see which interrupt we're running from
-         * Also make sure to prioritize RX */
-        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-            //Different method of checking tx vs rx for LEUART
-            if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) {
-                return serial_rx_irq_handler_asynch(obj);
-            } else if(LEUART_StatusGet(obj->serial.periph.leuart) & (LEUART_STATUS_TXBL | LEUART_STATUS_TXC)) {
-                return serial_tx_irq_handler_asynch(obj);
-            }
-        } else {
-            if(USART_IntGetEnabled(obj->serial.periph.uart) & (USART_IF_RXDATAV | USART_IF_RXOF | USART_IF_PERR | USART_IF_FERR)) {
-                return serial_rx_irq_handler_asynch(obj);
-            } else if(USART_StatusGet(obj->serial.periph.uart) & (USART_STATUS_TXBL | USART_STATUS_TXC)){
-                return serial_tx_irq_handler_asynch(obj);
-            }
-        }
-    }
-
-    // All should be done now
-    return 0;
-}
-
-/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and
- *  flush TX hardware buffer if TX FIFO is used
- *
- * @param obj The serial object
- */
-void serial_tx_abort_asynch(serial_t *obj)
-{
-    serial_tx_abort_asynch_intern(obj, 0);
-}
-
-static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
-{
-    // Transmitter should be disabled here but there are multiple issues
-    // making that quite difficult.
-    //
-    // - Disabling the transmitter when using DMA on platforms prior to
-    //   Pearl can cause the UART to leave the line low, generating a break
-    //   condition until the next transmission begins.
-    //
-    // - On (at least) Pearl, once TXC interrupt has fired it will take some time
-    //   (some tens of microsec) for TXC to be set in STATUS. If we turn off
-    //   the transmitter before this, bad things will happen.
-    //
-    // - On (at least) Pearl, when using TX DMA it is possible for the USART
-    //   status to be: TXENS TXBL TXIDLE = 1, TXBUFCNT = 0, but TXC = 0.
-    //
-    // All in all, the logic was so fragile it's best to leave it out.
-
-    /* Clean up */
-    switch(obj->serial.dmaOptionsTX.dmaUsageState) {
-        case DMA_USAGE_ALLOCATED:
-            /* stop DMA transfer */
-#ifndef LDMA_PRESENT
-            DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false);
-#else
-            LDMA_StopTransfer(obj->serial.dmaOptionsTX.dmaChannel);
-#endif
-            break;
-        case DMA_USAGE_TEMPORARY_ALLOCATED:
-            /* stop DMA transfer and release channel */
-#ifndef LDMA_PRESENT
-            DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false);
-#else
-            LDMA_StopTransfer(obj->serial.dmaOptionsTX.dmaChannel);
-#endif
-            dma_channel_free(obj->serial.dmaOptionsTX.dmaChannel);
-            obj->serial.dmaOptionsTX.dmaChannel = -1;
-            obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
-            break;
-        default:
-            break;
-    }
-
-    /* stop interrupting */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXBL);
-        LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXC);
-        LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC);
-    } else {
-        USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXBL);
-        USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXC);
-        USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
-    }
-
-    /* Say that we can stop using this emode */
-    if(unblock_sleep)
-        serial_unblock_sleep(obj);
-}
-
-
-static void serial_unblock_sleep(serial_t *obj)
-{
-    if( obj->serial.sleep_blocked > 0 ) {
-#ifdef LEUART_USING_LFXO
-        if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
-            unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
-        }else{
-            unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
-        }
-#else
-        unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
-#endif
-        obj->serial.sleep_blocked--;
-    }
-}
-
-static void serial_block_sleep(serial_t *obj)
-{
-    obj->serial.sleep_blocked++;
-#ifdef LEUART_USING_LFXO
-    if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
-        blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
-    }else{
-        blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
-    }
-#else
-    blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
-#endif
-}
-
-/** Abort the ongoing RX transaction It disables the enabled interrupt for RX and
- *  flush RX hardware buffer if RX FIFO is used
- *
- * @param obj The serial object
- */
-void serial_rx_abort_asynch(serial_t *obj)
-{
-    serial_rx_abort_asynch_intern(obj, 0);
-}
-
-static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
-{
-    /* Stop receiver */
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        obj->serial.periph.leuart->CMD = LEUART_CMD_RXDIS;
-        while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
-    } else {
-        obj->serial.periph.uart->CMD = USART_CMD_RXDIS;
-    }
-
-    /* Clean up */
-    switch(obj->serial.dmaOptionsRX.dmaUsageState) {
-        case DMA_USAGE_ALLOCATED:
-            /* stop DMA transfer */
-#ifndef LDMA_PRESENT
-            DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false);
-#else
-            LDMA_StopTransfer(obj->serial.dmaOptionsRX.dmaChannel);
-#endif
-            break;
-        case DMA_USAGE_TEMPORARY_ALLOCATED:
-            /* stop DMA transfer and release channel */
-#ifndef LDMA_PRESENT
-            DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false);
-#else
-            LDMA_StopTransfer(obj->serial.dmaOptionsRX.dmaChannel);
-#endif
-            dma_channel_free(obj->serial.dmaOptionsRX.dmaChannel);
-            obj->serial.dmaOptionsRX.dmaChannel = -1;
-            obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
-            break;
-        default:
-            /* stop interrupting */
-            if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-                LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_RXDATAV | LEUART_IEN_PERR | LEUART_IEN_FERR | LEUART_IEN_RXOF);
-            } else {
-                USART_IntDisable(obj->serial.periph.uart, USART_IEN_RXDATAV | USART_IEN_PERR | USART_IEN_FERR | USART_IEN_RXOF);
-            }
-            break;
-    }
-
-    /*clear all set interrupts*/
-    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
-        LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR | LEUART_IFC_FERR | LEUART_IFC_RXOF);
-    }else{
-        USART_IntClear(obj->serial.periph.uart,  USART_IFC_PERR | USART_IFC_FERR | USART_IFC_RXOF);
-    }
-
-    /* Say that we can stop using this emode */
-    if( unblock_sleep )
-        serial_unblock_sleep(obj);
-}
-
-#endif //DEVICE_SERIAL_ASYNCH
-#endif //DEVICE_SERIAL
+/***************************************************************************//**
+ * @file serial_api.c
+ *******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "device.h"
+#include "clocking.h"
+#if DEVICE_SERIAL
+
+#include "mbed_assert.h"
+#include "serial_api.h"
+#include "serial_api_HAL.h"
+#include <string.h>
+#include <stdbool.h>
+
+#include "pinmap.h"
+#include "pinmap_function.h"
+#include "PeripheralPins.h"
+#include "PeripheralNames.h"
+
+#include "em_usart.h"
+#include "em_leuart.h"
+#include "em_cmu.h"
+#include "em_dma.h"
+#include "dma_api_HAL.h"
+#include "dma_api.h"
+#include "sleep_api.h"
+#include "buffer.h"
+#include "sleepmodes.h"
+
+#define SERIAL_LEAST_ACTIVE_SLEEPMODE EM1
+#define SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART EM2
+
+/** Validation of LEUART register block pointer reference
+ *  for assert statements. */
+#if !defined(LEUART_COUNT)
+#define LEUART_REF_VALID(ref)    (0)
+#elif (LEUART_COUNT == 1)
+#define LEUART_REF_VALID(ref)    ((ref) == LEUART0)
+#elif (LEUART_COUNT == 2)
+#define LEUART_REF_VALID(ref)    (((ref) == LEUART0) || ((ref) == LEUART1))
+#else
+#error Undefined number of low energy UARTs (LEUART).
+#endif
+
+/* Store IRQ id for each UART */
+static uint32_t serial_irq_ids[MODULES_SIZE_SERIAL] = { 0 };
+/* Interrupt handler from mbed common */
+static uart_irq_handler irq_handler;
+/* Keep track of incoming DMA IRQ's */
+static bool serial_dma_irq_fired[DMACTRL_CH_CNT] = { false };
+
+/* Serial interface on USBTX/USBRX retargets stdio */
+int stdio_uart_inited = 0;
+serial_t stdio_uart;
+
+static void uart_irq(UARTName, SerialIrq);
+static uint8_t serial_get_index(serial_t *obj);
+static void serial_enable(serial_t *obj, uint8_t enable);
+static void serial_enable_pins(serial_t *obj, uint8_t enable);
+static void serial_set_route(serial_t *obj);
+static IRQn_Type serial_get_rx_irq_index(serial_t *obj);
+static IRQn_Type serial_get_tx_irq_index(serial_t *obj);
+static CMU_Clock_TypeDef serial_get_clock(serial_t *obj);
+static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx);
+static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
+static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
+static void serial_block_sleep(serial_t *obj);
+static void serial_unblock_sleep(serial_t *obj);
+static void serial_leuart_baud(serial_t *obj, int baudrate);
+
+/* ISRs for RX and TX events */
+#ifdef UART0
+static void uart0_rx_irq() { uart_irq(UART_0, RxIrq); }
+static void uart0_tx_irq() { uart_irq(UART_0, TxIrq); USART_IntClear((USART_TypeDef*)UART_0, USART_IFC_TXC);}
+#endif
+#ifdef UART1
+static void uart1_rx_irq() { uart_irq(UART_1, RxIrq); }
+static void uart1_tx_irq() { uart_irq(UART_1, TxIrq); USART_IntClear((USART_TypeDef*)UART_1, USART_IFC_TXC);}
+#endif
+#ifdef USART0
+static void usart0_rx_irq() { uart_irq(USART_0, RxIrq); }
+static void usart0_tx_irq() { uart_irq(USART_0, TxIrq); USART_IntClear((USART_TypeDef*)USART_0, USART_IFC_TXC);}
+#endif
+#ifdef USART1
+static void usart1_rx_irq() { uart_irq(USART_1, RxIrq); }
+static void usart1_tx_irq() { uart_irq(USART_1, TxIrq); USART_IntClear((USART_TypeDef*)USART_1, USART_IFC_TXC);}
+#endif
+#ifdef USART2
+static void usart2_rx_irq() { uart_irq(USART_2, RxIrq); }
+static void usart2_tx_irq() { uart_irq(USART_2, TxIrq); USART_IntClear((USART_TypeDef*)USART_2, USART_IFC_TXC);}
+#endif
+#ifdef LEUART0
+static void leuart0_irq()
+{
+    if(LEUART_IntGetEnabled(LEUART0) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) {
+        uart_irq(LEUART_0, RxIrq);
+    }
+
+    if(LEUART_IntGetEnabled(LEUART0) & (LEUART_IF_TXC | LEUART_IF_TXBL | LEUART_IF_TXOF)) {
+        uart_irq(LEUART_0, TxIrq);
+        LEUART_IntClear(LEUART0, LEUART_IFC_TXC);
+    }
+}
+#endif
+#ifdef LEUART1
+static void leuart1_irq()
+{
+    if(LEUART_IntGetEnabled(LEUART1) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) {
+        uart_irq(LEUART_1, RxIrq);
+    }
+
+    if(LEUART_IntGetEnabled(LEUART1) & (LEUART_IF_TXC | LEUART_IF_TXBL | LEUART_IF_TXOF)) {
+        uart_irq(LEUART_1, TxIrq);
+        LEUART_IntClear(LEUART1, LEUART_IFC_TXC);
+    }
+}
+#endif
+
+/**
+ * Initialize the UART using default settings, overridden by settings from serial object
+ *
+ * @param obj pointer to serial object
+ */
+static void uart_init(serial_t *obj, uint32_t baudrate, SerialParity parity, int stop_bits)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
+
+        if (stop_bits == 2) {
+            init.stopbits = leuartStopbits2;
+        } else {
+            init.stopbits = leuartStopbits1;
+        }
+
+        switch (parity) {
+            case ParityOdd:
+            case ParityForced0:
+                init.parity = leuartOddParity;
+                break;
+            case ParityEven:
+            case ParityForced1:
+                init.parity = leuartEvenParity;
+                break;
+            default: /* ParityNone */
+                init.parity = leuartNoParity;
+                break;
+        }
+
+        init.enable = leuartDisable;
+        init.baudrate = 9600;
+        init.databits = leuartDatabits8;
+#ifdef LEUART_USING_LFXO
+        init.refFreq = LEUART_LF_REF_FREQ;
+#else
+        init.refFreq = LEUART_REF_FREQ;
+#endif
+        LEUART_Init(obj->serial.periph.leuart, &init);
+
+        if (baudrate != 9600) {
+            serial_baud(obj, baudrate);
+        }
+    } else {
+        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
+
+        if (stop_bits == 2) {
+            init.stopbits = usartStopbits2;
+        } else {
+            init.stopbits = usartStopbits1;
+        }
+        switch (parity) {
+            case ParityOdd:
+            case ParityForced0:
+                init.parity = usartOddParity;
+                break;
+            case ParityEven:
+            case ParityForced1:
+                init.parity = usartEvenParity;
+                break;
+            default: /* ParityNone */
+                init.parity = usartNoParity;
+                break;
+        }
+
+        init.enable = usartDisable;
+        init.baudrate = baudrate;
+        init.oversampling = usartOVS16;
+        init.databits = usartDatabits8;
+        init.refFreq = REFERENCE_FREQUENCY;
+
+        USART_InitAsync(obj->serial.periph.uart, &init);
+    }
+}
+/**
+* Get index of serial object, relating it to the physical peripheral.
+*
+* @param obj pointer to serial peripheral (= base address of periph)
+* @return internal index of U(S)ART peripheral
+*/
+static inline uint8_t serial_pointer_get_index(uint32_t serial_ptr)
+{
+    uint8_t index = 0;
+#ifdef UART0
+    if (serial_ptr == UART_0) return index;
+    index++;
+#endif
+#ifdef UART1
+    if (serial_ptr == UART_1) return index;
+    index++;
+#endif
+#ifdef USART0
+    if (serial_ptr == USART_0) return index;
+    index++;
+#endif
+#ifdef USART1
+    if (serial_ptr == USART_1) return index;
+    index++;
+#endif
+#ifdef USART2
+    if (serial_ptr == USART_2) return index;
+    index++;
+#endif
+#ifdef LEUART0
+    if (serial_ptr == LEUART_0) return index;
+    index++;
+#endif
+#ifdef LEUART1
+    if (serial_ptr == LEUART_1) return index;
+    index++;
+#endif
+    return 0;
+}
+
+/**
+* Get index of serial object, relating it to the physical peripheral.
+*
+* @param obj pointer to serial object (mbed object)
+* @return internal index of U(S)ART peripheral
+*/
+static inline uint8_t serial_get_index(serial_t *obj)
+{
+    return serial_pointer_get_index((uint32_t)obj->serial.periph.uart);
+}
+
+/**
+* Get index of serial object RX IRQ, relating it to the physical peripheral.
+*
+* @param obj pointer to serial object
+* @return internal NVIC RX IRQ index of U(S)ART peripheral
+*/
+static inline IRQn_Type serial_get_rx_irq_index(serial_t *obj)
+{
+    switch ((uint32_t)obj->serial.periph.uart) {
+#ifdef UART0
+        case UART_0:
+            return UART0_RX_IRQn;
+#endif
+#ifdef UART1
+        case UART_1:
+            return UART1_RX_IRQn;
+#endif
+#ifdef USART0
+        case USART_0:
+            return USART0_RX_IRQn;
+#endif
+#ifdef USART1
+        case USART_1:
+            return USART1_RX_IRQn;
+#endif
+#ifdef USART2
+        case USART_2:
+            return USART2_RX_IRQn;
+#endif
+#ifdef LEUART0
+        case LEUART_0:
+            return LEUART0_IRQn;
+#endif
+#ifdef LEUART1
+        case LEUART_1:
+            return LEUART1_IRQn;
+#endif
+        default:
+            MBED_ASSERT(0);
+    }
+    return (IRQn_Type)0;
+}
+
+/**
+* Get index of serial object TX IRQ, relating it to the physical peripheral.
+*
+* @param obj pointer to serial object
+* @return internal NVIC TX IRQ index of U(S)ART peripheral
+*/
+static inline IRQn_Type serial_get_tx_irq_index(serial_t *obj)
+{
+    switch ((uint32_t)obj->serial.periph.uart) {
+#ifdef UART0
+        case UART_0:
+            return UART0_TX_IRQn;
+#endif
+#ifdef UART1
+        case UART_1:
+            return UART1_TX_IRQn;
+#endif
+#ifdef USART0
+        case USART_0:
+            return USART0_TX_IRQn;
+#endif
+#ifdef USART1
+        case USART_1:
+            return USART1_TX_IRQn;
+#endif
+#ifdef USART2
+        case USART_2:
+            return USART2_TX_IRQn;
+#endif
+#ifdef LEUART0
+        case LEUART_0:
+            return LEUART0_IRQn;
+#endif
+#ifdef LEUART1
+        case LEUART_1:
+            return LEUART1_IRQn;
+#endif
+        default:
+            MBED_ASSERT(0);
+    }
+    return (IRQn_Type)0;
+}
+
+/**
+* Get clock tree for serial peripheral pointed to by obj.
+*
+* @param obj pointer to serial object
+* @return CMU_Clock_TypeDef for U(S)ART
+*/
+inline CMU_Clock_TypeDef serial_get_clock(serial_t *obj)
+{
+    switch ((uint32_t)obj->serial.periph.uart) {
+#ifdef UART0
+        case UART_0:
+            return cmuClock_UART0;
+#endif
+#ifdef UART1
+        case UART_1:
+            return cmuClock_UART1;
+#endif
+#ifdef USART0
+        case USART_0:
+            return cmuClock_USART0;
+#endif
+#ifdef USART1
+        case USART_1:
+            return cmuClock_USART1;
+#endif
+#ifdef USART2
+        case USART_2:
+            return cmuClock_USART2;
+#endif
+#ifdef LEUART0
+        case LEUART_0:
+            return cmuClock_LEUART0;
+#endif
+#ifdef LEUART1
+        case LEUART_1:
+            return cmuClock_LEUART1;
+#endif
+        default:
+            return cmuClock_HFPER;
+    }
+}
+
+void serial_preinit(serial_t *obj, PinName tx, PinName rx)
+{
+    /* Get UART object connected to the given pins */
+    UARTName uart_tx = (UARTName) pinmap_peripheral(tx, PinMap_UART_TX);
+    UARTName uart_rx = (UARTName) pinmap_peripheral(rx, PinMap_UART_RX);
+    /* Check that pins are connected to same UART */
+    UARTName uart = (UARTName) pinmap_merge(uart_tx, uart_rx);
+    MBED_ASSERT((int) uart != NC);
+
+    obj->serial.periph.uart = (USART_TypeDef *) uart;
+
+    /* Get location */
+    uint32_t uart_tx_loc = pin_location(tx, PinMap_UART_TX);
+    uint32_t uart_rx_loc = pin_location(rx, PinMap_UART_RX);
+
+#if defined(_SILICON_LABS_32B_PLATFORM_1)
+    /* Check that pins are used by same location for the given UART */
+    obj->serial.location = pinmap_merge(uart_tx_loc, uart_rx_loc);
+    MBED_ASSERT(obj->serial.location != (uint32_t)NC);
+#else
+    obj->serial.location_tx = uart_tx_loc;
+    obj->serial.location_rx = uart_rx_loc;
+#endif
+
+    /* Store pins in object for easy disabling in serial_free() */
+    //TODO: replace all usages with AF_USARTx_TX_PORT(location) macro to save 8 bytes from struct
+    obj->serial.rx_pin = rx;
+    obj->serial.tx_pin = tx;
+
+    /* Select interrupt */
+    switch ((uint32_t)obj->serial.periph.uart) {
+#ifdef UART0
+        case UART_0:
+            NVIC_SetVector(UART0_RX_IRQn, (uint32_t) &uart0_rx_irq);
+            NVIC_SetVector(UART0_TX_IRQn, (uint32_t) &uart0_tx_irq);
+            NVIC_SetPriority(UART0_TX_IRQn, 1);
+            break;
+#endif
+#ifdef UART1
+        case UART_1:
+            NVIC_SetVector(UART1_RX_IRQn, (uint32_t) &uart1_rx_irq);
+            NVIC_SetVector(UART1_TX_IRQn, (uint32_t) &uart1_tx_irq);
+            NVIC_SetPriority(UART1_TX_IRQn, 1);
+            break;
+#endif
+#ifdef USART0
+        case USART_0:
+            NVIC_SetVector(USART0_RX_IRQn, (uint32_t) &usart0_rx_irq);
+            NVIC_SetVector(USART0_TX_IRQn, (uint32_t) &usart0_tx_irq);
+            NVIC_SetPriority(USART0_TX_IRQn, 1);
+            break;
+#endif
+#ifdef USART1
+        case USART_1:
+            NVIC_SetVector(USART1_RX_IRQn, (uint32_t) &usart1_rx_irq);
+            NVIC_SetVector(USART1_TX_IRQn, (uint32_t) &usart1_tx_irq);
+            NVIC_SetPriority(USART1_TX_IRQn, 1);
+            break;
+#endif
+#ifdef USART2
+        case USART_2:
+            NVIC_SetVector(USART2_RX_IRQn, (uint32_t) &usart2_rx_irq);
+            NVIC_SetVector(USART2_TX_IRQn, (uint32_t) &usart2_tx_irq);
+            NVIC_SetPriority(USART2_TX_IRQn, 1);
+            break;
+#endif
+#ifdef LEUART0
+        case LEUART_0:
+            NVIC_SetVector(LEUART0_IRQn, (uint32_t) &leuart0_irq);
+            break;
+#endif
+#ifdef LEUART1
+        case LEUART_1:
+            NVIC_SetVector(LEUART1_IRQn, (uint32_t) &leuart1_irq);
+            break;
+#endif
+    }
+}
+
+static void serial_enable_pins(serial_t *obj, uint8_t enable)
+{
+    if (enable) {
+        /* Configure GPIO pins*/
+        if(obj->serial.rx_pin != NC) {
+            pin_mode(obj->serial.rx_pin, Input);
+        }
+        /* Set DOUT first to prevent glitches */
+        if(obj->serial.tx_pin != NC) {
+            GPIO_PinOutSet((GPIO_Port_TypeDef)(obj->serial.tx_pin >> 4 & 0xF), obj->serial.tx_pin & 0xF);
+            pin_mode(obj->serial.tx_pin, PushPull);
+        }
+    } else {
+        if(obj->serial.rx_pin != NC) {
+            pin_mode(obj->serial.rx_pin, Disabled);
+        }
+        if(obj->serial.tx_pin != NC) {
+            pin_mode(obj->serial.tx_pin, Disabled);
+        }
+    }
+}
+
+static void serial_set_route(serial_t *obj)
+{
+    /* Enable pins for UART at correct location */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+#ifdef _LEUART_ROUTE_LOCATION_SHIFT
+        obj->serial.periph.leuart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
+        if(obj->serial.tx_pin != (uint32_t)NC) {
+            obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_TXPEN;
+        } else {
+            obj->serial.periph.leuart->ROUTE &= ~LEUART_ROUTE_TXPEN;
+        }
+        if(obj->serial.rx_pin != (uint32_t)NC) {
+            obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_RXPEN;
+        } else {
+            obj->serial.periph.leuart->CMD    = LEUART_CMD_RXBLOCKEN;
+            obj->serial.periph.leuart->ROUTE &= ~LEUART_ROUTE_RXPEN;
+        }
+#else
+        if(obj->serial.location_tx != NC) {
+            obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT);
+            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK)) | LEUART_ROUTEPEN_TXPEN;
+        } else {
+            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK));
+        }
+        if(obj->serial.location_rx != NC) {
+            obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
+            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK)) | LEUART_ROUTEPEN_RXPEN;
+        } else {
+            obj->serial.periph.leuart->CMD       = LEUART_CMD_RXBLOCKEN;
+            obj->serial.periph.leuart->ROUTEPEN  = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK));
+        }
+#endif
+    } else {
+#ifdef _USART_ROUTE_LOCATION_SHIFT
+        obj->serial.periph.uart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
+        if(obj->serial.tx_pin != (uint32_t)NC) {
+            obj->serial.periph.uart->ROUTE |= USART_ROUTE_TXPEN;
+        } else {
+            obj->serial.periph.uart->ROUTE &= ~USART_ROUTE_TXPEN;
+        }
+        if(obj->serial.rx_pin != (uint32_t)NC) {
+            obj->serial.periph.uart->ROUTE |= USART_ROUTE_RXPEN;
+        } else {
+            obj->serial.periph.uart->CMD    = USART_CMD_RXBLOCKEN;
+            obj->serial.periph.uart->ROUTE &= ~USART_ROUTE_RXPEN;
+        }
+#else
+        if(obj->serial.location_tx != NC) {
+            obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT);
+            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK)) | USART_ROUTEPEN_TXPEN;
+        } else {
+            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK));
+        }
+        if(obj->serial.location_rx != NC) {
+            obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
+            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK)) | USART_ROUTEPEN_RXPEN;
+        } else {
+            obj->serial.periph.uart->CMD       = USART_CMD_RXBLOCKEN;
+            obj->serial.periph.uart->ROUTEPEN  = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK));
+        }
+#endif
+    }
+}
+
+void serial_init(serial_t *obj, PinName tx, PinName rx)
+{
+    uint32_t baudrate;
+    uint32_t uart_for_stdio = false;
+
+    serial_preinit(obj, tx, rx);
+
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        // Set up LEUART clock tree
+#ifdef LEUART_USING_LFXO
+        //set to use LFXO
+        CMU_ClockEnable(cmuClock_CORELE, true);
+        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
+#else
+        //set to use high-speed clock
+#ifdef _SILICON_LABS_32B_PLATFORM_2
+        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);
+#else
+        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
+#endif
+#endif
+    }
+
+    CMU_ClockEnable(serial_get_clock(obj), true);
+
+    /* Limitations of board controller: CDC port only supports 115kbaud */
+    if(((tx == STDIO_UART_TX) || (rx == STDIO_UART_RX))
+       && (obj->serial.periph.uart == (USART_TypeDef*)STDIO_UART )
+      ) {
+        baudrate = 115200;
+        uart_for_stdio = true;
+    } else {
+        baudrate = 9600;
+    }
+
+    /* Configure UART for async operation */
+    uart_init(obj, baudrate, ParityNone, 1);
+
+    /* Enable pins for UART at correct location */
+    serial_set_route(obj);
+
+    /* Reset interrupts */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
+        obj->serial.periph.leuart->CTRL |= LEUART_CTRL_RXDMAWU | LEUART_CTRL_TXDMAWU;
+    } else {
+        obj->serial.periph.uart->IFC = USART_IFC_TXC;
+    }
+
+    /* If this is the UART to be used for stdio, copy it to the stdio_uart struct */
+    if(uart_for_stdio) {
+        stdio_uart_inited = 1;
+        memcpy(&stdio_uart, obj, sizeof(serial_t));
+    }
+
+    serial_enable_pins(obj, true);
+    serial_enable(obj, true);
+
+    obj->serial.dmaOptionsTX.dmaChannel = -1;
+    obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
+
+    obj->serial.dmaOptionsRX.dmaChannel = -1;
+    obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
+
+}
+
+void serial_free(serial_t *obj)
+{
+    if( LEUART_REF_VALID(obj->serial.periph.leuart) ) {
+        LEUART_Enable(obj->serial.periph.leuart, leuartDisable);
+    } else {
+        USART_Enable(obj->serial.periph.uart, usartDisable);
+    }
+    serial_enable_pins(obj, false);
+}
+
+static void serial_enable(serial_t *obj, uint8_t enable)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        if (enable) {
+            LEUART_Enable(obj->serial.periph.leuart, leuartEnable);
+        } else {
+            LEUART_Enable(obj->serial.periph.leuart, leuartDisable);
+        }
+    } else {
+        if (enable) {
+            USART_Enable(obj->serial.periph.uart, usartEnable);
+        } else {
+            USART_Enable(obj->serial.periph.uart, usartDisable);
+        }
+    }
+    serial_irq_ids[serial_get_index(obj)] = 0;
+}
+
+/**
+ * Set UART baud rate
+ */
+void serial_baud(serial_t *obj, int baudrate)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        serial_leuart_baud(obj, baudrate);
+    } else {
+        USART_BaudrateAsyncSet(obj->serial.periph.uart, REFERENCE_FREQUENCY, (uint32_t)baudrate, usartOVS16);
+    }
+}
+
+/**
+ * Set LEUART baud rate
+ * Calculate whether LF or HF clock should be used.
+ */
+static void serial_leuart_baud(serial_t *obj, int baudrate)
+{
+#ifdef LEUART_USING_LFXO
+    /* check if baudrate is within allowed range */
+#if defined(_SILICON_LABS_32B_PLATFORM_2)
+    // P2 has 9 bits + 5 fractional bits in LEUART CLKDIV register
+    MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 9));
+#else
+    // P1 has 7 bits + 5 fractional bits in LEUART CLKDIV register
+    MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 7));
+#endif
+
+    if(baudrate > (LEUART_LF_REF_FREQ >> 1)){
+        // Baudrate is bigger than LFCLK/2 - we need to use the HF clock
+        uint8_t divisor = 1;
+
+#if defined(_SILICON_LABS_32B_PLATFORM_2)
+        /* Check if baudrate is within allowed range: (HFCLK/4096, HFCLK/2] */
+        MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 12)));
+
+        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);
+
+        if(baudrate > (LEUART_HF_REF_FREQ >> 9)){
+            divisor = 1;
+        }else if(baudrate > (LEUART_HF_REF_FREQ >> 10)){
+            divisor = 2;
+        }else if(baudrate > (LEUART_HF_REF_FREQ >> 11)){
+            divisor = 4;
+        }else{
+            divisor = 8;
+        }
+#else // P1
+        /* Check if baudrate is within allowed range */
+        MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 10)));
+
+        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
+
+        if(baudrate > (LEUART_HF_REF_FREQ >> 7)){
+            divisor = 1;
+        }else if(baudrate > (LEUART_HF_REF_FREQ >> 8)){
+            divisor = 2;
+        }else if(baudrate > (LEUART_HF_REF_FREQ >> 9)){
+            divisor = 4;
+        }else{
+            divisor = 8;
+        }
+#endif
+        CMU_ClockDivSet(serial_get_clock(obj), divisor);
+        LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_HF_REF_FREQ/divisor, (uint32_t)baudrate);
+    }else{
+        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
+        CMU_ClockDivSet(serial_get_clock(obj), 1);
+        LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_LF_REF_FREQ, (uint32_t)baudrate);
+    }
+#else
+    /* check if baudrate is within allowed range */
+    MBED_ASSERT((baudrate > (LEUART_REF_FREQ >> 10)) && (baudrate <= (LEUART_REF_FREQ >> 1)));
+    uint8_t divisor = 1;
+    if(baudrate > (LEUART_REF_FREQ >> 7)){
+        divisor = 1;
+    }else if(baudrate > (LEUART_REF_FREQ >> 8)){
+        divisor = 2;
+    }else if(baudrate > (LEUART_REF_FREQ >> 9)){
+        divisor = 4;
+    }else{
+        divisor = 8;
+    }
+    CMU_ClockDivSet(serial_get_clock(obj), divisor);
+    LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_REF_FREQ/divisor, (uint32_t)baudrate);
+#endif
+}
+
+/**
+ * Set UART format by re-initializing the peripheral.
+ */
+void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        /* Save the serial state */
+        uint8_t     was_enabled = LEUART_StatusGet(obj->serial.periph.leuart) & (LEUART_STATUS_TXENS | LEUART_STATUS_RXENS);
+        uint32_t    enabled_interrupts = obj->serial.periph.leuart->IEN;
+
+        LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
+
+        /* We support 8 data bits ONLY on LEUART*/
+        MBED_ASSERT(data_bits == 8);
+
+        /* Re-init the UART */
+        init.enable = (was_enabled == 0 ? leuartDisable : leuartEnable);
+        init.baudrate = LEUART_BaudrateGet(obj->serial.periph.leuart);
+        if (stop_bits == 2) {
+            init.stopbits = leuartStopbits2;
+        } else {
+            init.stopbits = leuartStopbits1;
+        }
+        switch (parity) {
+            case ParityOdd:
+            case ParityForced0:
+                init.parity = leuartOddParity;
+                break;
+            case ParityEven:
+            case ParityForced1:
+                init.parity = leuartEvenParity;
+                break;
+            default: /* ParityNone */
+                init.parity = leuartNoParity;
+                break;
+        }
+
+        LEUART_Init(obj->serial.periph.leuart, &init);
+
+        /* Re-enable pins for UART at correct location */
+        serial_set_route(obj);
+
+        /* Re-enable interrupts */
+        if(was_enabled != 0) {
+            obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
+            obj->serial.periph.leuart->IEN = enabled_interrupts;
+        }
+    } else {
+        /* Save the serial state */
+        uint8_t     was_enabled = USART_StatusGet(obj->serial.periph.uart) & (USART_STATUS_TXENS | USART_STATUS_RXENS);
+        uint32_t    enabled_interrupts = obj->serial.periph.uart->IEN;
+
+
+        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
+
+        /* We support 4 to 8 data bits */
+        MBED_ASSERT(data_bits >= 4 && data_bits <= 8);
+
+        /* Re-init the UART */
+        init.enable = (was_enabled == 0 ? usartDisable : usartEnable);
+        init.baudrate = USART_BaudrateGet(obj->serial.periph.uart);
+        init.oversampling = usartOVS16;
+        init.databits = (USART_Databits_TypeDef)((data_bits - 3) << _USART_FRAME_DATABITS_SHIFT);
+        if (stop_bits == 2) {
+            init.stopbits = usartStopbits2;
+        } else {
+            init.stopbits = usartStopbits1;
+        }
+        switch (parity) {
+            case ParityOdd:
+            case ParityForced0:
+                init.parity = usartOddParity;
+                break;
+            case ParityEven:
+            case ParityForced1:
+                init.parity = usartEvenParity;
+                break;
+            default: /* ParityNone */
+                init.parity = usartNoParity;
+                break;
+        }
+
+        USART_InitAsync(obj->serial.periph.uart, &init);
+
+        /* Re-enable pins for UART at correct location */
+        serial_set_route(obj);
+
+        /* Re-enable interrupts */
+        if(was_enabled != 0) {
+            obj->serial.periph.uart->IFC = USART_IFC_TXC;
+            obj->serial.periph.uart->IEN = enabled_interrupts;
+        }
+    }
+}
+
+/******************************************************************************
+ *                               INTERRUPTS                                   *
+ ******************************************************************************/
+uint8_t serial_tx_ready(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL) ? true : false;
+    } else {
+        return (obj->serial.periph.uart->STATUS & USART_STATUS_TXBL) ? true : false;
+    }
+}
+
+uint8_t serial_rx_ready(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (obj->serial.periph.leuart->STATUS & LEUART_STATUS_RXDATAV) ? true : false;
+    } else {
+        return (obj->serial.periph.uart->STATUS & USART_STATUS_RXDATAV) ? true : false;
+    }
+}
+
+void serial_write_asynch(serial_t *obj, int data)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        obj->serial.periph.leuart->TXDATA = (uint32_t)data;
+    } else {
+        obj->serial.periph.uart->TXDATA = (uint32_t)data;
+    }
+}
+
+int serial_read_asynch(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (int)obj->serial.periph.leuart->RXDATA;
+    } else {
+        return (int)obj->serial.periph.uart->RXDATA;
+    }
+}
+
+uint8_t serial_tx_int_flag(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (obj->serial.periph.leuart->IF & LEUART_IF_TXBL) ? true : false;
+    } else {
+        return (obj->serial.periph.uart->IF & USART_IF_TXBL) ? true : false;
+    }
+}
+
+uint8_t serial_rx_int_flag(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (obj->serial.periph.leuart->IF & LEUART_IF_RXDATAV) ? true : false;
+    } else {
+        return (obj->serial.periph.uart->IF & USART_IF_RXDATAV) ? true : false;
+    }
+}
+
+void serial_read_asynch_complete(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        obj->serial.periph.leuart->IFC |= LEUART_IFC_RXOF; // in case it got full
+    } else {
+        obj->serial.periph.uart->IFC |= USART_IFC_RXFULL; // in case it got full
+    }
+}
+
+void serial_write_asynch_complete(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        obj->serial.periph.leuart->IFC |= LEUART_IFC_TXC;
+    } else {
+        obj->serial.periph.uart->IFC |= USART_IFC_TXC;
+    }
+}
+
+/** Enable and set the interrupt handler for write (TX)
+ *
+ * @param obj     The serial object
+ * @param address The address of TX handler
+ * @param enable  Set to non-zero to enable or zero to disable
+ */
+void serial_write_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable)
+{
+    NVIC_SetVector(serial_get_tx_irq_index(obj), address);
+    serial_irq_set(obj, (SerialIrq)1, enable);
+}
+
+/** Enable and set the interrupt handler for read (RX)
+ *
+ * @param obj     The serial object
+ * @param address The address of RX handler
+ * @param enable  Set to non-zero to enable or zero to disable
+ */
+void serial_read_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable)
+{
+    NVIC_SetVector(serial_get_rx_irq_index(obj), address);
+    serial_irq_set(obj, (SerialIrq)0, enable);
+}
+
+uint8_t serial_interrupt_enabled(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (obj->serial.periph.leuart->IEN & (LEUART_IEN_RXDATAV | LEUART_IEN_TXBL)) ? true : false;
+    } else {
+        return (obj->serial.periph.uart->IEN & (USART_IEN_RXDATAV | USART_IEN_TXBL)) ? true : false;
+    }
+}
+
+/**
+ * Set handler for all serial interrupts (is probably SerialBase::_handler())
+ * and store IRQ ID to be returned to the handler upon interrupt. ID is
+ * probably a pointer to the calling Serial object.
+ */
+void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
+{
+    irq_handler = handler;
+    serial_irq_ids[serial_get_index(obj)] = id;
+}
+
+/**
+ * Generic ISR for all UARTs, both TX and RX
+ */
+static void uart_irq(UARTName name, SerialIrq irq)
+{
+    uint8_t index = serial_pointer_get_index((uint32_t)name);
+    if (serial_irq_ids[index] != 0) {
+        /* Pass interrupt on to mbed common handler */
+        irq_handler(serial_irq_ids[index], irq);
+        /* Clearing interrupt not necessary */
+    }
+}
+
+/**
+ * Set ISR for a given UART and interrupt event (TX or RX)
+ */
+void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        /* Enable or disable interrupt */
+        if (enable) {
+            if (irq == RxIrq) { /* RX */
+                obj->serial.periph.leuart->IEN |= LEUART_IEN_RXDATAV;
+                NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj));
+                NVIC_EnableIRQ(serial_get_rx_irq_index(obj));
+            } else { /* TX */
+                obj->serial.periph.leuart->IEN |= LEUART_IEN_TXC;
+                NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj));
+                NVIC_SetPriority(serial_get_tx_irq_index(obj), 1);
+                NVIC_EnableIRQ(serial_get_tx_irq_index(obj));
+            }
+        } else {
+            if (irq == RxIrq) { /* RX */
+                obj->serial.periph.leuart->IEN &= ~LEUART_IEN_RXDATAV;
+                NVIC_DisableIRQ(serial_get_rx_irq_index(obj));
+            } else { /* TX */
+                obj->serial.periph.leuart->IEN &= ~LEUART_IEN_TXC;
+                NVIC_DisableIRQ(serial_get_tx_irq_index(obj));
+            }
+        }
+    } else {
+        /* Enable or disable interrupt */
+        if (enable) {
+            if (irq == RxIrq) { /* RX */
+                obj->serial.periph.uart->IEN |= USART_IEN_RXDATAV;
+                NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj));
+                NVIC_EnableIRQ(serial_get_rx_irq_index(obj));
+            } else { /* TX */
+                obj->serial.periph.uart->IEN |= USART_IEN_TXC;
+                NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj));
+                NVIC_SetPriority(serial_get_tx_irq_index(obj), 1);
+                NVIC_EnableIRQ(serial_get_tx_irq_index(obj));
+            }
+        } else {
+            if (irq == RxIrq) { /* RX */
+                obj->serial.periph.uart->IEN &= ~USART_IEN_RXDATAV;
+                NVIC_DisableIRQ(serial_get_rx_irq_index(obj));
+            } else { /* TX */
+                obj->serial.periph.uart->IEN &= ~USART_IEN_TXC;
+                NVIC_DisableIRQ(serial_get_tx_irq_index(obj));
+            }
+        }
+    }
+}
+
+/******************************************************************************
+ *                               READ/WRITE                                   *
+ ******************************************************************************/
+
+/**
+ *  Get one char from serial link
+ */
+int serial_getc(serial_t *obj)
+{
+    /* Emlib USART_Rx blocks until data is available, so we don't need to use
+     * serial_readable(). Use USART_RxDataGet() to read register directly. */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return LEUART_Rx(obj->serial.periph.leuart);
+    } else {
+        return USART_Rx(obj->serial.periph.uart);
+    }
+}
+
+/*
+ * Send one char over serial link
+ */
+void serial_putc(serial_t *obj, int c)
+{
+    /* Emlib USART_Tx blocks until buffer is writable (non-full), so we don't
+     * need to use serial_writable(). */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        LEUART_Tx(obj->serial.periph.leuart, (uint8_t)(c));
+        while (!(obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXC));
+    } else {
+        USART_Tx(obj->serial.periph.uart, (uint8_t)(c));
+        while (!(obj->serial.periph.uart->STATUS & USART_STATUS_TXC));
+    }
+}
+
+/**
+ * Check if data is available in RX data vector
+ */
+int serial_readable(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return obj->serial.periph.leuart->STATUS & LEUART_STATUS_RXDATAV;
+    } else {
+        return obj->serial.periph.uart->STATUS & USART_STATUS_RXDATAV;
+    }
+}
+
+/**
+ * Check if TX buffer is empty
+ */
+int serial_writable(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL;
+    } else {
+        return obj->serial.periph.uart->STATUS & USART_STATUS_TXBL;
+    }
+}
+
+/**
+ * Clear UART interrupts
+ */
+void serial_clear(serial_t *obj)
+{
+    /* Interrupts automatically clear when condition is not met anymore */
+}
+
+void serial_break_set(serial_t *obj)
+{
+    /* Send transmission break */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        obj->serial.periph.leuart->TXDATAX = LEUART_TXDATAX_TXBREAK;
+    } else {
+        obj->serial.periph.uart->TXDATAX = USART_TXDATAX_TXBREAK;
+    }
+}
+
+void serial_break_clear(serial_t *obj)
+{
+    /* No need to clear break, it is automatically cleared after one frame.
+     * From the reference manual:
+     *
+     * By setting TXBREAK, the output will be held low during the stop-bit
+     * period to generate a framing error. A receiver that supports break
+     * detection detects this state, allowing it to be used e.g. for framing
+     * of larger data packets. The line is driven high before the next frame
+     * is transmitted so the next start condition can be identified correctly
+     * by the recipient. Continuous breaks lasting longer than a USART frame
+     * are thus not supported by the USART. GPIO can be used for this.
+     */
+}
+
+void serial_pinout_tx(PinName tx)
+{
+    /* 0x10 sets DOUT high. Prevents false start. */
+    pin_mode(tx, PushPull | 0x10);
+}
+
+/************************************************************************************
+ *          DMA helper functions                                                    *
+ ************************************************************************************/
+/******************************************
+* static void serial_dmaTransferComplete(uint channel, bool primary, void* user)
+*
+* Callback function which gets called upon DMA transfer completion
+* the user-defined pointer is pointing to the CPP-land thunk
+******************************************/
+static void serial_dmaTransferComplete(unsigned int channel, bool primary, void *user)
+{
+    /* Store information about which channel triggered because CPP doesn't take arguments */
+    serial_dma_irq_fired[channel] = true;
+
+    /* User pointer should be a thunk to CPP land */
+    if (user != NULL) {
+        ((DMACallback)user)();
+    }
+}
+
+#ifndef LDMA_PRESENT
+
+/******************************************
+* static void serial_setupDmaChannel(serial_t *obj, bool tx_nrx)
+*
+* Sets up the DMA configuration block for the assigned channel
+* tx_nrx: true if configuring TX, false if configuring RX.
+******************************************/
+static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx)
+{
+    DMA_CfgChannel_TypeDef  channelConfig;
+
+    if(tx_nrx) {
+        //setup TX channel
+        channelConfig.highPri = false;
+        channelConfig.enableInt = true;
+        channelConfig.cb = &(obj->serial.dmaOptionsTX.dmaCallback);
+
+        switch((uint32_t)(obj->serial.periph.uart)) {
+#ifdef UART0
+            case UART_0:
+                channelConfig.select = DMAREQ_UART0_TXBL;
+                break;
+#endif
+#ifdef UART1
+            case UART_1:
+                channelConfig.select = DMAREQ_UART1_TXBL;
+                break;
+#endif
+#ifdef USART0
+            case USART_0:
+                channelConfig.select = DMAREQ_USART0_TXBL;
+                break;
+#endif
+#ifdef USART1
+            case USART_1:
+                channelConfig.select = DMAREQ_USART1_TXBL;
+                break;
+#endif
+#ifdef USART2
+            case USART_2:
+                channelConfig.select = DMAREQ_USART2_TXBL;
+                break;
+#endif
+#ifdef LEUART0
+            case LEUART_0:
+                channelConfig.select = DMAREQ_LEUART0_TXBL;
+                break;
+#endif
+#ifdef LEUART1
+            case LEUART_1:
+                channelConfig.select = DMAREQ_LEUART1_TXBL;
+                break;
+#endif
+        }
+
+        DMA_CfgChannel(obj->serial.dmaOptionsTX.dmaChannel, &channelConfig);
+    } else {
+        //setup RX channel
+        channelConfig.highPri = true;
+        channelConfig.enableInt = true;
+        channelConfig.cb = &(obj->serial.dmaOptionsRX.dmaCallback);
+
+        switch((uint32_t)(obj->serial.periph.uart)) {
+#ifdef UART0
+            case UART_0:
+                channelConfig.select = DMAREQ_UART0_RXDATAV;
+                break;
+#endif
+#ifdef UART1
+            case UART_1:
+                channelConfig.select = DMAREQ_UART1_RXDATAV;
+                break;
+#endif
+#ifdef USART0
+            case USART_0:
+                channelConfig.select = DMAREQ_USART0_RXDATAV;
+                break;
+#endif
+#ifdef USART1
+            case USART_1:
+                channelConfig.select = DMAREQ_USART1_RXDATAV;
+                break;
+#endif
+#ifdef USART2
+            case USART_2:
+                channelConfig.select = DMAREQ_USART2_RXDATAV;
+                break;
+#endif
+#ifdef LEUART0
+            case LEUART_0:
+                channelConfig.select = DMAREQ_LEUART0_RXDATAV;
+                break;
+#endif
+#ifdef LEUART1
+            case LEUART_1:
+                channelConfig.select = DMAREQ_LEUART1_RXDATAV;
+                break;
+#endif
+        }
+
+        DMA_CfgChannel(obj->serial.dmaOptionsRX.dmaChannel, &channelConfig);
+    }
+}
+
+#endif /* LDMA_PRESENT */
+
+/******************************************
+* static void serial_dmaTrySetState(DMA_OPTIONS_t *obj, DMAUsage requestedState)
+*
+* Tries to set the passed DMA state to the requested state.
+*
+* requested state possibilities:
+*   * NEVER:
+*       if the previous state was always, will deallocate the channel
+*   * OPPORTUNISTIC:
+*       If the previous state was always, will reuse that channel but free upon next completion.
+*       If not, will try to acquire a channel.
+*       When allocated, state changes to DMA_USAGE_TEMPORARY_ALLOCATED.
+*   * ALWAYS:
+*       Will try to allocate a channel and keep it.
+*       If succesfully allocated, state changes to DMA_USAGE_ALLOCATED.
+******************************************/
+static void serial_dmaTrySetState(DMA_OPTIONS_t *obj, DMAUsage requestedState, serial_t *serialPtr, bool tx_nrx)
+{
+    DMAUsage currentState = obj->dmaUsageState;
+    int tempDMAChannel = -1;
+
+    if ((requestedState == DMA_USAGE_ALWAYS) && (currentState != DMA_USAGE_ALLOCATED)) {
+        /* Try to allocate channel */
+        tempDMAChannel = dma_channel_allocate(DMA_CAP_NONE);
+        if(tempDMAChannel >= 0) {
+            obj->dmaChannel = tempDMAChannel;
+            obj->dmaUsageState = DMA_USAGE_ALLOCATED;
+            dma_init();
+            serial_dmaSetupChannel(serialPtr, tx_nrx);
+        }
+    } else if (requestedState == DMA_USAGE_OPPORTUNISTIC) {
+        if (currentState == DMA_USAGE_ALLOCATED) {
+            /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
+            obj->dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
+        } else {
+            /* Try to allocate channel */
+            tempDMAChannel = dma_channel_allocate(DMA_CAP_NONE);
+            if(tempDMAChannel >= 0) {
+                obj->dmaChannel = tempDMAChannel;
+                obj->dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
+                dma_init();
+                serial_dmaSetupChannel(serialPtr, tx_nrx);
+            }
+        }
+    } else if (requestedState == DMA_USAGE_NEVER) {
+        /* If channel is allocated, get rid of it */
+        dma_channel_free(obj->dmaChannel);
+        obj->dmaChannel = -1;
+        obj->dmaUsageState = DMA_USAGE_NEVER;
+    }
+}
+
+#ifndef LDMA_PRESENT
+
+static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length, bool tx_nrx)
+{
+    DMA_CfgDescr_TypeDef channelConfig;
+
+    if(tx_nrx) {
+        // Set DMA callback
+        obj->serial.dmaOptionsTX.dmaCallback.cbFunc = serial_dmaTransferComplete;
+        obj->serial.dmaOptionsTX.dmaCallback.userPtr = NULL;
+
+        // Set up configuration structure
+        channelConfig.dstInc = dmaDataIncNone;
+        channelConfig.srcInc = dmaDataInc1;
+        channelConfig.size = dmaDataSize1;
+        channelConfig.arbRate = dmaArbitrate1;
+        channelConfig.hprot = 0;
+
+        // Clear TXC
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC);
+        } else {
+            USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
+        }
+
+        // Set callback and enable TXC. This will fire once the
+        // serial transfer finishes
+        NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)cb);
+        serial_irq_set(obj, TxIrq, true);
+
+        DMA_CfgDescr(obj->serial.dmaOptionsTX.dmaChannel, true, &channelConfig);
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            // Activate TX and clear TX buffer (note that clear must be done
+            // separately and before TXEN or DMA will die on some platforms)
+            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX;
+            obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN;
+            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+
+            // Kick off TX DMA
+            DMA_ActivateBasic(obj->serial.dmaOptionsTX.dmaChannel, true, false, (void*) &(obj->serial.periph.leuart->TXDATA), buffer, length - 1);
+        } else {
+            // Activate TX amd clear TX buffer
+            obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
+
+            // Kick off TX DMA
+            DMA_ActivateBasic(obj->serial.dmaOptionsTX.dmaChannel, true, false, (void*) &(obj->serial.periph.uart->TXDATA), buffer, length - 1);
+        }
+
+
+    } else {
+        // Set DMA callback
+        obj->serial.dmaOptionsRX.dmaCallback.cbFunc = serial_dmaTransferComplete;
+        obj->serial.dmaOptionsRX.dmaCallback.userPtr = cb;
+
+        // Set up configuration structure
+        channelConfig.dstInc = dmaDataInc1;
+        channelConfig.srcInc = dmaDataIncNone;
+        channelConfig.size = dmaDataSize1;
+        channelConfig.arbRate = dmaArbitrate1;
+        channelConfig.hprot = 0;
+
+        DMA_CfgDescr(obj->serial.dmaOptionsRX.dmaChannel, true, &channelConfig);
+
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            // Activate RX and clear RX buffer
+            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX;
+            obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN;
+            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+
+            // Kick off RX DMA
+            DMA_ActivateBasic(obj->serial.dmaOptionsRX.dmaChannel, true, false, buffer, (void*) &(obj->serial.periph.leuart->RXDATA), length - 1);
+        } else {
+            // Activate RX and clear RX buffer
+            obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
+
+            // Kick off RX DMA
+            DMA_ActivateBasic(obj->serial.dmaOptionsRX.dmaChannel, true, false, buffer, (void*) &(obj->serial.periph.uart->RXDATA), length - 1);
+        }
+    }
+}
+
+#endif
+
+
+#ifdef LDMA_PRESENT
+
+static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx)
+{
+}
+
+static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length, bool tx_nrx)
+{
+    LDMA_PeripheralSignal_t dma_periph;
+
+    obj->serial.dmaOptionsRX.dmaCallback.userPtr = cb;
+
+    if( tx_nrx ) {
+        volatile void *target_addr;
+
+        // Clear TXC
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC);
+        } else {
+            USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
+        }
+
+        switch((uint32_t)(obj->serial.periph.uart)) {
+#ifdef USART0
+            case USART_0:
+                dma_periph = ldmaPeripheralSignal_USART0_TXBL;
+                target_addr = &USART0->TXDATA;
+                obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
+                break;
+#endif
+#ifdef USART1
+            case USART_1:
+                dma_periph = ldmaPeripheralSignal_USART1_TXBL;
+                target_addr = &USART1->TXDATA;
+                obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
+                break;
+#endif
+#ifdef LEUART0
+            case LEUART_0:
+                dma_periph = ldmaPeripheralSignal_LEUART0_TXBL;
+                target_addr = &LEUART0->TXDATA;
+                obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX;
+                obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN;
+                while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+                break;
+#endif
+            default:
+                MBED_ASSERT(0);
+                while(1);
+                break;
+        }
+
+        // Set callback and enable TXC. This will fire once the
+        // serial transfer finishes
+        NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)cb);
+        serial_irq_set(obj, TxIrq, true);
+
+        // Start DMA transfer
+        LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
+        LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(buffer, target_addr, length);
+        LDMAx_StartTransfer(obj->serial.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete, NULL);
+
+    } else {
+        volatile const void *source_addr;
+
+        switch((uint32_t)(obj->serial.periph.uart)) {
+#ifdef USART0
+            case USART_0:
+                dma_periph = ldmaPeripheralSignal_USART0_RXDATAV;
+                source_addr = &USART0->RXDATA;
+                obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
+                break;
+#endif
+#ifdef USART1
+            case USART_1:
+                dma_periph = ldmaPeripheralSignal_USART1_RXDATAV;
+                source_addr = &USART1->RXDATA;
+                obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
+                break;
+#endif
+#ifdef LEUART0
+            case LEUART_0:
+                dma_periph = ldmaPeripheralSignal_LEUART0_RXDATAV;
+                source_addr = &LEUART0->RXDATA;
+                obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX;
+                obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN;
+                while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+                break;
+#endif
+            default:
+                MBED_ASSERT(0);
+                while(1);
+                break;
+        }
+
+        LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
+        LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(source_addr, buffer, length);
+        LDMAx_StartTransfer(obj->serial.dmaOptionsRX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete, cb);
+    }
+}
+
+#endif /* LDMA_PRESENT */
+
+/************************************************************************************
+ *          ASYNCHRONOUS HAL                                                        *
+ ************************************************************************************/
+
+#if DEVICE_SERIAL_ASYNCH
+
+/************************************
+ * HELPER FUNCTIONS                 *
+ ***********************************/
+
+/** Configure TX events
+ *
+ * @param obj    The serial object
+ * @param event  The logical OR of the TX events to configure
+ * @param enable Set to non-zero to enable events, or zero to disable them
+ */
+void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable)
+{
+    // Shouldn't have to enable TX interrupt here, just need to keep track of the requested events.
+    if(enable) obj->serial.events |= event;
+    else obj->serial.events &= ~event;
+}
+
+/**
+ * @param obj    The serial object.
+ * @param event  The logical OR of the RX events to configure
+ * @param enable Set to non-zero to enable events, or zero to disable them
+ */
+void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable)
+{
+    if(enable) {
+        obj->serial.events |= event;
+    } else {
+        obj->serial.events &= ~event;
+    }
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        if(event & SERIAL_EVENT_RX_FRAMING_ERROR) {
+            //FERR interrupt source
+            if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_FERR;
+            else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_FERR;
+        }
+        if(event & SERIAL_EVENT_RX_PARITY_ERROR) {
+            //PERR interrupt source
+            if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_PERR;
+            else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_PERR;
+        }
+        if(event & SERIAL_EVENT_RX_OVERFLOW) {
+            //RXOF interrupt source
+            if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_RXOF;
+            else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_RXOF;
+        }
+    } else {
+        if(event & SERIAL_EVENT_RX_FRAMING_ERROR) {
+            //FERR interrupt source
+            if(enable) obj->serial.periph.uart->IEN |= USART_IEN_FERR;
+            else obj->serial.periph.uart->IEN &= ~USART_IEN_FERR;
+        }
+        if(event & SERIAL_EVENT_RX_PARITY_ERROR) {
+            //PERR interrupt source
+            if(enable) obj->serial.periph.uart->IEN |= USART_IEN_PERR;
+            else obj->serial.periph.uart->IEN &= ~USART_IEN_PERR;
+        }
+        if(event & SERIAL_EVENT_RX_OVERFLOW) {
+            //RXOF interrupt source
+            if(enable) obj->serial.periph.uart->IEN |= USART_IEN_RXOF;
+            else obj->serial.periph.uart->IEN &= ~USART_IEN_RXOF;
+        }
+    }
+}
+
+/** Configure the TX buffer for an asynchronous write serial transaction
+ *
+ * @param obj       The serial object.
+ * @param tx        The buffer for sending.
+ * @param tx_length The number of words to transmit.
+ */
+void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width)
+{
+    // We only support byte buffers for now
+    MBED_ASSERT(width == 8);
+
+    if(serial_tx_active(obj)) return;
+
+    obj->tx_buff.buffer = tx;
+    obj->tx_buff.length = tx_length;
+    obj->tx_buff.pos = 0;
+
+    return;
+}
+
+/** Configure the TX buffer for an asynchronous read serial transaction
+ *
+ * @param obj       The serial object.
+ * @param rx        The buffer for receiving.
+ * @param rx_length The number of words to read.
+ */
+void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width)
+{
+    // We only support byte buffers for now
+    MBED_ASSERT(width == 8);
+
+    if(serial_rx_active(obj)) return;
+
+    obj->rx_buff.buffer = rx;
+    obj->rx_buff.length = rx_length;
+    obj->rx_buff.pos = 0;
+
+    return;
+}
+
+/************************************
+ * TRANSFER FUNCTIONS               *
+ ***********************************/
+
+/** Begin asynchronous TX transfer. The used buffer is specified in the serial object,
+ *  tx_buff
+ *
+ * @param obj  The serial object
+ * @param cb   The function to call when an event occurs
+ * @param hint A suggestion for how to use DMA with this transfer
+ * @return Returns number of data transfered, or 0 otherwise
+ */
+int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
+{
+   // Check that a buffer has indeed been set up
+    MBED_ASSERT(tx != (void*)0);
+    if(tx_length == 0) return 0;
+
+    // Set up buffer
+    serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width);
+
+    // Set up events
+    serial_tx_enable_event(obj, SERIAL_EVENT_TX_ALL, false);
+    serial_tx_enable_event(obj, event, true);
+
+    // Set up sleepmode
+    serial_block_sleep(obj);
+
+    // Determine DMA strategy
+    serial_dmaTrySetState(&(obj->serial.dmaOptionsTX), hint, obj, true);
+
+    // If DMA, kick off DMA transfer
+    if(obj->serial.dmaOptionsTX.dmaChannel >= 0) {
+        serial_dmaActivate(obj, (void*)handler, obj->tx_buff.buffer, obj->tx_buff.length, true);
+    }
+    // Else, activate interrupt. TXBL will take care of buffer filling through ISR.
+    else {
+        // Store callback
+        NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj));
+        NVIC_DisableIRQ(serial_get_tx_irq_index(obj));
+        NVIC_SetPriority(serial_get_tx_irq_index(obj), 1);
+        NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)handler);
+        NVIC_EnableIRQ(serial_get_tx_irq_index(obj));
+
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            // Activate TX and clear TX buffer
+            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX;
+            obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN;
+            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+
+            // Enable interrupt
+            LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_TXBL);
+        } else {
+            // Activate TX and clear TX buffer
+            obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX;
+
+            // Enable interrupt
+            USART_IntEnable(obj->serial.periph.uart, USART_IEN_TXBL);
+        }
+    }
+
+    return 0;
+}
+
+/** Begin asynchronous RX transfer (enable interrupt for data collecting)
+ *  The used buffer is specified in the serial object - rx_buff
+ *
+ * @param obj  The serial object
+ * @param cb   The function to call when an event occurs
+ * @param hint A suggestion for how to use DMA with this transfer
+ */
+void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
+{
+    // Check that a buffer has indeed been set up
+    MBED_ASSERT(rx != (void*)0);
+    if(rx_length == 0) return;
+
+    // Set up buffer
+    serial_rx_buffer_set(obj,(void*) rx, rx_length, rx_width);
+
+    //disable character match if no character is specified
+    if(char_match == SERIAL_RESERVED_CHAR_MATCH){
+        event &= ~SERIAL_EVENT_RX_CHARACTER_MATCH;
+    }
+
+    /*clear all set interrupts*/
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR | LEUART_IFC_FERR | LEUART_IFC_RXOF);
+    }else{
+        USART_IntClear(obj->serial.periph.uart,  USART_IFC_PERR | USART_IFC_FERR | USART_IFC_RXOF);
+    }
+
+    // Set up events
+    serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, false);
+    serial_rx_enable_event(obj, event, true);
+    obj->char_match = char_match;
+
+    // Set up sleepmode
+    serial_block_sleep(obj);
+
+    // Determine DMA strategy
+    // If character match is enabled, we can't use DMA, sadly. We could when using LEUART though, but that support is not in here yet.
+    // TODO: add DMA support for character matching with leuart
+    if(!(event & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
+        serial_dmaTrySetState(&(obj->serial.dmaOptionsRX), hint, obj, false);
+    }else{
+        serial_dmaTrySetState(&(obj->serial.dmaOptionsRX), DMA_USAGE_NEVER, obj, false);
+    }
+
+    // If DMA, kick off DMA
+    if(obj->serial.dmaOptionsRX.dmaChannel >= 0) {
+        serial_dmaActivate(obj, (void*)handler, obj->rx_buff.buffer, obj->rx_buff.length, false);
+    }
+    // Else, activate interrupt. RXDATAV is responsible for incoming data notification.
+    else {
+        // Store callback
+        NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj));
+        NVIC_SetVector(serial_get_rx_irq_index(obj), (uint32_t)handler);
+        NVIC_EnableIRQ(serial_get_rx_irq_index(obj));
+
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            // Activate RX and clear RX buffer
+            obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX;
+            obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN;
+            while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+
+            // Enable interrupt
+            LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_RXDATAV);
+        } else {
+            // Activate RX and clear RX buffer
+            obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX;
+
+            // Clear RXFULL
+            USART_IntClear(obj->serial.periph.uart, USART_IFC_RXFULL);
+
+            // Enable interrupt
+            USART_IntEnable(obj->serial.periph.uart, USART_IEN_RXDATAV);
+        }
+    }
+
+    return;
+}
+
+/** Attempts to determine if the serial peripheral is already in use for TX
+ *
+ * @param obj The serial object
+ * @return Non-zero if the TX transaction is ongoing, 0 otherwise
+ */
+uint8_t serial_tx_active(serial_t *obj)
+{
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        return (obj->serial.periph.leuart->IEN & (LEUART_IEN_TXBL|LEUART_IEN_TXC)) ? true : false;
+    } else {
+        return (obj->serial.periph.uart->IEN & (USART_IEN_TXBL|USART_IEN_TXC)) ? true : false;
+    }
+}
+
+/** Attempts to determine if the serial peripheral is already in use for RX
+ *
+ * @param obj The serial object
+ * @return Non-zero if the RX transaction is ongoing, 0 otherwise
+ */
+uint8_t serial_rx_active(serial_t *obj)
+{
+    switch(obj->serial.dmaOptionsRX.dmaUsageState) {
+        case DMA_USAGE_TEMPORARY_ALLOCATED:
+            /* Temporary allocation always means its active, as this state gets cleared afterwards */
+            return 1;
+        case DMA_USAGE_ALLOCATED:
+            /* Check whether the allocated DMA channel is active by checking the DMA transfer */
+#ifndef LDMA_PRESENT
+            return DMA_ChannelEnabled(obj->serial.dmaOptionsRX.dmaChannel);
+#else
+            // LDMA_TransferDone does not work since the CHDONE bits get cleared,
+            // so just check if the channel is enabled
+            return LDMA->CHEN & (1 << obj->serial.dmaOptionsRX.dmaChannel);
+#endif
+        default:
+            /* Check whether interrupt for serial TX is enabled */
+            if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+                return (obj->serial.periph.leuart->IEN & (LEUART_IEN_RXDATAV)) ? true : false;
+            } else {
+                return (obj->serial.periph.uart->IEN & (USART_IEN_RXDATAV)) ? true : false;
+            }
+    }
+}
+
+/** The asynchronous TX handler. Writes to the TX FIFO and checks for events.
+ *  If any TX event has occured, the TX abort function is called.
+ *
+ * @param obj The serial object
+ * @return Returns event flags if a TX transfer termination condition was met or 0 otherwise
+ */
+int serial_tx_irq_handler_asynch(serial_t *obj)
+{
+    /* This interrupt handler is called from USART irq */
+    uint8_t *buf = obj->tx_buff.buffer;
+
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        if(obj->serial.periph.leuart->IEN & LEUART_IEN_TXBL){
+            /* There is still data to send */
+            while((LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_TXBL) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
+                while (obj->serial.periph.leuart->SYNCBUSY);
+                LEUART_Tx(obj->serial.periph.leuart, buf[obj->tx_buff.pos]);
+                obj->tx_buff.pos++;
+            }
+            if(obj->tx_buff.pos >= obj->tx_buff.length){
+                /* Last byte has been put in TX, set up TXC interrupt */
+                LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXBL);
+                LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_TXC);
+                while (obj->serial.periph.leuart->SYNCBUSY);
+            }
+        }else if (obj->serial.periph.leuart->IF & LEUART_IF_TXC){
+            /* Last byte has been successfully transmitted. Stop the procedure */
+            serial_tx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
+        }
+    } else {
+        if(obj->serial.periph.uart->IEN & USART_IEN_TXBL){
+            /* There is still data to send */
+            while((USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_TXBL) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
+                USART_Tx(obj->serial.periph.uart, buf[obj->tx_buff.pos]);
+                obj->tx_buff.pos++;
+            }
+            if(obj->tx_buff.pos >= obj->tx_buff.length){
+                /* Last byte has been put in TX, set up TXC interrupt */
+                USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXBL);
+                USART_IntEnable(obj->serial.periph.uart, USART_IEN_TXC);
+            }
+        } else if (obj->serial.periph.uart->IF & USART_IF_TXC) {
+            /* Last byte has been successfully transmitted. Stop the procedure */
+            serial_tx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
+        }
+    }
+    return 0;
+}
+
+/** The asynchronous RX handler. Reads from the RX FIFOF and checks for events.
+ *  If any RX event has occured, the RX abort function is called.
+ *
+ * @param obj The serial object
+ * @return Returns event flags if a RX transfer termination condition was met or 0 otherwise
+ */
+int serial_rx_irq_handler_asynch(serial_t *obj)
+{
+    int event = 0;
+
+    /* This interrupt handler is called from USART irq */
+    uint8_t *buf = (uint8_t*)obj->rx_buff.buffer;
+
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        /* Determine the source of the interrupt */
+        if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_PERR) {
+            /* Parity error has occurred, and we are notifying. */
+            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR);
+            serial_rx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_RX_PARITY_ERROR;
+        }
+
+        if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_FERR) {
+            /* Framing error has occurred, and we are notifying */
+            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_FERR);
+            serial_rx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_RX_FRAMING_ERROR;
+        }
+
+        if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_RXOF) {
+            /* RX buffer overflow has occurred, and we are notifying */
+            LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_RXOF);
+            serial_rx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_RX_OVERFLOW;
+        }
+
+        if((LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_RXDATAV) || (LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_RXDATAV)) {
+            /* Valid data in buffer. Determine course of action: continue receiving or interrupt */
+            if(obj->rx_buff.pos >= (obj->rx_buff.length - 1)) {
+                /* Last char, transfer complete. Switch off interrupt and return event. */
+                buf[obj->rx_buff.pos] = LEUART_RxDataGet(obj->serial.periph.leuart);
+
+                event |= SERIAL_EVENT_RX_COMPLETE;
+
+                if((buf[obj->rx_buff.pos] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
+
+                serial_rx_abort_asynch_intern(obj, 1);
+                return event & obj->serial.events;
+            } else {
+                /* There's still space in the receive buffer */
+                while((LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_RXDATAV) && (obj->rx_buff.pos <= (obj->rx_buff.length - 1))) {
+                    bool aborting = false;
+                    buf[obj->rx_buff.pos] = LEUART_RxDataGet(obj->serial.periph.leuart);
+                    obj->rx_buff.pos++;
+
+                    /* Check for character match event */
+                    if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
+                        aborting = true;
+                        event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
+                    }
+
+                    /* Check for final char event */
+                    if(obj->rx_buff.pos >= (obj->rx_buff.length)) {
+                        aborting = true;
+                        event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
+                    }
+
+                    if(aborting) {
+                        serial_rx_abort_asynch_intern(obj, 1);
+                        return event & obj->serial.events;
+                    }
+                }
+            }
+        }
+    } else {
+        /* Determine the source of the interrupt */
+        if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_PERR) {
+            /* Parity error has occurred, and we are notifying. */
+            USART_IntClear(obj->serial.periph.uart, USART_IFC_PERR);
+            serial_rx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_RX_PARITY_ERROR;
+        }
+
+        if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_FERR) {
+            /* Framing error has occurred, and we are notifying */
+            USART_IntClear(obj->serial.periph.uart, USART_IFC_FERR);
+            serial_rx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_RX_FRAMING_ERROR;
+        }
+
+        if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_RXOF) {
+            /* RX buffer overflow has occurred, and we are notifying */
+            USART_IntClear(obj->serial.periph.uart, USART_IFC_RXOF);
+            serial_rx_abort_asynch_intern(obj, 1);
+            return SERIAL_EVENT_RX_OVERFLOW;
+        }
+
+        if((USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_RXDATAV) || (USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_RXFULL)) {
+            /* Valid data in buffer. Determine course of action: continue receiving or interrupt */
+            if(obj->rx_buff.pos >= (obj->rx_buff.length - 1)) {
+                /* Last char, transfer complete. Switch off interrupt and return event. */
+                buf[obj->rx_buff.pos] = USART_RxDataGet(obj->serial.periph.uart);
+
+                event |= SERIAL_EVENT_RX_COMPLETE;
+
+                if((buf[obj->rx_buff.pos] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
+
+                serial_rx_abort_asynch_intern(obj, 1);
+                return event & obj->serial.events;
+            } else {
+                /* There's still space in the receive buffer */
+                while(((USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_RXDATAV) || (USART_StatusGet(obj->serial.periph.uart) & USART_IF_RXFULL)) && (obj->rx_buff.pos <= (obj->rx_buff.length - 1))) {
+                    bool aborting = false;
+                    buf[obj->rx_buff.pos] = USART_RxDataGet(obj->serial.periph.uart);
+                    obj->rx_buff.pos++;
+
+                    /* Check for character match event */
+                    if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
+                        aborting = true;
+                        event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
+                    }
+
+                    /* Check for final char event */
+                    if(obj->rx_buff.pos >= (obj->rx_buff.length)) {
+                        aborting = true;
+                        event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
+                    }
+
+                    if(aborting) {
+                        serial_rx_abort_asynch_intern(obj, 1);
+                        return event & obj->serial.events;
+                    }
+                }
+            }
+        }
+    }
+
+    /* All events should have generated a return, if no return has happened, no event has been caught */
+    return 0;
+}
+
+/** Unified IRQ handler. Determines the appropriate handler to execute and returns the flags.
+ *
+ * WARNING: this code should be stateless, as re-entrancy is very possible in interrupt-based mode.
+ */
+int serial_irq_handler_asynch(serial_t *obj)
+{
+    uint32_t txc_int;
+
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        txc_int = LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_TXC;
+    } else {
+        txc_int = USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_TXC;
+    }
+
+    /* First, check if we're running in DMA mode */
+    if( (obj->serial.dmaOptionsRX.dmaChannel != -1) &&
+        serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel]) {
+        /* Clean up */
+        serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel] = false;
+        serial_rx_abort_asynch_intern(obj, 1);
+
+        /* Notify CPP land of RX completion */
+        return SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
+    } else if (txc_int && (obj->serial.dmaOptionsTX.dmaChannel != -1) &&
+               serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel]) {
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            /* Clean up */
+            serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false;
+            serial_tx_abort_asynch_intern(obj, 1);
+            /* Notify CPP land of completion */
+            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
+        }else{
+            /* Clean up */
+            serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false;
+            serial_tx_abort_asynch_intern(obj, 1);
+            /* Notify CPP land of completion */
+            return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
+        }
+    } else {
+        /* Check the NVIC to see which interrupt we're running from
+         * Also make sure to prioritize RX */
+        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+            //Different method of checking tx vs rx for LEUART
+            if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) {
+                return serial_rx_irq_handler_asynch(obj);
+            } else if(LEUART_StatusGet(obj->serial.periph.leuart) & (LEUART_STATUS_TXBL | LEUART_STATUS_TXC)) {
+                return serial_tx_irq_handler_asynch(obj);
+            }
+        } else {
+            if(USART_IntGetEnabled(obj->serial.periph.uart) & (USART_IF_RXDATAV | USART_IF_RXOF | USART_IF_PERR | USART_IF_FERR)) {
+                return serial_rx_irq_handler_asynch(obj);
+            } else if(USART_StatusGet(obj->serial.periph.uart) & (USART_STATUS_TXBL | USART_STATUS_TXC)){
+                return serial_tx_irq_handler_asynch(obj);
+            }
+        }
+    }
+
+    // All should be done now
+    return 0;
+}
+
+/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and
+ *  flush TX hardware buffer if TX FIFO is used
+ *
+ * @param obj The serial object
+ */
+void serial_tx_abort_asynch(serial_t *obj)
+{
+    serial_tx_abort_asynch_intern(obj, 0);
+}
+
+static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
+{
+    // Transmitter should be disabled here but there are multiple issues
+    // making that quite difficult.
+    //
+    // - Disabling the transmitter when using DMA on platforms prior to
+    //   Pearl can cause the UART to leave the line low, generating a break
+    //   condition until the next transmission begins.
+    //
+    // - On (at least) Pearl, once TXC interrupt has fired it will take some time
+    //   (some tens of microsec) for TXC to be set in STATUS. If we turn off
+    //   the transmitter before this, bad things will happen.
+    //
+    // - On (at least) Pearl, when using TX DMA it is possible for the USART
+    //   status to be: TXENS TXBL TXIDLE = 1, TXBUFCNT = 0, but TXC = 0.
+    //
+    // All in all, the logic was so fragile it's best to leave it out.
+
+    /* Clean up */
+    switch(obj->serial.dmaOptionsTX.dmaUsageState) {
+        case DMA_USAGE_ALLOCATED:
+            /* stop DMA transfer */
+#ifndef LDMA_PRESENT
+            DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false);
+#else
+            LDMA_StopTransfer(obj->serial.dmaOptionsTX.dmaChannel);
+#endif
+            break;
+        case DMA_USAGE_TEMPORARY_ALLOCATED:
+            /* stop DMA transfer and release channel */
+#ifndef LDMA_PRESENT
+            DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false);
+#else
+            LDMA_StopTransfer(obj->serial.dmaOptionsTX.dmaChannel);
+#endif
+            dma_channel_free(obj->serial.dmaOptionsTX.dmaChannel);
+            obj->serial.dmaOptionsTX.dmaChannel = -1;
+            obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
+            break;
+        default:
+            break;
+    }
+
+    /* stop interrupting */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXBL);
+        LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXC);
+        LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC);
+    } else {
+        USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXBL);
+        USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXC);
+        USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
+    }
+
+    /* Say that we can stop using this emode */
+    if(unblock_sleep)
+        serial_unblock_sleep(obj);
+}
+
+
+static void serial_unblock_sleep(serial_t *obj)
+{
+    if( obj->serial.sleep_blocked > 0 ) {
+#ifdef LEUART_USING_LFXO
+        if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
+            unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
+        }else{
+            unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
+        }
+#else
+        unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
+#endif
+        obj->serial.sleep_blocked--;
+    }
+}
+
+static void serial_block_sleep(serial_t *obj)
+{
+    obj->serial.sleep_blocked++;
+#ifdef LEUART_USING_LFXO
+    if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
+        blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
+    }else{
+        blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
+    }
+#else
+    blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
+#endif
+}
+
+/** Abort the ongoing RX transaction It disables the enabled interrupt for RX and
+ *  flush RX hardware buffer if RX FIFO is used
+ *
+ * @param obj The serial object
+ */
+void serial_rx_abort_asynch(serial_t *obj)
+{
+    serial_rx_abort_asynch_intern(obj, 0);
+}
+
+static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
+{
+    /* Stop receiver */
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        obj->serial.periph.leuart->CMD = LEUART_CMD_RXDIS;
+        while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD);
+    } else {
+        obj->serial.periph.uart->CMD = USART_CMD_RXDIS;
+    }
+
+    /* Clean up */
+    switch(obj->serial.dmaOptionsRX.dmaUsageState) {
+        case DMA_USAGE_ALLOCATED:
+            /* stop DMA transfer */
+#ifndef LDMA_PRESENT
+            DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false);
+#else
+            LDMA_StopTransfer(obj->serial.dmaOptionsRX.dmaChannel);
+#endif
+            break;
+        case DMA_USAGE_TEMPORARY_ALLOCATED:
+            /* stop DMA transfer and release channel */
+#ifndef LDMA_PRESENT
+            DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false);
+#else
+            LDMA_StopTransfer(obj->serial.dmaOptionsRX.dmaChannel);
+#endif
+            dma_channel_free(obj->serial.dmaOptionsRX.dmaChannel);
+            obj->serial.dmaOptionsRX.dmaChannel = -1;
+            obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
+            break;
+        default:
+            /* stop interrupting */
+            if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+                LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_RXDATAV | LEUART_IEN_PERR | LEUART_IEN_FERR | LEUART_IEN_RXOF);
+            } else {
+                USART_IntDisable(obj->serial.periph.uart, USART_IEN_RXDATAV | USART_IEN_PERR | USART_IEN_FERR | USART_IEN_RXOF);
+            }
+            break;
+    }
+
+    /*clear all set interrupts*/
+    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
+        LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR | LEUART_IFC_FERR | LEUART_IFC_RXOF);
+    }else{
+        USART_IntClear(obj->serial.periph.uart,  USART_IFC_PERR | USART_IFC_FERR | USART_IFC_RXOF);
+    }
+
+    /* Say that we can stop using this emode */
+    if( unblock_sleep )
+        serial_unblock_sleep(obj);
+}
+
+#endif //DEVICE_SERIAL_ASYNCH
+#endif //DEVICE_SERIAL