mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c

Committer:
mbed_official
Date:
2015-09-25
Revision:
627:4fa1328d9c60
Parent:
563:536c9fb088a0

File content as of revision 627:4fa1328d9c60:

/***************************************************************************//**
 * @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 <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[SERIAL_NUM_UARTS] = { 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, int, SerialIrq);
uint8_t serial_get_index(serial_t *obj);
void serial_enable(serial_t *obj, uint8_t enable);
void serial_enable_pins(serial_t *obj, uint8_t enable);
IRQn_Type serial_get_rx_irq_index(serial_t *obj);
IRQn_Type serial_get_tx_irq_index(serial_t *obj);
CMU_Clock_TypeDef serial_get_clock(serial_t *obj);

/* ISRs for RX and TX events */
#ifdef UART0
static void uart0_rx_irq() { uart_irq(UART_0, 0, RxIrq); }
static void uart0_tx_irq() { uart_irq(UART_0, 0, TxIrq); USART_IntClear((USART_TypeDef*)UART_0, USART_IFC_TXC);}
#endif
#ifdef UART1
static void uart1_rx_irq() { uart_irq(UART_1, 1, RxIrq); }
static void uart1_tx_irq() { uart_irq(UART_1, 1, TxIrq); USART_IntClear((USART_TypeDef*)UART_1, USART_IFC_TXC);}
#endif
#ifdef USART0
static void usart0_rx_irq() { uart_irq(USART_0, 2, RxIrq); }
static void usart0_tx_irq() { uart_irq(USART_0, 2, TxIrq); USART_IntClear((USART_TypeDef*)USART_0, USART_IFC_TXC);}
#endif
#ifdef USART1
static void usart1_rx_irq() { uart_irq(USART_1, 3, RxIrq); }
static void usart1_tx_irq() { uart_irq(USART_1, 3, TxIrq); USART_IntClear((USART_TypeDef*)USART_1, USART_IFC_TXC);}
#endif
#ifdef USART2
static void usart2_rx_irq() { uart_irq(USART_2, 4, RxIrq); }
static void usart2_tx_irq() { uart_irq(USART_2, 4, 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_IFC_PERR | LEUART_IF_RXOF)) {
        uart_irq(LEUART_0, 5, RxIrq);
    } else {
        uart_irq(LEUART_0, 5, TxIrq);
    }
}
#endif
#ifdef LEUART1
static void leuart1_irq()
{
    if(LEUART_IntGetEnabled(LEUART1) && (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IFC_PERR | LEUART_IF_RXOF)) {
        uart_irq(LEUART_1, 6, RxIrq);
    } else {
        uart_irq(LEUART_1, 6, TxIrq);
    }
}
#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)
{
    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
        LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;

        init.enable = leuartDisable;
        init.baudrate = 9600;
        init.databits = leuartDatabits8;
        init.parity = leuartNoParity;
        init.stopbits = leuartStopbits1;
#ifdef LEUART_USING_LFXO
        init.refFreq = LEUART_LF_REF_FREQ;
#else
        init.refFreq = LEUART_REF_FREQ;
#endif
        LEUART_Init(obj->serial.periph.leuart, &init);
    } else {
        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;

        init.enable = usartDisable;
        init.baudrate = 9600;
        init.oversampling = usartOVS16;
        init.databits = usartDatabits8;
        init.parity = usartNoParity;
        init.stopbits = usartStopbits1;

        /* Determine the reference clock, because the correct clock is not set up at init time */
        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 object
* @return internal index of U(S)ART peripheral
*/
inline uint8_t serial_get_index(serial_t *obj)
{
    switch ((uint32_t)obj->serial.periph.uart) {
#ifdef UART0
        case UART_0:
            return 0;
#endif
#ifdef UART1
        case UART_1:
            return 1;
#endif
#ifdef USART0
        case USART_0:
            return 2;
#endif
#ifdef USART1
        case USART_1:
            return 3;
#endif
#ifdef USART2
        case USART_2:
            return 4;
#endif
#ifdef LEUART0
        case LEUART_0:
            return 5;
#endif
#ifdef LEUART1
        case LEUART_1:
            return 6;
#endif
    }
    return 0;
}

/**
* 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
*/
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
*/
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);
    /* 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);

    /* Store pins in object for easy disabling in serial_free() */
    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
    }
}

void serial_enable_pins(serial_t *obj, uint8_t enable)
{
    if (enable) {
        /* Configure GPIO pins*/
        pin_mode(obj->serial.rx_pin, Input);
        /* 0x10 sets DOUT. Prevents false start. */
        pin_mode(obj->serial.tx_pin, PushPull | 0x10);
    } else {
        pin_mode(obj->serial.rx_pin, Disabled);
        pin_mode(obj->serial.tx_pin, Disabled);
    }
}

