mbed library sources. Supersedes mbed-src.

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

Revision:
188:bcfe06ba3d64
Child:
189:f392fc9709a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/TARGET_Cypress/TARGET_PSOC6/serial_api.c	Thu Nov 08 11:46:34 2018 +0000
@@ -0,0 +1,820 @@
+/*
+ * mbed Microcontroller Library
+ * Copyright (c) 2017-2018 Future Electronics
+ *
+ * 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.
+ */
+
+#if DEVICE_SERIAL
+
+#include <string.h>
+
+#include "cmsis.h"
+#include "mbed_assert.h"
+#include "mbed_error.h"
+#include "PeripheralPins.h"
+#include "pinmap.h"
+#include "serial_api.h"
+#include "psoc6_utils.h"
+
+#include "drivers/peripheral/sysclk/cy_sysclk.h"
+#include "drivers/peripheral/gpio/cy_gpio.h"
+#include "drivers/peripheral/scb/cy_scb_uart.h"
+#include "drivers/peripheral/sysint/cy_sysint.h"
+
+#define UART_OVERSAMPLE                 12
+#define UART_DEFAULT_BAUDRATE           115200
+#define NUM_SERIAL_PORTS                8
+#define SERIAL_DEFAULT_IRQ_PRIORITY     3
+
+typedef struct serial_s serial_obj_t;
+#if DEVICE_SERIAL_ASYNCH
+#define OBJ_P(in)     (&(in->serial))
+#else
+#define OBJ_P(in)     (in)
+#endif
+
+/*
+ * NOTE: Cypress PDL high level API implementation of USART doe not
+ * align well with Mbed interface for interrupt-driven serial I/O.
+ * For this reason only low level PDL API is used here.
+ */
+
+
+static const cy_stc_scb_uart_config_t default_uart_config = {
+    .uartMode                   = CY_SCB_UART_STANDARD,
+    .enableMutliProcessorMode   = false,
+    .smartCardRetryOnNack       = false,
+    .irdaInvertRx               = false,
+    .irdaEnableLowPowerReceiver = false,
+
+    .oversample                 = UART_OVERSAMPLE,
+
+    .enableMsbFirst             = false,
+    .dataWidth                  = 8UL,
+    .parity                     = CY_SCB_UART_PARITY_NONE,
+    .stopBits                   = CY_SCB_UART_STOP_BITS_1,
+    .enableInputFilter          = false,
+    .breakWidth                 = 11UL,
+    .dropOnFrameError           = false,
+    .dropOnParityError          = false,
+
+    .receiverAddress            = 0x0UL,
+    .receiverAddressMask        = 0x0UL,
+    .acceptAddrInFifo           = false,
+
+    .enableCts                  = false,
+    .ctsPolarity                = CY_SCB_UART_ACTIVE_LOW,
+    .rtsRxFifoLevel             = 20UL,
+    .rtsPolarity                = CY_SCB_UART_ACTIVE_LOW,
+
+    .rxFifoTriggerLevel         = 0UL,
+    .rxFifoIntEnableMask        = 0x0UL,
+
+    .txFifoTriggerLevel         = 0UL,
+    .txFifoIntEnableMask        = 0x0UL
+};
+
+int stdio_uart_inited = false;
+serial_t stdio_uart;
+
+typedef struct irq_info_s {
+    serial_obj_t        *serial_obj;
+    uart_irq_handler    handler;
+    uint32_t            id_arg;
+    IRQn_Type           irqn;
+#if defined (TARGET_MCU_PSOC6_M0)
+    cy_en_intr_t        cm0p_irq_src;
+#endif
+} irq_info_t;
+
+static irq_info_t irq_info[NUM_SERIAL_PORTS] = {
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn},
+    {NULL, NULL, 0, unconnected_IRQn}
+};
+
+
+static void serial_irq_dispatcher(uint32_t serial_id)
+{
+    MBED_ASSERT(serial_id < NUM_SERIAL_PORTS);
+    irq_info_t *info = &irq_info[serial_id];
+    serial_obj_t *obj = info->serial_obj;
+    MBED_ASSERT(obj);
+
+#if DEVICE_SERIAL_ASYNCH
+    if (obj->async_handler) {
+        obj->async_handler();
+        return;
+    }
+#endif
+    if (Cy_SCB_GetRxInterruptStatusMasked(obj->base) & CY_SCB_RX_INTR_NOT_EMPTY) {
+        info->handler(info->id_arg, RxIrq);
+        Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_RX_INTR_NOT_EMPTY);
+    }
+
+    if (Cy_SCB_GetTxInterruptStatusMasked(obj->base) & (CY_SCB_TX_INTR_LEVEL | CY_SCB_UART_TX_DONE)) {
+        info->handler(info->id_arg, TxIrq);
+    }
+}
+
+static void serial_irq_dispatcher_uart0(void)
+{
+    serial_irq_dispatcher(0);
+}
+
+static void serial_irq_dispatcher_uart1(void)
+{
+    serial_irq_dispatcher(1);
+}
+
+static void serial_irq_dispatcher_uart2(void)
+{
+    serial_irq_dispatcher(2);
+}
+
+static void serial_irq_dispatcher_uart3(void)
+{
+    serial_irq_dispatcher(3);
+}
+
+static void serial_irq_dispatcher_uart4(void)
+{
+    serial_irq_dispatcher(4);
+}
+
+static void serial_irq_dispatcher_uart5(void)
+{
+    serial_irq_dispatcher(5);
+}
+
+void serial_irq_dispatcher_uart6(void)
+{
+    serial_irq_dispatcher(6);
+}
+
+static void serial_irq_dispatcher_uart7(void)
+{
+    serial_irq_dispatcher(7);
+}
+
+
+static void (*irq_dispatcher_table[])(void) = {
+    serial_irq_dispatcher_uart0,
+    serial_irq_dispatcher_uart1,
+    serial_irq_dispatcher_uart2,
+    serial_irq_dispatcher_uart3,
+    serial_irq_dispatcher_uart4,
+    serial_irq_dispatcher_uart5,
+    serial_irq_dispatcher_uart6,
+    serial_irq_dispatcher_uart7
+};
+
+
+static IRQn_Type serial_irq_allocate_channel(serial_obj_t *obj)
+{
+#if defined (TARGET_MCU_PSOC6_M0)
+    irq_info[obj->serial_id].cm0p_irq_src = scb_0_interrupt_IRQn + obj->serial_id;
+    return cy_m0_nvic_allocate_channel(CY_SERIAL_IRQN_ID + obj->serial_id);
+#else
+    return (IRQn_Type)(scb_0_interrupt_IRQn + obj->serial_id);
+#endif // M0
+}
+
+static void serial_irq_release_channel(IRQn_Type channel, uint32_t serial_id)
+{
+#if defined (TARGET_MCU_PSOC6_M0)
+    cy_m0_nvic_release_channel(channel, CY_SERIAL_IRQN_ID + serial_id);
+#endif //M0
+}
+
+static int serial_irq_setup_channel(serial_obj_t *obj)
+{
+    cy_stc_sysint_t irq_config;
+    irq_info_t      *info = &irq_info[obj->serial_id];
+
+    if (info->irqn == unconnected_IRQn) {
+        IRQn_Type irqn = serial_irq_allocate_channel(obj);
+        if (irqn < 0) {
+            return (-1);
+        }
+        // Configure NVIC
+        irq_config.intrPriority = SERIAL_DEFAULT_IRQ_PRIORITY;
+        irq_config.intrSrc = irqn;
+#if defined (TARGET_MCU_PSOC6_M0)
+        irq_config.cm0pSrc = info->cm0p_irq_src;
+#endif
+        if (Cy_SysInt_Init(&irq_config, irq_dispatcher_table[obj->serial_id]) != CY_SYSINT_SUCCESS) {
+            return(-1);
+        }
+
+        info->irqn = irqn;
+        info->serial_obj = obj;
+        NVIC_EnableIRQ(irqn);
+    }
+    return 0;
+}
+
+/*
+ * Calculates fractional divider value.
+ */
+static uint32_t divider_value(uint32_t frequency, uint32_t frac_bits)
+{
+    /* UARTs use peripheral clock */
+    return ((CY_CLK_PERICLK_FREQ_HZ * (1 << frac_bits)) + (frequency / 2)) / frequency;
+}
+
+static cy_en_sysclk_status_t serial_init_clock(serial_obj_t *obj, uint32_t baudrate)
+{
+    cy_en_sysclk_status_t status = CY_SYSCLK_BAD_PARAM;
+
+    if (obj->div_num == CY_INVALID_DIVIDER) {
+        uint32_t divider_num = cy_clk_allocate_divider(CY_SYSCLK_DIV_16_5_BIT);
+
+        if (divider_num < PERI_DIV_16_5_NR) {
+            /* Assign fractional divider. */
+            status = Cy_SysClk_PeriphAssignDivider(obj->clock, CY_SYSCLK_DIV_16_5_BIT, divider_num);
+            if (status == CY_SYSCLK_SUCCESS) {
+                obj->div_type = CY_SYSCLK_DIV_16_5_BIT;
+                obj->div_num = divider_num;
+            }
+        } else {
+            // Try 16-bit divider.
+            divider_num = cy_clk_allocate_divider(CY_SYSCLK_DIV_16_BIT);
+            if (divider_num < PERI_DIV_16_NR) {
+                /* Assign 16-bit divider. */
+                status = Cy_SysClk_PeriphAssignDivider(obj->clock, CY_SYSCLK_DIV_16_BIT, divider_num);
+                if (status == CY_SYSCLK_SUCCESS) {
+                    obj->div_type = CY_SYSCLK_DIV_16_BIT;
+                    obj->div_num = divider_num;
+                }
+            } else {
+                error("Serial: cannot assign clock divider.");
+            }
+        }
+    } else {
+        status = CY_SYSCLK_SUCCESS;
+    }
+
+    if (status == CY_SYSCLK_SUCCESS) {
+        /* Set baud rate */
+        if (obj->div_type == CY_SYSCLK_DIV_16_5_BIT) {
+            Cy_SysClk_PeriphDisableDivider(CY_SYSCLK_DIV_16_5_BIT, obj->div_num);
+            uint32_t divider = divider_value(baudrate * UART_OVERSAMPLE, 5);
+            status = Cy_SysClk_PeriphSetFracDivider(CY_SYSCLK_DIV_16_5_BIT,
+                                                    obj->div_num,
+                                                    (divider >> 5) - 1, // integral part
+                                                    divider & 0x1F);    // fractional part
+            Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_16_5_BIT, obj->div_num);
+        } else if (obj->div_type == CY_SYSCLK_DIV_16_BIT) {
+            Cy_SysClk_PeriphDisableDivider(CY_SYSCLK_DIV_16_BIT, obj->div_num);
+            status = Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_16_BIT,
+                                                obj->div_num,
+                                                divider_value(baudrate * UART_OVERSAMPLE, 0));
+            Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_16_BIT, obj->div_num);
+        }
+    }
+    return status;
+}
+
+/*
+ * Initializes i/o pins for UART tx/rx.
+ */
+static void serial_init_pins(serial_obj_t *obj)
+{
+    int tx_function = pinmap_function(obj->pin_tx, PinMap_UART_TX);
+    int rx_function = pinmap_function(obj->pin_rx, PinMap_UART_RX);
+    if (cy_reserve_io_pin(obj->pin_tx) || cy_reserve_io_pin(obj->pin_rx)) {
+        error("Serial TX/RX pin reservation conflict.");
+    }
+    pin_function(obj->pin_tx, tx_function);
+    pin_function(obj->pin_rx, rx_function);
+}
+
+/*
+ * Initializes i/o pins for UART flow control.
+ */
+static void serial_init_flow_pins(serial_obj_t *obj)
+{
+    if (obj->pin_rts != NC) {
+        int rts_function = pinmap_function(obj->pin_rts, PinMap_UART_RTS);
+        if (cy_reserve_io_pin(obj->pin_rts)) {
+            error("Serial RTS pin reservation conflict.");
+        }
+        pin_function(obj->pin_rts, rts_function);
+    }
+
+    if (obj->pin_cts != NC) {
+        int cts_function = pinmap_function(obj->pin_cts, PinMap_UART_CTS);
+        if (cy_reserve_io_pin(obj->pin_cts)) {
+            error("Serial CTS pin reservation conflict.");
+        }
+        pin_function(obj->pin_cts, cts_function);
+    }
+}
+
+
+/*
+ * Initializes and enables UART/SCB.
+ */
+static void serial_init_peripheral(serial_obj_t *obj)
+{
+    cy_stc_scb_uart_config_t uart_config = default_uart_config;
+
+    uart_config.dataWidth   = obj->data_width;
+    uart_config.parity      = obj->parity;
+    uart_config.stopBits    = obj->stop_bits;
+    uart_config.enableCts   = (obj->pin_cts != NC);
+
+    Cy_SCB_UART_Init(obj->base, &uart_config, NULL);
+    Cy_SCB_UART_Enable(obj->base);
+}
+
+#if DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
+static cy_en_syspm_status_t serial_pm_callback(cy_stc_syspm_callback_params_t *params)
+{
+    serial_obj_t *obj = (serial_obj_t *)params->context;
+    cy_en_syspm_status_t status = CY_SYSPM_FAIL;
+
+    switch (params->mode) {
+        case CY_SYSPM_CHECK_READY:
+            /* If all data elements are transmitted from the TX FIFO and
+            * shifter and the RX FIFO is empty: the UART is ready to enter
+            * Deep Sleep mode.
+            */
+            if (Cy_SCB_UART_IsTxComplete(obj->base)) {
+                if (0UL == Cy_SCB_UART_GetNumInRxFifo(obj->base)) {
+                    /* Disable the UART. The transmitter stops driving the
+                    * lines and the receiver stops receiving data until
+                    * the UART is enabled.
+                    * This happens when the device failed to enter Deep
+                    * Sleep or it is awaken from Deep Sleep mode.
+                    */
+                    Cy_SCB_UART_Disable(obj->base, NULL);
+                    status = CY_SYSPM_SUCCESS;
+                }
+            }
+            break;
+
+
+        case CY_SYSPM_CHECK_FAIL:
+            /* Enable the UART to operate */
+            Cy_SCB_UART_Enable(obj->base);
+            status = CY_SYSPM_SUCCESS;
+            break;
+
+        case CY_SYSPM_BEFORE_TRANSITION:
+            status = CY_SYSPM_SUCCESS;
+            break;
+
+        case CY_SYSPM_AFTER_TRANSITION:
+            /* Enable the UART to operate */
+            Cy_SCB_UART_Enable(obj->base);
+            status = CY_SYSPM_SUCCESS;
+            break;
+
+        default:
+            break;
+    }
+    return status;
+}
+#endif // DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
+
+void serial_init(serial_t *obj_in, PinName tx, PinName rx)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    bool is_stdio = (tx == CY_STDIO_UART_TX) || (rx == CY_STDIO_UART_RX);
+
+    if (is_stdio && stdio_uart_inited) {
+        memcpy(obj_in, &stdio_uart, sizeof(serial_t));
+        return;
+    }
+    {
+        uint32_t uart = pinmap_peripheral(tx, PinMap_UART_TX);
+        uart = pinmap_merge(uart, pinmap_peripheral(rx, PinMap_UART_RX));
+        if (uart != (uint32_t)NC) {
+            obj->base = (CySCB_Type*)uart;
+            obj->serial_id = ((UARTName)uart - UART_0) / (UART_1 - UART_0);
+            obj->pin_tx = tx;
+            obj->pin_rx = rx;
+            obj->clock = CY_PIN_CLOCK(pinmap_function(tx, PinMap_UART_TX));
+            obj->div_num = CY_INVALID_DIVIDER;
+            obj->data_width = 8;
+            obj->stop_bits = CY_SCB_UART_STOP_BITS_1;
+            obj->parity = CY_SCB_UART_PARITY_NONE;
+            obj->pin_rts = NC;
+            obj->pin_cts = NC;
+
+            serial_init_clock(obj, UART_DEFAULT_BAUDRATE);
+            serial_init_peripheral(obj);
+            //Cy_GPIO_Write(Cy_GPIO_PortToAddr(CY_PORT(P13_6)), CY_PIN(P13_6), 1);
+            serial_init_pins(obj);
+            //Cy_GPIO_Write(Cy_GPIO_PortToAddr(CY_PORT(P13_6)), CY_PIN(P13_6), 0);
+#if DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
+            obj->pm_callback_handler.callback = serial_pm_callback;
+            obj->pm_callback_handler.type = CY_SYSPM_DEEPSLEEP;
+            obj->pm_callback_handler.skipMode = 0;
+            obj->pm_callback_handler.callbackParams = &obj->pm_callback_params;
+            obj->pm_callback_params.base = obj->base;
+            obj->pm_callback_params.context = obj;
+            if (!Cy_SysPm_RegisterCallback(&obj->pm_callback_handler)) {
+                error("PM callback registration failed!");
+            }
+#endif // DEVICE_SLEEP && DEVICE_LOWPOWERTIMER
+            if (is_stdio) {
+                memcpy(&stdio_uart, obj_in, sizeof(serial_t));
+                stdio_uart_inited = true;
+            }
+        } else {
+            error("Serial pinout mismatch. Requested pins Rx and Tx can't be used for the same Serial communication.");
+        }
+    }
+}
+
+void serial_baud(serial_t *obj_in, int baudrate)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    Cy_SCB_UART_Disable(obj->base, NULL);
+    serial_init_clock(obj, baudrate);
+    Cy_SCB_UART_Enable(obj->base);
+}
+
+void serial_format(serial_t *obj_in, int data_bits, SerialParity parity, int stop_bits)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    if ((data_bits >= 5) && (data_bits <= 9)) {
+        obj->data_width = data_bits;
+    }
+
+    switch (parity) {
+        case ParityNone:
+            obj->parity = CY_SCB_UART_PARITY_NONE;
+            break;
+        case ParityOdd:
+            obj->parity = CY_SCB_UART_PARITY_ODD;
+            break;
+        case ParityEven:
+            obj->parity = CY_SCB_UART_PARITY_EVEN;
+            break;
+        case ParityForced1:
+        case ParityForced0:
+            MBED_ASSERT("Serial parity mode not supported!");
+            break;
+    }
+
+    switch (stop_bits) {
+        case 1:
+            obj->stop_bits = CY_SCB_UART_STOP_BITS_1;
+            break;
+        case 2:
+            obj->stop_bits = CY_SCB_UART_STOP_BITS_2;
+            break;
+        case 3:
+            obj->stop_bits = CY_SCB_UART_STOP_BITS_3;
+            break;
+        case 4:
+            obj->stop_bits = CY_SCB_UART_STOP_BITS_4;
+            break;
+    }
+
+    Cy_SCB_UART_Disable(obj->base, NULL);
+    serial_init_peripheral(obj);
+}
+
+void serial_putc(serial_t *obj_in, int c)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    while (!serial_writable(obj_in)) {
+        // empty
+    }
+    Cy_SCB_UART_Put(obj->base, c);
+}
+
+int serial_getc(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    while (!serial_readable(obj_in)) {
+        // empty
+    }
+    return Cy_SCB_UART_Get(obj->base);
+}
+
+int serial_readable(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    return Cy_SCB_GetNumInRxFifo(obj->base) != 0;
+}
+
+int serial_writable(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    return Cy_SCB_GetNumInTxFifo(obj->base) != Cy_SCB_GetFifoSize(obj->base);
+}
+
+void serial_clear(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    Cy_SCB_UART_Disable(obj->base, NULL);
+    Cy_SCB_ClearTxFifo(obj->base);
+    Cy_SCB_ClearRxFifo(obj->base);
+    serial_init_peripheral(obj);
+}
+
+void serial_break_set(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    /* Cypress SCB does not support transmitting break directly.
+     * We emulate functionality by switching TX pin to GPIO mode.
+     */
+    GPIO_PRT_Type *port_tx = Cy_GPIO_PortToAddr(CY_PORT(obj->pin_tx));
+    Cy_GPIO_Pin_FastInit(port_tx, CY_PIN(obj->pin_tx), CY_GPIO_DM_STRONG_IN_OFF, 0, HSIOM_SEL_GPIO);
+    Cy_GPIO_Write(port_tx, CY_PIN(obj->pin_tx), 0);
+}
+
+void serial_break_clear(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    /* Connect TX pin back to SCB, see a comment in serial_break_set() above */
+    GPIO_PRT_Type *port_tx = Cy_GPIO_PortToAddr(CY_PORT(obj->pin_tx));
+    int tx_function = pinmap_function(obj->pin_tx, PinMap_UART_TX);
+    Cy_GPIO_Pin_FastInit(port_tx, CY_PIN(obj->pin_tx), CY_GPIO_DM_STRONG_IN_OFF, 0, CY_PIN_HSIOM(tx_function));
+}
+
+void serial_set_flow_control(serial_t *obj_in, FlowControl type, PinName rxflow, PinName txflow)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    Cy_SCB_UART_Disable(obj->base, NULL);
+
+    switch (type) {
+        case FlowControlNone:
+            obj->pin_rts = NC;
+            obj->pin_cts = NC;
+            break;
+        case FlowControlRTS:
+            obj->pin_rts = rxflow;
+            obj->pin_cts = NC;
+            break;
+        case FlowControlCTS:
+            obj->pin_rts = NC;
+            obj->pin_cts = txflow;
+            break;
+        case FlowControlRTSCTS:
+            obj->pin_rts = rxflow;
+            obj->pin_cts = txflow;
+            break;
+    }
+
+    serial_init_peripheral(obj);
+    serial_init_flow_pins(obj);
+}
+
+#if DEVICE_SERIAL_ASYNCH
+
+void serial_irq_handler(serial_t *obj_in, uart_irq_handler handler, uint32_t id)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    irq_info_t *info = &irq_info[obj->serial_id];
+
+    if (info->irqn != unconnected_IRQn) {
+        NVIC_DisableIRQ(info->irqn);
+    }
+    info->handler = handler;
+    info->id_arg = id;
+    serial_irq_setup_channel(obj);
+}
+
+void serial_irq_set(serial_t *obj_in, SerialIrq irq, uint32_t enable)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    switch (irq) {
+        case RxIrq:
+            if (enable) {
+                Cy_SCB_SetRxInterruptMask(obj->base,  CY_SCB_RX_INTR_NOT_EMPTY);
+            } else {
+                Cy_SCB_SetRxInterruptMask(obj->base, 0);
+            }
+            break;
+        case TxIrq:
+            if (enable) {
+                Cy_SCB_SetTxInterruptMask(obj->base, CY_SCB_TX_INTR_LEVEL | CY_SCB_UART_TX_DONE);
+            } else {
+                Cy_SCB_SetTxInterruptMask(obj->base, 0);
+            }
+            break;
+    }
+}
+
+static void serial_finish_tx_asynch(serial_obj_t *obj)
+{
+    Cy_SCB_SetTxInterruptMask(obj->base, 0);
+    obj->tx_pending = false;
+}
+
+static void serial_finish_rx_asynch(serial_obj_t *obj)
+{
+    Cy_SCB_SetRxInterruptMask(obj->base, 0);
+    obj->rx_pending = false;
+}
+
+int serial_tx_asynch(serial_t *obj_in, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+    const uint8_t *p_buf = tx;
+
+    (void)tx_width; // Obsolete argument
+    (void)hint; // At the moment we do not support DAM transfers, so this parameter gets ignored.
+
+    if (obj->tx_pending) {
+        return 0;
+    }
+
+    obj->async_handler = (cy_israddress)handler;
+    if (serial_irq_setup_channel(obj) < 0) {
+        return 0;
+    }
+
+    // Write as much as possible into the FIFO first.
+    while ((tx_length > 0) && Cy_SCB_UART_Put(obj->base, *p_buf)) {
+        ++p_buf;
+        --tx_length;
+    }
+
+    if (tx_length > 0) {
+        obj->tx_events = event;
+        obj_in->tx_buff.buffer = (void *)p_buf;
+        obj_in->tx_buff.length = tx_length;
+        obj_in->tx_buff.pos = 0;
+        obj->tx_pending = true;
+        // Enable interrupts to complete transmission.
+        Cy_SCB_SetRxInterruptMask(obj->base, CY_SCB_TX_INTR_LEVEL | CY_SCB_UART_TX_DONE);
+
+    } else {
+        // Enable interrupt to signal completing of the transmission.
+        Cy_SCB_SetRxInterruptMask(obj->base, CY_SCB_UART_TX_DONE);
+    }
+    return tx_length;
+}
+
+void serial_rx_asynch(serial_t *obj_in, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    (void)rx_width; // Obsolete argument
+    (void)hint; // At the moment we do not support DAM transfers, so this parameter gets ignored.
+
+    if (obj->rx_pending || (rx_length == 0)) {
+        return;
+    }
+
+    obj_in->char_match = char_match;
+    obj_in->char_found = false;
+    obj->rx_events = event;
+    obj_in->rx_buff.buffer = rx;
+    obj_in->rx_buff.length = rx_length;
+    obj_in->rx_buff.pos = 0;
+    obj->async_handler = (cy_israddress)handler;
+    if (serial_irq_setup_channel(obj) < 0) {
+        return;
+    }
+    obj->rx_pending = true;
+    // Enable interrupts to start receiving.
+    Cy_SCB_SetRxInterruptMask(obj->base, CY_SCB_UART_RX_INTR_MASK & ~CY_SCB_RX_INTR_UART_BREAK_DETECT);
+}
+
+uint8_t serial_tx_active(serial_t *obj)
+{
+    return obj->serial.tx_pending;
+}
+
+uint8_t serial_rx_active(serial_t *obj)
+{
+    return obj->serial.rx_pending;
+}
+
+int serial_irq_handler_asynch(serial_t *obj_in)
+{
+    uint32_t cur_events = 0;
+    uint32_t tx_status;
+    uint32_t rx_status;
+
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    rx_status = Cy_SCB_GetRxInterruptStatusMasked(obj->base);
+
+    tx_status = Cy_SCB_GetTxInterruptStatusMasked(obj->base);
+
+
+    if (tx_status & CY_SCB_TX_INTR_LEVEL) {
+        // FIFO has space available for more TX
+        uint8_t *ptr = obj_in->tx_buff.buffer;
+        ptr += obj_in->tx_buff.pos;
+        while ((obj_in->tx_buff.pos < obj_in->tx_buff.length) &&
+                Cy_SCB_UART_Put(obj->base, *ptr)) {
+            ++ptr;
+            ++(obj_in->tx_buff.pos);
+        }
+        if (obj_in->tx_buff.pos == obj_in->tx_buff.length) {
+            // No more bytes to follow; check to see if we need to signal completion.
+            if (obj->tx_events & SERIAL_EVENT_TX_COMPLETE) {
+                // Disable FIFO interrupt as there are no more bytes to follow.
+                Cy_SCB_SetRxInterruptMask(obj->base, CY_SCB_UART_TX_DONE);
+            } else {
+                // Nothing more to do, mark end of transmission.
+                serial_finish_tx_asynch(obj);
+            }
+        }
+    }
+
+    if (tx_status & CY_SCB_TX_INTR_UART_DONE) {
+        // Mark end of the transmission.
+        serial_finish_tx_asynch(obj);
+        cur_events |= SERIAL_EVENT_TX_COMPLETE & obj->tx_events;
+    }
+
+    Cy_SCB_ClearTxInterrupt(obj->base, tx_status);
+
+    if (rx_status & CY_SCB_RX_INTR_OVERFLOW) {
+        cur_events |= SERIAL_EVENT_RX_OVERRUN_ERROR & obj->rx_events;
+    }
+
+    if (rx_status & CY_SCB_RX_INTR_UART_FRAME_ERROR) {
+        cur_events |= SERIAL_EVENT_RX_FRAMING_ERROR & obj->rx_events;
+    }
+
+    if (rx_status & CY_SCB_RX_INTR_UART_PARITY_ERROR) {
+        cur_events |= SERIAL_EVENT_RX_PARITY_ERROR & obj->rx_events;
+    }
+
+    if (rx_status & CY_SCB_RX_INTR_LEVEL) {
+        uint8_t *ptr = obj_in->rx_buff.buffer;
+        ptr += obj_in->rx_buff.pos;
+        while (obj_in->rx_buff.pos < obj_in->rx_buff.length) {
+            uint32_t c = Cy_SCB_UART_Get(obj->base);
+            if (c == CY_SCB_UART_RX_NO_DATA) {
+                break;
+            }
+            *ptr++ = (uint8_t)c;
+            ++(obj_in->rx_buff.pos);
+            // Check for character match condition.
+            if (obj_in->char_match != SERIAL_RESERVED_CHAR_MATCH) {
+                if (c == obj_in->char_match) {
+                    obj_in->char_found = true;
+                    cur_events |= SERIAL_EVENT_RX_CHARACTER_MATCH & obj->rx_events;
+                    // Clamp RX.
+                    obj_in->rx_buff.length = obj_in->rx_buff.pos;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (obj_in->rx_buff.pos == obj_in->rx_buff.length) {
+        serial_finish_rx_asynch(obj);
+    }
+
+    Cy_SCB_ClearRxInterrupt(obj->base, rx_status);
+
+    return cur_events;
+}
+
+void serial_tx_abort_asynch(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    serial_finish_tx_asynch(obj);
+    Cy_SCB_UART_ClearTxFifo(obj->base);
+}
+
+void serial_rx_abort_asynch(serial_t *obj_in)
+{
+    serial_obj_t *obj = OBJ_P(obj_in);
+
+    serial_finish_rx_asynch(obj);
+    Cy_SCB_UART_ClearRxFifo(obj->base);
+}
+
+#endif // DEVICE_SERIAL_ASYNCH
+
+#endif // DEVICE_SERIAL