mbed library sources. Supersedes mbed-src.

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

Revision:
189:f392fc9709a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/TARGET_GigaDevice/TARGET_GD32E10X/serial_api.c	Wed Feb 20 22:31:08 2019 +0000
@@ -0,0 +1,1072 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 GigaDevice Semiconductor Inc.
+ *
+ * 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 "mbed_assert.h"
+#include "serial_api.h"
+
+#if DEVICE_SERIAL
+
+#include "cmsis.h"
+#include "pinmap.h"
+#include "mbed_error.h"
+#include <string.h>
+#include "PeripheralPins.h"
+
+#define USART_NUM (5)
+
+static uint32_t serial_irq_ids[USART_NUM]   = {0};
+static rcu_periph_enum usart_clk[USART_NUM] = {RCU_USART0, RCU_USART1, RCU_USART2, RCU_UART3, RCU_UART4};
+static IRQn_Type usart_irq_n[USART_NUM]     = {USART0_IRQn, USART1_IRQn, USART2_IRQn, UART3_IRQn, UART4_IRQn};
+
+static uart_irq_handler irq_handler;
+
+int stdio_uart_inited = 0;
+serial_t stdio_uart;
+
+#if DEVICE_SERIAL_ASYNCH
+#define GET_SERIAL_S(obj) (&((obj)->serial))
+#else
+#define GET_SERIAL_S(obj) (obj)
+#endif /* DEVICE_SERIAL_ASYNCH */
+
+/** Initialize the USART peripheral.
+ *
+ * @param obj_s The serial object
+ */
+static void usart_init(struct serial_s *obj_s)
+{
+    if (obj_s->index >= USART_NUM) {
+        return;
+    }
+
+    /* USART configuration */
+    usart_deinit(obj_s->uart);
+    usart_word_length_set(obj_s->uart, obj_s->databits);
+    usart_baudrate_set(obj_s->uart, obj_s->baudrate);
+    usart_stop_bit_set(obj_s->uart, obj_s->stopbits);
+    usart_parity_config(obj_s->uart, obj_s->parity);
+#if DEVICE_SERIAL_FC
+    if (obj_s->hw_flow_ctl == USART_HWCONTROL_NONE) {
+        usart_hardware_flow_cts_config(obj_s->uart, USART_CTS_DISABLE);
+        usart_hardware_flow_rts_config(obj_s->uart, USART_RTS_DISABLE);
+    } else if (obj_s->hw_flow_ctl == USART_HWCONTROL_RTS) {
+        usart_hardware_flow_cts_config(obj_s->uart, USART_CTS_DISABLE);
+        usart_hardware_flow_rts_config(obj_s->uart, USART_RTS_ENABLE);
+    } else if (obj_s->hw_flow_ctl == USART_HWCONTROL_CTS) {
+        usart_hardware_flow_cts_config(obj_s->uart, USART_CTS_ENABLE);
+        usart_hardware_flow_rts_config(obj_s->uart, USART_RTS_DISABLE);
+    } else if (obj_s->hw_flow_ctl == USART_HWCONTROL_RTS_CTS) {
+        usart_hardware_flow_cts_config(obj_s->uart, USART_CTS_ENABLE);
+        usart_hardware_flow_rts_config(obj_s->uart, USART_RTS_ENABLE);
+    }
+#endif /* DEVICE_SERIAL_FC */
+    usart_receive_config(obj_s->uart, USART_RECEIVE_ENABLE);
+    usart_transmit_config(obj_s->uart, USART_TRANSMIT_ENABLE);
+    usart_enable(obj_s->uart);
+}
+
+/** Initialize the serial peripheral. It sets the default parameters for serial
+ *  peripheral, and configures its specifieds pins.
+ *
+ * @param obj The serial object
+ * @param tx  The TX pin name
+ * @param rx  The RX pin name
+ */
+void serial_init(serial_t *obj, PinName tx, PinName rx)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
+    UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
+
+    p_obj->uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
+    MBED_ASSERT(p_obj->uart != (UARTName)NC);
+
+    /* enable UART peripheral clock */
+    if (p_obj->uart == UART_0) {
+        p_obj->index = 0;
+        rcu_periph_clock_enable(usart_clk[p_obj->index]);
+    } else if (p_obj->uart == UART_1) {
+        p_obj->index = 1;
+        rcu_periph_clock_enable(usart_clk[p_obj->index]);
+    } else if (p_obj->uart == UART_2) {
+        p_obj->index = 2;
+        rcu_periph_clock_enable(usart_clk[p_obj->index]);
+    } else if (p_obj->uart == UART_3) {
+        p_obj->index = 3;
+        rcu_periph_clock_enable(usart_clk[p_obj->index]);
+    } else if (p_obj->uart == UART_4) {
+        p_obj->index = 4;
+        rcu_periph_clock_enable(usart_clk[p_obj->index]);
+    }
+
+    /* configurte the pins */
+    pinmap_pinout(tx, PinMap_UART_TX);
+    pinmap_pinout(rx, PinMap_UART_RX);
+
+    /* default UART parameters */
+    p_obj->baudrate    = 9600U;
+    p_obj->databits    = USART_WL_8BIT;
+    p_obj->stopbits    = USART_STB_1BIT;
+    p_obj->parity      = USART_PM_NONE;
+
+#if DEVICE_SERIAL_FC
+    p_obj->hw_flow_ctl = USART_HWCONTROL_NONE;
+#endif /* DEVICE_SERIAL_FC */
+
+    p_obj->pin_tx = tx;
+    p_obj->pin_rx = rx;
+
+    p_obj->tx_state = OP_STATE_BUSY;
+    p_obj->rx_state = OP_STATE_BUSY;
+
+    usart_init(p_obj);
+
+    p_obj->tx_state = OP_STATE_READY;
+    p_obj->rx_state = OP_STATE_READY;
+
+    if (p_obj->uart == STDIO_UART) {
+        stdio_uart_inited = 1;
+        memcpy(&stdio_uart, obj, sizeof(serial_t));
+    }
+}
+
+/** Release the serial peripheral, not currently invoked. It requires further
+ *  resource management.
+ *
+ * @param obj The serial object
+ */
+void serial_free(serial_t *obj)
+{
+    struct serial_s *p_obj     = GET_SERIAL_S(obj);
+    rcu_periph_enum rcu_periph = usart_clk[p_obj->index];
+
+    /* reset USART and disable clock */
+    usart_deinit(p_obj->uart);
+    rcu_periph_clock_disable(rcu_periph);
+
+    serial_irq_ids[p_obj->index] = 0;
+
+    /* reset the GPIO state */
+    pin_function(p_obj->pin_tx, MODE_IN_FLOATING);
+    pin_function(p_obj->pin_rx, MODE_IN_FLOATING);
+}
+
+/** Configure the baud rate
+ *
+ * @param obj      The serial object
+ * @param baudrate The baud rate to be configured
+ */
+void serial_baud(serial_t *obj, int baudrate)
+{
+    uint16_t uen_flag = 0U;
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    /* store the UEN flag */
+    uen_flag = USART_CTL0(p_obj->uart) & USART_CTL0_UEN;
+
+    /* disable the USART first */
+    usart_disable(p_obj->uart);
+
+    usart_baudrate_set(p_obj->uart, baudrate);
+
+    p_obj->baudrate = baudrate;
+
+    /* restore the UEN flag */
+    if (RESET != uen_flag) {
+        usart_enable(p_obj->uart);
+    }
+}
+
+/** Configure the format. Set the number of bits, parity and the number of stop bits
+ *
+ * @param obj       The serial object
+ * @param data_bits The number of data bits
+ * @param parity    The parity
+ * @param stop_bits The number of stop bits
+ */
+void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
+{
+    uint16_t uen_flag = 0U;
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    /* store the UEN flag */
+    uen_flag = USART_CTL0(p_obj->uart) & USART_CTL0_UEN;
+
+    /* disable the UART clock first */
+    usart_disable(p_obj->uart);
+
+    /* configurate the UART parity */
+    switch (parity) {
+        case ParityOdd:
+            p_obj->parity = USART_PM_ODD;
+            usart_parity_config(p_obj->uart, USART_PM_ODD);
+            break;
+
+        case ParityEven:
+            p_obj->parity = USART_PM_EVEN;
+            usart_parity_config(p_obj->uart, USART_PM_EVEN);
+            break;
+
+        case ParityForced0:
+        case ParityForced1:
+        default:
+            p_obj->parity = USART_PM_NONE;
+            usart_parity_config(p_obj->uart, USART_PM_NONE);
+            break;
+    }
+
+    if (p_obj->parity == USART_PM_NONE) {
+        if (data_bits == 9) {
+            usart_word_length_set(p_obj->uart, USART_WL_9BIT);
+        } else if (data_bits == 8) {
+            usart_word_length_set(p_obj->uart, USART_WL_8BIT);
+        } else if (data_bits == 7) {
+            return;
+        }
+    } else {
+        if (data_bits == 9) {
+            return;
+        } else if (data_bits == 8) {
+            usart_word_length_set(p_obj->uart, USART_WL_9BIT);
+        } else if (data_bits == 7) {
+            usart_word_length_set(p_obj->uart, USART_WL_8BIT);
+        }
+    }
+
+    if (stop_bits == 2) {
+        usart_stop_bit_set(p_obj->uart, USART_STB_2BIT);
+    } else {
+        usart_stop_bit_set(p_obj->uart, USART_STB_1BIT);
+    }
+
+    /* restore the UEN flag */
+    if (RESET != uen_flag) {
+        usart_enable(p_obj->uart);
+    }
+}
+
+/** The serial interrupt handler registration
+ *
+ * @param obj     The serial object
+ * @param handler The interrupt handler which will be invoked when the interrupt fires
+ * @param id      The SerialBase object
+ */
+void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    irq_handler = handler;
+    serial_irq_ids[p_obj->index] = id;
+}
+
+/** This function handles USART interrupt handler
+ *
+ * @param usart_index  The index of UART
+ * @param usart_periph The UART peripheral
+ */
+static void usart_irq(int usart_index, uint32_t usart_periph)
+{
+    if (serial_irq_ids[usart_index] != 0) {
+        if (usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_TC) != RESET) {
+            usart_interrupt_flag_clear(usart_periph, USART_INT_FLAG_TC);
+            irq_handler(serial_irq_ids[usart_index], TxIrq);
+        }
+
+        if (usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_RBNE) != RESET) {
+            usart_interrupt_flag_clear(usart_periph, USART_INT_FLAG_RBNE);
+            irq_handler(serial_irq_ids[usart_index], RxIrq);
+        }
+
+        if (usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_ERR_ORERR) != RESET) {
+            /* clear ORERR error flag by reading USART DATA register */
+            USART_DATA(usart_periph);
+        }
+
+        if (usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_ERR_NERR) != RESET) {
+            /* clear NERR error flag by reading USART DATA register */
+            USART_DATA(usart_periph);
+        }
+
+        if (usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_ERR_FERR) != RESET) {
+            /* clear FERR error flag by reading USART DATA register */
+            USART_DATA(usart_periph);
+        }
+
+        if (usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_PERR) != RESET) {
+            /* clear PERR error flag by reading USART DATA register */
+            USART_DATA(usart_periph);
+        }
+    }
+}
+
+/** This function handles USART0 interrupt handler
+ *
+ */
+static void usart0_irq(void)
+{
+    usart_irq(0, USART0);
+}
+
+/** This function handles USART1 interrupt handler
+ *
+ */
+static void usart1_irq(void)
+{
+    usart_irq(1, USART1);
+}
+
+/** This function handles USART2 interrupt handler
+ *
+ */
+static void usart2_irq(void)
+{
+    usart_irq(2, USART2);
+}
+
+/** This function handles USART3 interrupt handler
+ *
+ */
+static void uart3_irq(void)
+{
+    usart_irq(3, UART3);
+}
+
+/** This function handles USART4 interrupt handler
+ *
+ */
+static void uart4_irq(void)
+{
+    usart_irq(4, UART4);
+}
+
+/** Configure serial interrupt. This function is used for word-approach
+ *
+ * @param obj    The serial object
+ * @param irq    The serial IRQ type (RX or TX)
+ * @param enable Set to non-zero to enable events, or zero to disable them
+ */
+void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+    IRQn_Type irq_n = (IRQn_Type)0;
+    uint32_t vector = 0;
+
+    if (p_obj->uart == USART0) {
+        irq_n = USART0_IRQn;
+        vector = (uint32_t)&usart0_irq;
+    } else if (p_obj->uart == USART1) {
+        irq_n = USART1_IRQn;
+        vector = (uint32_t)&usart1_irq;
+    } else if (p_obj->uart == USART2) {
+        irq_n = USART2_IRQn;
+        vector = (uint32_t)&usart2_irq;
+    } else if (p_obj->uart == UART3) {
+        irq_n = UART3_IRQn;
+        vector = (uint32_t)&uart3_irq;
+    } else if (p_obj->uart == UART4) {
+        irq_n = UART4_IRQn;
+        vector = (uint32_t)&uart4_irq;
+    }
+
+    if (enable) {
+        if (irq == RxIrq) {
+            /* Rx IRQ */
+            usart_interrupt_enable(p_obj->uart, USART_INT_RBNE);
+        } else {
+            /* Tx IRQ */
+            usart_interrupt_enable(p_obj->uart, USART_INT_TBE);
+        }
+
+        NVIC_SetVector(irq_n, vector);
+        NVIC_EnableIRQ(irq_n);
+    } else {
+        if (irq == RxIrq) {
+            /* Rx IRQ */
+            usart_interrupt_disable(p_obj->uart, USART_INT_RBNE);
+        } else {
+            /* Tx IRQ */
+            usart_interrupt_disable(p_obj->uart, USART_INT_TBE);
+        }
+    }
+}
+
+/** Get character. This is a blocking call, waiting for a character
+ *
+ * @param obj The serial object
+ */
+int serial_getc(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    while (!serial_readable(obj));
+    return (int)(usart_data_receive(p_obj->uart) & BITS(0, 7 + (p_obj->databits >> 12)));
+}
+
+/** Send a character. This is a blocking call, waiting for a peripheral to be available
+ *  for writing
+ *
+ * @param obj The serial object
+ * @param c   The character to be sent
+ */
+void serial_putc(serial_t *obj, int c)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    while (!serial_writable(obj));
+    usart_data_transmit(p_obj->uart, (int)((c) & BITS(0, 7 + (p_obj->databits >> 12))));
+}
+
+/** Check if the serial peripheral is readable
+ *
+ * @param obj The serial object
+ * @return Non-zero value if a character can be read, 0 if nothing to read
+ */
+int serial_readable(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    return (usart_flag_get(p_obj->uart, USART_FLAG_RBNE) != RESET) ? 1 : 0;
+}
+
+/** Check if the serial peripheral is writable
+ *
+ * @param obj The serial object
+ * @return Non-zero value if a character can be written, 0 otherwise.
+ */
+int serial_writable(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    return (usart_flag_get(p_obj->uart, USART_FLAG_TBE) != RESET) ? 1 : 0;
+}
+
+/** Clear the serial peripheral
+ *
+ * @param obj The serial object
+ */
+void serial_clear(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    p_obj->tx_count = 0U;
+    p_obj->rx_count = 0U;
+}
+
+/** Set the break
+ *
+ * @param obj The serial object
+ */
+void serial_break_set(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    usart_send_break(p_obj->uart);
+}
+
+/** Clear the break
+ *
+ * @param obj The serial object
+ */
+void serial_break_clear(serial_t *obj)
+{
+    /* do nothing */
+}
+
+/** Configure the TX pin for UART function.
+ *
+ * @param tx The pin name used for TX
+ */
+void serial_pinout_tx(PinName tx)
+{
+    pinmap_pinout(tx, PinMap_UART_TX);
+}
+
+#if DEVICE_SERIAL_ASYNCH
+/**
+ * Enable the serial events
+ *
+ * @param obj   The serial object
+ * @param event The events to be configured
+ */
+static void serial_event_enable(serial_t *obj, int event)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    p_obj->events |= event;
+
+}
+
+/**
+ * Disable the serial events
+ *
+ * @param obj   The serial object
+ * @param event The events to be configured
+ */
+static void serial_event_disable(serial_t *obj, int event)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    p_obj->events &= ~event;
+}
+
+/**
+ * Preprocess the USART tx interrupt
+ *
+ * @param obj_s The serial object
+ * @param pData Pointer to tx buffer
+ * @param Size  Size of tx buffer
+ * @return Returns the status
+ */
+static gd_status_enum usart_tx_interrupt_preprocess(struct serial_s *obj_s, uint8_t *pData, uint16_t Size)
+{
+    if (obj_s->tx_state == OP_STATE_READY) {
+        if ((pData == NULL) || (Size == 0U)) {
+            return GD_ERROR;
+        }
+
+        obj_s->tx_buffer_ptr = pData;
+        obj_s->tx_count      = Size;
+        obj_s->error_code    = USART_ERROR_CODE_NONE;
+        obj_s->tx_state      = OP_STATE_BUSY_TX;
+
+        usart_interrupt_enable(obj_s->uart, USART_INT_TBE);
+
+        return GD_OK;
+    } else {
+        return GD_BUSY;
+    }
+}
+
+/**
+ * Preprocess the USART rx interrupt
+ *
+ * @param obj_s The serial object
+ * @param pData Pointer to rx buffer
+ * @param Size  Size of rx buffer
+ * @return Returns the status
+ */
+static gd_status_enum usart_rx_interrupt_preprocess(struct serial_s *obj_s, uint8_t *pData, uint16_t Size)
+{
+    if (obj_s->rx_state == OP_STATE_READY) {
+        if ((pData == NULL) || (Size == 0U)) {
+            return GD_ERROR;
+        }
+
+        obj_s->rx_buffer_ptr = pData;
+        obj_s->rx_size       = Size;
+        obj_s->rx_count      = Size;
+        obj_s->error_code    = USART_ERROR_CODE_NONE;
+        obj_s->rx_state      = OP_STATE_BUSY_RX;
+
+        usart_interrupt_enable(obj_s->uart, USART_INT_PERR);
+        usart_interrupt_enable(obj_s->uart, USART_INT_ERR);
+        usart_interrupt_enable(obj_s->uart, USART_INT_RBNE);
+
+        return GD_OK;
+    } else {
+        return GD_BUSY;
+    }
+}
+
+/** Begin asynchronous TX transfer. The used buffer is specified in the serial object,
+ *  tx_buff
+ *
+ * @param obj       The serial object
+ * @param tx        The transmit buffer
+ * @param tx_length The number of bytes to transmit
+ * @param tx_width  Deprecated argument
+ * @param handler   The serial handler
+ * @param event     The logical OR of events to be registered
+ * @param hint      A suggestion for how to use DMA with this transfer
+ * @return Returns number of data transfered, otherwise returns 0
+ */
+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)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+    IRQn_Type irq = usart_irq_n[p_obj->index];
+
+    if ((tx_length == 0) || (tx_width != 8)) {
+        return 0;
+    }
+
+    if (serial_tx_active(obj)) {
+        /* some transmit is in progress */
+        return 0;
+    }
+
+    obj->tx_buff.buffer = (void *)tx;
+    obj->tx_buff.length = tx_length;
+    obj->tx_buff.pos = 0;
+
+    /* disable all events first */
+    serial_event_disable(obj, SERIAL_EVENT_TX_ALL);
+    /* enable the specific event */
+    serial_event_enable(obj, event);
+
+    /* enable interrupt */
+    /* clear pending IRQ */
+    NVIC_ClearPendingIRQ(irq);
+    /* disable the IRQ first */
+    NVIC_DisableIRQ(irq);
+    /* set the priority and vector */
+    NVIC_SetPriority(irq, 1);
+    NVIC_SetVector(irq, (uint32_t)handler);
+    /* enable IRQ */
+    NVIC_EnableIRQ(irq);
+
+    if (usart_tx_interrupt_preprocess(p_obj, (uint8_t *)tx, tx_length) != GD_OK) {
+        return 0;
+    }
+
+    return tx_length;
+}
+
+/** 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 rx         The receive buffer
+ * @param rx_length  The number of bytes to receive
+ * @param rx_width   Deprecated argument
+ * @param handler    The serial handler
+ * @param event      The logical OR of events to be registered
+ * @param handler    The serial handler
+ * @param char_match A character in range 0-254 to be matched
+ * @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)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+    IRQn_Type irq = usart_irq_n[p_obj->index];
+
+    if ((rx_length == 0) || (rx_width != 8)) {
+        return;
+    }
+
+    /* disable all events first */
+    serial_event_disable(obj, SERIAL_EVENT_RX_ALL);
+    /* enable the specific event */
+    serial_event_enable(obj, event);
+
+    obj->char_match = char_match;
+
+    if (serial_rx_active(obj)) {
+        /* some reception is in progress */
+        return;
+    }
+
+    obj->rx_buff.buffer = rx;
+    obj->rx_buff.length = rx_length;
+    obj->rx_buff.pos = 0;
+
+    /* enable interrupt */
+    /* clear pending IRQ */
+    NVIC_ClearPendingIRQ(irq);
+    /* disable the IRQ first */
+    NVIC_DisableIRQ(irq);
+    /* set the priority(higher than Tx) and vector */
+    NVIC_SetPriority(irq, 0);
+    NVIC_SetVector(irq, (uint32_t)handler);
+    /* enable IRQ */
+    NVIC_EnableIRQ(irq);
+
+    usart_rx_interrupt_preprocess(p_obj, (uint8_t *)rx, rx_length);
+}
+
+/** Attempts to determine if the serial peripheral is already in use for TX
+ *
+ * @param obj The serial object
+ * @return Non-zero if the RX transaction is ongoing, 0 otherwise
+ */
+uint8_t serial_tx_active(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    return ((p_obj->tx_state == OP_STATE_BUSY_TX) ? 1 : 0);
+}
+
+/** 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)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    return ((p_obj->rx_state == OP_STATE_BUSY_RX) ? 1 : 0);
+}
+
+/** Handle the serial rx interrupt
+ *
+ * @param obj_s The serial object
+ * @return Returns the status
+ */
+static gd_status_enum usart_rx_interrupt(struct serial_s *obj_s)
+{
+    uint16_t *temp;
+
+    if (obj_s->rx_state == OP_STATE_BUSY_RX) {
+        if (obj_s->databits == USART_WL_9BIT) {
+            temp = (uint16_t *) obj_s->rx_buffer_ptr;
+            if (obj_s->parity == USART_PM_NONE) {
+                /* 9-bit data, none parity bit */
+                *temp = (uint16_t)(USART_DATA(obj_s->uart) & (uint16_t)0x01FF);
+                obj_s->rx_buffer_ptr += 2U;
+            } else {
+                /* 9-bit data, with parity bit */
+                *temp = (uint16_t)(USART_DATA(obj_s->uart) & (uint16_t)0x00FF);
+                obj_s->rx_buffer_ptr += 1U;
+            }
+        } else {
+            if (obj_s->parity == USART_PM_NONE) {
+                /* 8-bit data, none parity bit */
+                *obj_s->rx_buffer_ptr++ = (uint8_t)(USART_DATA(obj_s->uart) & (uint8_t)0x00FF);
+            } else {
+                /* 8-bit data, with parity bit */
+                *obj_s->rx_buffer_ptr++ = (uint8_t)(USART_DATA(obj_s->uart) & (uint8_t)0x007F);
+            }
+        }
+
+        if (--obj_s->rx_count == 0U) {
+            usart_interrupt_disable(obj_s->uart, USART_INT_RBNE);
+            usart_interrupt_disable(obj_s->uart, USART_INT_PERR);
+            usart_interrupt_disable(obj_s->uart, USART_INT_ERR);
+
+            obj_s->rx_state = OP_STATE_READY;
+        }
+
+        return GD_OK;
+    } else {
+        return GD_BUSY;
+    }
+}
+
+/** Handle the serial tx interrupt
+ *
+ * @param obj_s The serial object
+ * @return Returns the status
+ */
+static gd_status_enum usart_tx_interrupt(struct serial_s *obj_s)
+{
+    uint16_t *temp;
+
+    if (obj_s->tx_state == OP_STATE_BUSY_TX) {
+        if (obj_s->databits == USART_WL_9BIT) {
+            temp = (uint16_t *) obj_s->tx_buffer_ptr;
+            USART_DATA(obj_s->uart) = (uint16_t)(*temp & (uint16_t)0x01FF);
+            if (obj_s->parity == USART_PM_NONE) {
+                obj_s->tx_buffer_ptr += 2U;
+            } else {
+                obj_s->tx_buffer_ptr += 1U;
+            }
+        } else {
+            USART_DATA(obj_s->uart) = (uint8_t)(*obj_s->tx_buffer_ptr++ & (uint8_t)0x00FF);
+        }
+
+        if (--obj_s->tx_count == 0U) {
+            /* disable USART_INT_TBE interrupt */
+            usart_interrupt_disable(obj_s->uart, USART_INT_TBE);
+
+            /* enable USART_INT_TC interrupt */
+            usart_interrupt_enable(obj_s->uart, USART_INT_TC);
+        }
+
+        return GD_OK;
+    } else {
+        return GD_BUSY;
+    }
+}
+
+/** Handle the serial tx complete interrupt
+ *
+ * @param obj_s The serial object
+ */
+static void usart_tx_complete_interrupt(struct serial_s *obj_s)
+{
+    usart_interrupt_disable(obj_s->uart, USART_INT_TC);
+
+    obj_s->tx_state = OP_STATE_READY;
+}
+
+/** Handle all the serial interrupt request
+ *
+ * @param obj_s The serial object
+ */
+static void usart_irq_handler(struct serial_s *obj_s)
+{
+    uint32_t err_flags = 0U;
+
+    /* no error occurs */
+    err_flags = (USART_STAT0(obj_s->uart) & (uint32_t)(USART_FLAG_PERR | USART_FLAG_FERR | USART_FLAG_ORERR | USART_FLAG_NERR));
+    if (err_flags == RESET) {
+        /* check whether USART is in receiver mode or not */
+        if (usart_interrupt_flag_get(obj_s->uart, USART_INT_FLAG_RBNE) != RESET) {
+            usart_rx_interrupt(obj_s);
+
+            return;
+        }
+    }
+
+    if (usart_interrupt_flag_get(obj_s->uart, USART_INT_FLAG_TBE) != RESET) {
+        usart_tx_interrupt(obj_s);
+        return;
+    }
+
+    if (usart_interrupt_flag_get(obj_s->uart, USART_INT_FLAG_TC) != RESET) {
+        usart_tx_complete_interrupt(obj_s);
+        return;
+    }
+}
+
+/** The asynchronous TX and RX handler.
+ *
+ * @param obj The serial object
+ * @return Returns event flags if an RX transfer termination condition was met; otherwise returns 0
+ */
+int serial_irq_handler_asynch(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+    volatile uint8_t i = 0;
+    volatile int return_val = 0;
+    uint8_t *p_buf = (uint8_t *)(obj->rx_buff.buffer);
+
+    if (usart_interrupt_flag_get(p_obj->uart, USART_INT_FLAG_PERR) != RESET) {
+        /* clear PERR error flag by reading USART DATA register */
+        USART_DATA(p_obj->uart);
+
+        return_val |= (SERIAL_EVENT_RX_PARITY_ERROR & p_obj->events);
+        p_obj->error_code |= USART_ERROR_CODE_PERR;
+    }
+
+    if (usart_interrupt_flag_get(p_obj->uart, USART_INT_FLAG_ERR_FERR) != RESET) {
+        /* clear FERR error flag by reading USART DATA register */
+        USART_DATA(p_obj->uart);
+
+        return_val |= (SERIAL_EVENT_RX_FRAMING_ERROR & p_obj->events);
+        p_obj->error_code |= USART_ERROR_CODE_FERR;
+    }
+
+    if (usart_interrupt_flag_get(p_obj->uart, USART_INT_FLAG_ERR_ORERR) != RESET) {
+        /* clear ORERR error flag by reading USART DATA register */
+        USART_DATA(p_obj->uart);
+
+        return_val |= (SERIAL_EVENT_RX_OVERRUN_ERROR & p_obj->events);
+        p_obj->error_code |= USART_ERROR_CODE_ORERR;
+    }
+
+    if (return_val & (SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR |
+                      SERIAL_EVENT_RX_OVERRUN_ERROR)) {
+        return return_val;
+    }
+
+    if (usart_interrupt_flag_get(p_obj->uart, USART_INT_FLAG_TC) != RESET) {
+        if ((p_obj->events & SERIAL_EVENT_TX_COMPLETE) != 0) {
+            return_val |= (SERIAL_EVENT_TX_COMPLETE & p_obj->events);
+        }
+    }
+
+    usart_irq_handler(p_obj);
+
+    if (p_obj->rx_size != 0) {
+        obj->rx_buff.pos = p_obj->rx_size - p_obj->rx_count;
+    }
+
+    if ((p_obj->rx_count == 0) && (obj->rx_buff.pos >= (obj->rx_buff.length - 1))) {
+        return_val |= (SERIAL_EVENT_RX_COMPLETE & p_obj->events);
+    }
+
+    if (p_obj->events & SERIAL_EVENT_RX_CHARACTER_MATCH) {
+        if (p_buf != NULL) {
+            for (i = 0; i < obj->rx_buff.pos; i++) {
+                if (p_buf[i] == obj->char_match) {
+                    obj->rx_buff.pos = i;
+                    return_val |= (SERIAL_EVENT_RX_CHARACTER_MATCH & p_obj->events);
+                    serial_rx_abort_asynch(obj);
+                    break;
+                }
+            }
+        }
+    }
+
+    return return_val;
+}
+
+/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and
+ *  flushes the TX hardware buffer if TX FIFO is used
+ *
+ * @param obj The serial object
+ */
+void serial_tx_abort_asynch(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    usart_interrupt_disable(p_obj->uart, USART_INT_TC);
+    usart_interrupt_disable(p_obj->uart, USART_INT_TBE);
+
+    usart_flag_clear(p_obj->uart, USART_FLAG_TC);
+
+    p_obj->tx_count = 0;
+    p_obj->tx_state = OP_STATE_READY;
+}
+
+/** Abort the ongoing RX transaction. It disables the enabled interrupt for RX and
+ *  flushes the RX hardware buffer if RX FIFO is used
+ *
+ * @param obj The serial object
+ */
+void serial_rx_abort_asynch(serial_t *obj)
+{
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    /* disable interrupts */
+    usart_interrupt_disable(p_obj->uart, USART_INT_RBNE);
+    usart_interrupt_disable(p_obj->uart, USART_INT_PERR);
+    usart_interrupt_disable(p_obj->uart, USART_INT_ERR);
+
+    /* clear USART_FLAG_RBNE flag */
+    usart_flag_clear(p_obj->uart, USART_FLAG_RBNE);
+
+    /* clear errors flag by reading USART STATx register and then USART DATA register */
+    usart_flag_get(p_obj->uart, USART_FLAG_PERR);
+    usart_flag_get(p_obj->uart, USART_FLAG_FERR);
+    usart_flag_get(p_obj->uart, USART_FLAG_ORERR);
+    USART_DATA(p_obj->uart);
+
+    /* reset rx transfer count */
+    p_obj->rx_count = 0;
+
+    /* reset rx state */
+    p_obj->rx_state = OP_STATE_READY;
+}
+
+#endif /* DEVICE_SERIAL_ASYNCH */
+
+#if DEVICE_SERIAL_FC
+/** Configure the serial for the flow control. It sets flow control in the hardware
+ *  if a serial peripheral supports it, otherwise software emulation is used.
+ *
+ * @param obj    The serial object
+ * @param type   The type of the flow control. Look at the available FlowControl types.
+ * @param rxflow The TX pin name
+ * @param txflow The RX pin name
+ */
+void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
+{
+    uint16_t uen_flag = 0U;
+    struct serial_s *p_obj = GET_SERIAL_S(obj);
+
+    /* store the UEN flag */
+    uen_flag = USART_CTL0(p_obj->uart) & USART_CTL0_UEN;
+
+    UARTName uart_rts = (UARTName)pinmap_peripheral(rxflow, PinMap_UART_RTS);
+    UARTName uart_cts = (UARTName)pinmap_peripheral(txflow, PinMap_UART_CTS);
+
+    p_obj->uart = (UARTName)pinmap_merge(uart_cts, uart_rts);
+    MBED_ASSERT(p_obj->uart != (UARTName)NC);
+
+    /* disable USART to modify CTS/RTS configuration */
+    usart_disable(p_obj->uart);
+
+    if (type == FlowControlNone) {
+        p_obj->hw_flow_ctl = USART_HWCONTROL_NONE;
+        usart_hardware_flow_cts_config(p_obj->uart, USART_CTS_DISABLE);
+        usart_hardware_flow_rts_config(p_obj->uart, USART_RTS_DISABLE);
+    }
+
+    if (type == FlowControlRTS) {
+        MBED_ASSERT(uart_rts != (UARTName)NC);
+        p_obj->hw_flow_ctl = USART_HWCONTROL_RTS;
+        p_obj->pin_rts = rxflow;
+        pinmap_pinout(rxflow, PinMap_UART_RTS);
+        usart_hardware_flow_cts_config(p_obj->uart, USART_CTS_DISABLE);
+        usart_hardware_flow_rts_config(p_obj->uart, USART_RTS_ENABLE);
+    }
+
+    if (type == FlowControlCTS) {
+        MBED_ASSERT(uart_cts != (UARTName)NC);
+        p_obj->hw_flow_ctl = USART_HWCONTROL_CTS;
+        p_obj->pin_cts = txflow;
+        pinmap_pinout(txflow, PinMap_UART_CTS);
+        usart_hardware_flow_rts_config(p_obj->uart, USART_RTS_DISABLE);
+        usart_hardware_flow_cts_config(p_obj->uart, USART_CTS_ENABLE);
+    }
+
+    if (type == FlowControlRTSCTS) {
+        MBED_ASSERT(uart_rts != (UARTName)NC);
+        MBED_ASSERT(uart_cts != (UARTName)NC);
+        p_obj->hw_flow_ctl = USART_HWCONTROL_RTS_CTS;
+        p_obj->pin_rts = rxflow;
+        p_obj->pin_cts = txflow;
+        pinmap_pinout(txflow, PinMap_UART_CTS);
+        pinmap_pinout(rxflow, PinMap_UART_RTS);
+        usart_hardware_flow_cts_config(p_obj->uart, USART_CTS_ENABLE);
+        usart_hardware_flow_rts_config(p_obj->uart, USART_RTS_ENABLE);
+    }
+
+    /* restore the UEN flag */
+    if (RESET != uen_flag) {
+        usart_enable(p_obj->uart);
+    }
+}
+
+#endif /* DEVICE_SERIAL_FC */
+
+#if DEVICE_SLEEP
+/** Check whether the serial is in busy state
+ *
+ * @return 0: all the serial is free to use, 1: some serial is in busy in transfer
+ */
+int serial_busy_state_check(void)
+{
+#if defined(USART0)
+    if ((USART_CTL0(USART0) & USART_CTL0_UEN) && !(USART_STAT0(USART0) & USART_STAT0_TC)) {
+        return 1;
+    }
+#endif
+
+#if defined(USART1)
+    if ((USART_CTL0(USART1) & USART_CTL0_UEN) && !(USART_STAT0(USART1) & USART_STAT0_TC)) {
+        return 1;
+    }
+#endif
+
+#if defined(USART2)
+    if ((USART_CTL0(USART2) & USART_CTL0_UEN) && !(USART_STAT0(USART2) & USART_STAT0_TC)) {
+        return 1;
+    }
+#endif
+
+#if defined(UART3)
+    if ((USART_CTL0(UART3) & USART_CTL0_UEN) && !(USART_STAT0(UART3) & USART_STAT0_TC)) {
+        return 1;
+    }
+#endif
+
+#if defined(UART4)
+    if ((USART_CTL0(UART4) & USART_CTL0_UEN) && !(USART_STAT0(UART4) & USART_STAT0_TC)) {
+        return 1;
+    }
+#endif
+
+    /* no serial is in busy state */
+    return 0;
+}
+#endif /* DEVICE_SLEEP */
+
+#endif /* DEVICE_SERIAL */