void serial_init(serial_t *obj, PinName tx, PinName rx)
{
    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_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
        CMU_ClockEnable(cmuClock_CORELE, true);
#else
        //set to use high-speed clock
        CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
#endif
    }

    CMU_ClockEnable(serial_get_clock(obj), true);

    /* Configure UART for async operation */
    uart_init(obj);

    /* 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 )) {
        serial_baud(obj, 115200);
    }

    /* Enable pins for UART at correct location */
    if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
        obj->serial.periph.leuart->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
        obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
        obj->serial.periph.leuart->CTRL |= LEUART_CTRL_RXDMAWU | LEUART_CTRL_TXDMAWU;
    } else {
        obj->serial.periph.uart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
        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 (obj->serial.periph.uart == (USART_TypeDef*)STDIO_UART ) {
        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_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)) {
#ifdef LEUART_USING_LFXO

        /* check if baudrate is within allowed range */
        MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 7));

        if(baudrate > (LEUART_LF_REF_FREQ >> 1)){
            /* 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);
            uint8_t divisor = 1;

            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;
            }
            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
    } else {
        USART_BaudrateAsyncSet(obj->serial.periph.uart, REFERENCE_FREQUENCY, (uint32_t)baudrate, usartOVS16);
    }
}

/**
 * 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 */
        obj->serial.periph.leuart->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);

        /* 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 */
        obj->serial.periph.uart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);

        /* 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, int index, SerialIrq irq)
{
    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));
    } else {
        USART_Tx(obj->serial.periph.uart, (uint8_t)(c));
    }
}

/**
 * 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)();
    }
}

/******************************************
* 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);
    }


}

/******************************************
* 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;
    }
}

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 = cb;

        // Set up configuration structure
        channelConfig.dstInc = dmaDataIncNone;
        channelConfig.srcInc = dmaDataInc1;
        channelConfig.size = dmaDataSize1;
        channelConfig.arbRate = dmaArbitrate1;
        channelConfig.hprot = 0;

        DMA_CfgDescr(obj->serial.dmaOptionsTX.dmaChannel, true, &channelConfig);
        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
            // Activate TX
            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_RXEN | LEUART_CMD_CLEARRX;
            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);
        }
    }
}

/************************************************************************************
 *          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
#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

    // 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_TXEN | LEUART_CMD_CLEARTX;
            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
#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

    // 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_RXEN | LEUART_CMD_CLEARRX;
            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)
{
    switch(obj->serial.dmaOptionsTX.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 */
            return(DMA_ChannelEnabled(obj->serial.dmaOptionsTX.dmaChannel));
        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_TXBL)) ? true : false;
            } else {
                return (obj->serial.periph.uart->IEN & (USART_IEN_TXBL)) ? 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 */
            return(DMA_ChannelEnabled(obj->serial.dmaOptionsRX.dmaChannel));
        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);
            }
        }else if (obj->serial.periph.leuart->IF & LEUART_IF_TXC){
            /* Last byte has been successfully transmitted. Stop the procedure */
            serial_tx_abort_asynch(obj);
            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(obj);
            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(obj);
            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(obj);
            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(obj);
            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(obj);
                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(obj);
                        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(obj);
            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(obj);
            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(obj);
            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(obj);
                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(obj);
                        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)
{
    /* First, check if we're running in DMA mode */
    if(serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel]) {
        /* Clean up */
        serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel] = false;
        serial_rx_abort_asynch(obj);

        /* Notify CPP land of RX completion */
        return SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
    } else if (serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel]) {
        if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
            if(obj->serial.periph.leuart->IEN & LEUART_IEN_TXC){
                LEUART_IntDisable(obj->serial.periph.leuart,LEUART_IEN_TXC);
                /* Clean up */
                serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false;
                serial_tx_abort_asynch(obj);
                /* Notify CPP land of completion */
                return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
            }else{
                LEUART_IntEnable(obj->serial.periph.leuart,LEUART_IEN_TXC);
            }
        }else{
            if(obj->serial.periph.uart->IEN & USART_IEN_TXC){
                USART_IntDisable(obj->serial.periph.leuart,USART_IEN_TXC);
                /* Clean up */
                serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false;
                serial_tx_abort_asynch(obj);
                /* Notify CPP land of completion */
                return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
            }else{
                USART_IntEnable(obj->serial.periph.leuart,USART_IEN_TXC);
            }
        }
    } 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)
{
    /* Stop transmitter */
    //obj->serial.periph.uart->CMD |= USART_CMD_TXDIS;

    /* Clean up */
    switch(obj->serial.dmaOptionsTX.dmaUsageState) {
        case DMA_USAGE_ALLOCATED:
            /* stop DMA transfer */
            DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false);
            break;
        case DMA_USAGE_TEMPORARY_ALLOCATED:
            /* stop DMA transfer and release channel */
            DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false);
            dma_channel_free(obj->serial.dmaOptionsTX.dmaChannel);
            obj->serial.dmaOptionsTX.dmaChannel = -1;
            obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
            break;
        default:
            /* stop interrupting */
            if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
                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_TXC);
                USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC);
            }
            break;
    }

    /* Say that we can stop using this emode */
#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
}

/** 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)
{
    /* Stop receiver */
    obj->serial.periph.uart->CMD |= USART_CMD_RXDIS;

    /* Clean up */
    switch(obj->serial.dmaOptionsRX.dmaUsageState) {
        case DMA_USAGE_ALLOCATED:
            /* stop DMA transfer */
            DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false);
            break;
        case DMA_USAGE_TEMPORARY_ALLOCATED:
            /* stop DMA transfer and release channel */
            DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false);
            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 */
#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
}

#endif //DEVICE_SERIAL_ASYNCH
#endif //DEVICE_SERIAL