Newer
Older
mbed-os / targets / TARGET_RENESAS / TARGET_RZ_A2XX / serial_api.c
@RyoheiHagimoto RyoheiHagimoto on 17 Aug 2020 24 KB Added GR-MANGO to be a target.
/* mbed Microcontroller Library
 * Copyright (c) 2006-2020 ARM Limited
 * 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.
 */
// math.h required for floating point operations for baud rate calculation

#if DEVICE_SERIAL
#include "mbed_assert.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>

#include "serial_api.h"
#include "cmsis.h"
#include "PeripheralPins.h"
#include "gpio_api.h"
#include "RZ_A2_Init.h"

#include "iodefine.h"
#include "mbed_drv_cfg.h"
#include "mbed_critical.h"

/******************************************************************************
 * INITIALIZATION
 ******************************************************************************/

#define UART_NUM    5
#define IRQ_NUM     3

static void uart0_tx_irq(void);
static void uart0_rx_irq(void);
static void uart0_er_irq(void);
static void uart1_tx_irq(void);
static void uart1_rx_irq(void);
static void uart1_er_irq(void);
static void uart2_tx_irq(void);
static void uart2_rx_irq(void);
static void uart2_er_irq(void);
static void uart3_tx_irq(void);
static void uart3_rx_irq(void);
static void uart3_er_irq(void);
static void uart4_tx_irq(void);
static void uart4_rx_irq(void);
static void uart4_er_irq(void);

static uint8_t serial_available_buffer(serial_t *obj);
static void serial_irq_err_set(serial_t *obj, uint32_t enable);

static volatile struct st_scifa* SCIFA[UART_NUM] = {
    &SCIFA0, &SCIFA1, &SCIFA2, &SCIFA3, &SCIFA4
};

int stdio_uart_inited = 0;
serial_t stdio_uart;
static uart_irq_handler irq_handler;

struct serial_global_data_s {
    uint32_t serial_irq_id;
    gpio_t sw_rts, sw_cts;
    serial_t *tranferring_obj, *receiving_obj;
    uint32_t async_tx_callback, async_rx_callback;
    int event, wanted_rx_events;
};

static struct serial_global_data_s uart_data[UART_NUM];

static const IRQn_Type irq_set_tbl[UART_NUM][IRQ_NUM] = {
    {RXI0_IRQn, TXI0_IRQn, ERI0_IRQn},
    {RXI1_IRQn, TXI1_IRQn, ERI1_IRQn},
    {RXI2_IRQn, TXI2_IRQn, ERI2_IRQn},
    {RXI3_IRQn, TXI3_IRQn, ERI3_IRQn},
    {RXI4_IRQn, TXI4_IRQn, ERI4_IRQn},
};

static const IRQHandler hander_set_tbl[UART_NUM][IRQ_NUM] = {
    {uart0_rx_irq, uart0_tx_irq, uart0_er_irq},
    {uart1_rx_irq, uart1_tx_irq, uart1_er_irq},
    {uart2_rx_irq, uart2_tx_irq, uart2_er_irq},
    {uart3_rx_irq, uart3_tx_irq, uart3_er_irq},
    {uart4_rx_irq, uart4_tx_irq, uart4_er_irq},
};


void serial_init(serial_t *obj, PinName tx, PinName rx) {
    volatile uint8_t dummy_buf;
    int is_stdio_uart = 0;
    // determine the UART to use
    uint32_t uart_tx = pinmap_peripheral(tx, PinMap_UART_TX);
    uint32_t uart_rx = pinmap_peripheral(rx, PinMap_UART_RX);
    uint32_t ch_no = pinmap_merge(uart_tx, uart_rx);

#if defined(PRINTF_NOT_USE)
    if ((int)ch_no == NC) {
        obj->serial.ch = ch_no;
        return;
    }
#else
   MBED_ASSERT((int)ch_no != NC);
#endif

    // pinout the chosen uart
    pinmap_pinout(tx, PinMap_UART_TX);
    pinmap_pinout(rx, PinMap_UART_RX);

    obj->serial.ch = ch_no;
    obj->serial.uart = SCIFA[ch_no];

    /* ==== Module standby clear ==== */
    CPG.STBCR4.BYTE &= ~(0x80 >> ch_no);
    dummy_buf = CPG.STBCR4.BYTE;
    (void)dummy_buf;

    /* ==== SCIF initial setting ==== */
    /* --- Serial control register(SCR) setting --- */
    obj->serial.uart->SCR.WORD = 0x0000;   /* SCIFA transmitting and receiving operations stop */

    /* ---- FIFO control register (FCR) setting ---- */
    if ((int)uart_tx != NC) {      /* Use transmit */
        /* Transmit FIFO reset */
        obj->serial.uart->FCR.BIT.TFRST = 0x01;
    }

    if ((int)uart_rx != NC) {      /* Use receive */
        /* Receive FIFO data register reset */
        obj->serial.uart->FCR.BIT.RFRST = 0x1;
    }

    /* ---- Serial status register (FSR) setting ---- */
    obj->serial.uart->FSR.BIT.DR  = 0x0;  /* ER bit clear  */
    obj->serial.uart->FSR.BIT.BRK = 0x0;  /* BRK bit clear */
    obj->serial.uart->FSR.BIT.ER  = 0x0;  /* ER bit clear  */

    /* ---- Line status register (LSR) setting ---- */
    obj->serial.uart->LSR.BIT.ORER = 0x0; /* ORER bit clear */

    /* ---- Serial control register (SCR) setting ---- */
    obj->serial.uart->SCR.BIT.CKE = 0x0;  /* B'00 : Internal CLK */

    serial_baud(obj, 9600);
    serial_format(obj, 8, ParityNone, 1);

    /* ---- Serial extension mode register (SEMR) setting ----
    b7 BGDM - Baud rate generator double-speed mode  : Normal mode
    b0 ABCS - Base clock select in asynchronous mode : Base clock is 16 times the bit rate */

    obj->serial.uart->SEMR.BIT.ABCS0 = 0x0;    /* Base clock select in asynchronous mode : Base clock is 16 times the bit rate */
    obj->serial.uart->SEMR.BIT.NFEN  = 0x1;    /*  Noise Filter : Enable */
    obj->serial.uart->SEMR.BIT.DIR   = 0x0;    /* LSB first */
    obj->serial.uart->SEMR.BIT.MDDRS = 0x0;    /* Select BRR register */
    obj->serial.uart->SEMR.BIT.BRME  = 0x0;    /* Bit Modulation Enable : Disable */
    obj->serial.uart->SEMR.BIT.BGDM  = 0x0;    /* Baud rate generator double-speed mode  : Normal mode*/

    obj->serial.uart->FCR.BIT.LOOP   = 0x0;    /* Loop-back test                    : Disabled      */
    if ((int)uart_rx != NC) {
        obj->serial.uart->FCR.BIT.RFRST = 0x0; /* Receive FIFO data register reset  : Disabled      */
        obj->serial.uart->SCR.BIT.TE    = 0x1; /* transmitting operations is enabled */
    } else {
        obj->serial.uart->FCR.BIT.RFRST = 0x1; /* Receive FIFO data register reset  : Enable        */
    }
    if ((int)uart_tx != NC) {      /* Use transmit */
        obj->serial.uart->FCR.BIT.TFRST = 0x0; /* Transmit FIFO data register reset : Disabled      */
        obj->serial.uart->SCR.BIT.RE    = 0x1; /* receiving operations is enabled */
    } else {
        obj->serial.uart->FCR.BIT.TFRST = 0x1; /* Transmit FIFO data register reset : Enable        */
    }
    obj->serial.uart->FCR.BIT.MCE   = 0x0;     /* Modem control enable              : Disabled      */
    obj->serial.uart->FCR.BIT.TTRG  = 0x3;     /* Transmit FIFO data trigger        : 0-data        */
    obj->serial.uart->FCR.BIT.RTRG  = 0x0;     /* Receive FIFO data trigger         : 1-data        */
    obj->serial.uart->FCR.BIT.RSTRG = 0x0;     /* RTS output active trigger         : Initial value */

    /* ---- Serial port register (SCR, SPTR) setting ---- */
    /* b1 SPB2IO - Serial port break output : Enabled
       b0 SPB2DT - Serial port break data   : High-level */

    obj->serial.uart->SPTR.WORD |= 0x3;   /* b1 SPB2IO - Serial port break output : Enabled    */
                                          /* b0 SPB2DT - Serial port break data   : High-level */

    if ((int)uart_rx != NC) {
        obj->serial.uart->SCR.BIT.TIE   = 0x1;
        obj->serial.uart->SCR.BIT.TE    = 0x1; /* transmitting operations is enabled */
    }
    if ((int)uart_tx != NC) {      /* Use transmit */
        obj->serial.uart->SCR.BIT.RIE   = 0x1;
        obj->serial.uart->SCR.BIT.RE    = 0x1; /* receiving operations is enabled */
    }

    is_stdio_uart = (ch_no == STDIO_UART) ? (1) : (0);

    if (is_stdio_uart) {
        stdio_uart_inited = 1;
        memcpy(&stdio_uart, obj, sizeof(serial_t));
    }
}

void serial_free(serial_t *obj) {
    
}

// serial_baud
// set the baud rate, taking in to account the current SystemFrequency
void serial_baud(serial_t *obj, int baudrate) {
    uint32_t idx;
    uint32_t brr;
    uint32_t mddr;
    uint32_t wk_data = 8;
    float    wk_error;

#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return;
    }
#endif

    if (baudrate <= 0) {
        return;
    }

    for (idx = 0; idx <= 4; idx++) {
        /* Calculate Bit Rate */
        brr = CM0_RENESAS_RZ_A2_P1_CLK / (wk_data * baudrate);
        if (brr > 0) {
            /* The maximum baud rate is (CM0_RENESAS_RZ_A2_P1_CLK / 8) */
            /* If the baud rate is more, brr is set to 0 */
            brr -= 1;
        }

        /* When idx is 4 (CKS=3), it allows up to the limit value which can be adjusted with MDDR */
        if ((brr <= 255) || (idx == 4)) {
            if (brr > 255) {
               brr = 255;
            }

            /* Calculate Modulation Duty */
            wk_error = (float)CM0_RENESAS_RZ_A2_P1_CLK / (float)(wk_data * baudrate * (brr + 1));
            mddr = (uint32_t)((256.0f / wk_error) + 0.5f);
            if (mddr < 128) {
                mddr = 128;    /* MDDR >= 128 (Executed only when idx is 4) */
            }

            /* idx= 0: BGDM=1 ABCS0=1 CKS=0 */
            /*      1: BGDM=0 ABCS0=0 CKS=0 */
            /*      2: BGDM=0 ABCS0=0 CKS=1 */
            /*      3: BGDM=1 ABCS0=1 CKS=3 (Do not use CKS=2) */
            /*      4: BGDM=0 ABCS0=0 CKS=3 */
            if ((idx == 0) || (idx == 3)) {
                obj->serial.uart->SEMR.BIT.BGDM  = 0x1;     /* Baud rate generator double-speed mode */
                obj->serial.uart->SEMR.BIT.ABCS0 = 0x1;     /* 8 times the transfer rate as the base clock */
                obj->serial.uart->SMR.BIT.CKS    = idx;     /* Clock Select  0(1/1), 1(1/4), 2(1/16), 3(1/64) */
            } else {
                obj->serial.uart->SEMR.BIT.BGDM  = 0x0;     /* Baud rate generator normal mode */
                obj->serial.uart->SEMR.BIT.ABCS0 = 0x0;     /* 16 times the transfer rate as the base clock */
                obj->serial.uart->SMR.BIT.CKS    = idx - 1; /* Clock Select  0(1/1), 1(1/4), 2(1/16), 3(1/64) */
            }
            obj->serial.uart->SEMR.BIT.MDDRS = 0x0;                   /* Select BRR register */
            obj->serial.uart->BRR_MDDR.BRR.BYTE = (uint8_t)brr;       /* Bit Rate */
            obj->serial.uart->SEMR.BIT.BRME = 0x0;                    /* Bit rate modulation is disabled */
            if (mddr <= 255) {
                obj->serial.uart->SEMR.BIT.MDDRS = 0x1;               /* Select MDDR register */
                obj->serial.uart->BRR_MDDR.MDDR.BYTE = (uint8_t)mddr; /* Modulation Duty */
                obj->serial.uart->SEMR.BIT.BRME = 0x1;                /* Bit rate modulation is enabled */
            }
            break;
        }
        wk_data = (wk_data << 2);
    }
}

void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return;
    }
#endif

    MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
    MBED_ASSERT((data_bits == 8) || (data_bits == 7));
    MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven) ||
                (parity == ParityForced1) || (parity == ParityForced0));

    if (stop_bits == 1) {
        obj->serial.uart->SMR.BIT.STOP = 0x0;    /* Stop bit length    : 1 stop bit  */
    } else {
        obj->serial.uart->SMR.BIT.STOP = 0x1;    /* Stop bit length    : 2 stop bits */
    }

    switch (parity) {
        case ParityNone:
            obj->serial.uart->SMR.BIT.PE = 0x0;  /* Parity enable : Add and check are disabled */
            obj->serial.uart->SMR.BIT.PM = 0x0;  /* Parity mode : even */
            break;
        case ParityOdd:
            obj->serial.uart->SMR.BIT.PE = 0x1;  /* Parity enable : Add and check are enabled  */
            obj->serial.uart->SMR.BIT.PM = 0x1;  /* Parity mode : odd */
            break;
        case ParityEven:
            obj->serial.uart->SMR.BIT.PE = 0x1;  /* Parity enable : Add and check are enabled  */
            obj->serial.uart->SMR.BIT.PM = 0x0;  /* Parity mode : even */
            break;
        case ParityForced1:
        case ParityForced0:
        default:
            obj->serial.uart->SMR.BIT.PE = 0x0;  /* Parity enable : Add and check are disabled */
            obj->serial.uart->SMR.BIT.PM = 0x0;  /* Parity mode : even */
            break;
    }

    if (data_bits == 8) {
        obj->serial.uart->SMR.BIT.CHR = 0x0;    /* Character length   : 8-bit data  */
    } else {
        obj->serial.uart->SMR.BIT.CHR = 0x1;    /* Character length   : 7-bit data  */
    }
    obj->serial.uart->SMR.BIT.CM = 0x0;         /* Communication mode : Asynchronous mode  */
}

/******************************************************************************
 * INTERRUPTS HANDLING
 ******************************************************************************/

static void uart_tx_irq(uint32_t ch) {
    serial_t *obj = uart_data[ch].tranferring_obj;
    if (obj) {
        int i = obj->tx_buff.length - obj->tx_buff.pos;
        if (0 < i) {
            if (serial_available_buffer(obj) < i) {
                i = serial_available_buffer(obj);
            }
            do {
                uint8_t c = *(uint8_t *)obj->tx_buff.buffer;
                obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + 1;
                ++obj->tx_buff.pos;
                obj->serial.uart->FTDR.BYTE = c;
                obj->serial.uart->FSR.WORD &= ~0x0060u;
            } while (--i);
        } else {
            uart_data[ch].tranferring_obj = NULL;
            uart_data[ch].event = SERIAL_EVENT_TX_COMPLETE;
            ((void (*)())uart_data[ch].async_tx_callback)();
        }
    }

    irq_handler(uart_data[ch].serial_irq_id, TxIrq);
}

static void uart_rx_irq(uint32_t ch) {
    serial_t *obj = uart_data[ch].receiving_obj;
    if (obj) {
        if (obj->serial.uart->LSR.BIT.ORER == 1) {
            obj->serial.uart->LSR.BIT.ORER = 0;
            if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_OVERRUN_ERROR) {
                serial_rx_abort_asynch(obj);
                uart_data[ch].event = SERIAL_EVENT_RX_OVERRUN_ERROR;
                ((void (*)())uart_data[ch].async_rx_callback)();
            }
            return;
        }
        int c = serial_getc(obj);
        if (c != -1) {
            ((uint8_t *)obj->rx_buff.buffer)[obj->rx_buff.pos] = c;
            ++obj->rx_buff.pos;
            if (c == obj->char_match && ! obj->char_found) {
                obj->char_found = 1;
                if (obj->rx_buff.pos == obj->rx_buff.length) {
                    if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_COMPLETE) {
                        uart_data[ch].event = SERIAL_EVENT_RX_COMPLETE;
                    }
                }
                if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_CHARACTER_MATCH) {
                    uart_data[ch].event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
                }
                if (uart_data[ch].event) {
                    uart_data[ch].receiving_obj = NULL;
                    ((void (*)())uart_data[ch].async_rx_callback)();
                }
            } else if (obj->rx_buff.pos == obj->rx_buff.length) {
                uart_data[ch].receiving_obj = NULL;
                if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_COMPLETE) {
                    uart_data[ch].event = SERIAL_EVENT_RX_COMPLETE;
                    ((void (*)())uart_data[ch].async_rx_callback)();
                }
            }
        } else {
            serial_rx_abort_asynch(obj);
            if (uart_data[ch].wanted_rx_events & (SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR)) {
                uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR;
                if (obj->serial.uart->FSR.BIT.PER == 1) {
                    uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR;
                } else if (obj->serial.uart->FSR.BIT.FER == 1) {
                    uart_data[ch].event = SERIAL_EVENT_RX_FRAMING_ERROR;
                }
                ((void (*)())uart_data[ch].async_rx_callback)();
            }
            return;
        }
    }

    irq_handler(uart_data[ch].serial_irq_id, RxIrq);
}

static void uart_err_irq(uint32_t ch) {
    serial_t *obj = uart_data[ch].receiving_obj;
    if (obj) {
        serial_irq_err_set(obj, 0);
        if (uart_data[ch].wanted_rx_events & (SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR)) {
            uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR;
            if (obj->serial.uart->FSR.BIT.PER == 1) {
                uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR;
            } else if (obj->serial.uart->FSR.BIT.FER == 1) {
                uart_data[ch].event = SERIAL_EVENT_RX_FRAMING_ERROR;
            }
            ((void (*)())uart_data[ch].async_rx_callback)();
        }
        serial_rx_abort_asynch(obj);

        core_util_critical_section_enter();
        if (obj->serial.uart->FSR.WORD & 0x009Cu) {
            obj->serial.uart->FSR.WORD &=~0x009Cu;
        }
        if (obj->serial.uart->LSR.BIT.ORER == 1) {
            obj->serial.uart->LSR.BIT.ORER = 0;
        }
        core_util_critical_section_exit();
    }
}

static void uart0_tx_irq(void) {
    uart_tx_irq(0);
}
static void uart0_rx_irq(void) {
    uart_rx_irq(0);
}
static void uart0_er_irq(void) {
    uart_err_irq(0);
}

static void uart1_tx_irq(void) {
    uart_tx_irq(1);
}
static void uart1_rx_irq(void) {
    uart_rx_irq(1);
}
static void uart1_er_irq(void) {
    uart_err_irq(1);
}

static void uart2_tx_irq(void) {
    uart_tx_irq(2);
}
static void uart2_rx_irq(void) {
    uart_rx_irq(2);
}
static void uart2_er_irq(void) {
    uart_err_irq(2);
}

static void uart3_tx_irq(void) {
    uart_tx_irq(3);
}
static void uart3_rx_irq(void) {
    uart_rx_irq(3);
}
static void uart3_er_irq(void) {
    uart_err_irq(3);
}

static void uart4_tx_irq(void) {
    uart_tx_irq(4);
}
static void uart4_rx_irq(void) {
    uart_rx_irq(4);
}
static void uart4_er_irq(void) {
    uart_err_irq(4);
}

void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
    irq_handler = handler;
    uart_data[obj->serial.ch].serial_irq_id = id;
}

static void serial_irq_set_irq(IRQn_Type IRQn, IRQHandler handler, uint32_t enable) {
    if (enable) {
        InterruptHandlerRegister(IRQn, (void (*)(uint32_t))handler);
        GIC_SetPriority(IRQn, 5);
        GIC_EnableIRQ(IRQn);
    } else {
        GIC_DisableIRQ(IRQn);
    }
}

static void serial_irq_err_set(serial_t *obj, uint32_t enable) {
    serial_irq_set_irq(irq_set_tbl[obj->serial.ch][2], hander_set_tbl[obj->serial.ch][2], enable);
}

void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
    IRQn_Type IRQn;
    IRQHandler handler;

    IRQn = irq_set_tbl[obj->serial.ch][irq];
    handler = hander_set_tbl[obj->serial.ch][irq];

    if (obj->serial.ch < UART_NUM) {
        serial_irq_set_irq(IRQn, handler, enable);
    }
}

/******************************************************************************
 * READ/WRITE
 ******************************************************************************/
int serial_getc(serial_t *obj) {
    int data;

#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return 0;
    }
#endif
    /* Confirming receive error(ER,BRK,FER,PER,ORER) */
    if (((obj->serial.uart->FSR.WORD & 0x009Cu) != 0)  ||
       (obj->serial.uart->LSR.BIT.ORER == 1)) {
        /* ---- Detect receive error ---- */
        /* Disable reception             */
        /* Reset receiving FIFO          */
        /* Clearing FIFO reception reset */
        /* Error bit clear               */
        /* Enable reception              */
        obj->serial.uart->SCR.BIT.RE = 0;
        obj->serial.uart->FCR.BIT.RFRST = 1;
        obj->serial.uart->FCR.BIT.RFRST = 0;
        obj->serial.uart->FSR.WORD &=~0x009Cu;
        obj->serial.uart->LSR.BIT.ORER = 0;
        obj->serial.uart->SCR.BIT.RE = 1;
        return -1;
    }

    /* Is there receive FIFO data? */
    while (obj->serial.uart->FSR.BIT.RDF == 0) {
        /* Wait */
    }

    /* Read receive data */
    data = (int)((obj->serial.uart->FRDR.BYTE) & 0xFFu);
    /* Clear DR,RDF */
    obj->serial.uart->FSR.BIT.RDF = 0;

    return data;
}

void serial_putc(serial_t *obj, int c) {
#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return;
    }
#endif

    /* Check if it is possible to transmit (TDFE flag) */
    while (obj->serial.uart->FSR.BIT.TDFE == 0) {
        /* Wait */
    }

    /* Write the receiving data in TDR */
    obj->serial.uart->FTDR.BYTE = (uint8_t)c;

    /* Clear TDFE and TEND flag */
    obj->serial.uart->FSR.WORD &= ~0x0060u;
}

int serial_readable(serial_t *obj) {
    if (obj->serial.uart->FSR.BIT.RDF == 0) {
        return 0;
    } else {
        return 1;
    }
}

int serial_writable(serial_t *obj) {
#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return 0;
    }
#endif
    if (obj->serial.uart->FSR.BIT.TDFE == 0) {
        return 0;
    } else {
        return 1;
    }
}

void serial_clear(serial_t *obj) {
#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return;
    }
#endif
    core_util_critical_section_enter();
    obj->serial.uart->FCR.WORD |=  0x0006u;   // TFRST = 1, RFRST = 1
    obj->serial.uart->FCR.WORD &= ~0x0006u;   // TFRST = 0, RFRST = 0
    obj->serial.uart->FSR.WORD &= ~0x0093u;   // ER, BRK, RDF, DR = 0
    core_util_critical_section_exit();
}

void serial_pinout_tx(PinName tx) {
    pinmap_pinout(tx, PinMap_UART_TX);
}

void serial_break_set(serial_t *obj) {
    core_util_critical_section_enter();
    obj->serial.uart->SCR.BIT.TE = 0;
    core_util_critical_section_exit();
}

void serial_break_clear(serial_t *obj) {
#if defined(PRINTF_NOT_USE)
    if ((int)obj->serial.ch == NC) {
        return;
    }
#endif
    core_util_critical_section_enter();
    obj->serial.uart->SCR.BIT.TE = 1;
    core_util_critical_section_exit();
}

#if DEVICE_SERIAL_FC
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
    // determine the UART to use

    if (type == FlowControlRTSCTS) {
        core_util_critical_section_enter();
        obj->serial.uart->FCR.BIT.MCE  = 0x1;     // CTS/RTS enable
        core_util_critical_section_exit();
        pinmap_pinout(rxflow, PinMap_UART_RTS);
        pinmap_pinout(txflow, PinMap_UART_CTS);
    } else {
        core_util_critical_section_enter();
        obj->serial.uart->FCR.BIT.MCE  = 0x0;     // CTS/RTS diable
        core_util_critical_section_exit();
    }
}
#endif

static uint8_t serial_available_buffer(serial_t *obj) {
    return 1;
}

const PinMap *serial_tx_pinmap()
{
    return PinMap_UART_TX;
}

const PinMap *serial_rx_pinmap()
{
    return PinMap_UART_RX;
}

const PinMap *serial_cts_pinmap()
{
    return PinMap_UART_CTS;
}

const PinMap *serial_rts_pinmap()
{
    return PinMap_UART_RTS;
}

#if DEVICE_SERIAL_ASYNCH

/******************************************************************************
 * ASYNCHRONOUS HAL
 ******************************************************************************/
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) {
    int i;
    buffer_t *buf = &obj->tx_buff;
    struct serial_global_data_s *data = uart_data + obj->serial.ch;

    if (tx_length == 0) {
        return 0;
    }

    buf->buffer = (void *)tx;
    buf->length = tx_length * tx_width / 8;
    buf->pos = 0;
    buf->width = tx_width;
    data->tranferring_obj = obj;
    data->async_tx_callback = handler;
    serial_irq_set(obj, TxIrq, 1);

    while (!serial_writable(obj));
    i = buf->length;
    if (serial_available_buffer(obj) < i) {
        i = serial_available_buffer(obj);
    }
    do {
        uint8_t c = *(uint8_t *)buf->buffer;
        obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + 1;
        ++buf->pos;
	    obj->serial.uart->FTDR.BYTE = c;
	    obj->serial.uart->FSR.WORD &= ~0x0060u;
    } while (--i);

    return buf->length;
}

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) {
    buffer_t *buf = &obj->rx_buff;
    struct serial_global_data_s *data = uart_data + obj->serial.ch;

    if (rx_length == 0) {
        return;
    }

    buf->buffer = rx;
    buf->length = rx_length * rx_width / 8;
    buf->pos = 0;
    buf->width = rx_width;
    obj->char_match = char_match;
    obj->char_found = 0;
    data->receiving_obj = obj;
    data->async_rx_callback = handler;
    data->event = 0;
    data->wanted_rx_events = event;

    serial_irq_set(obj, RxIrq, 1);
    serial_irq_err_set(obj, 1);
}

uint8_t serial_tx_active(serial_t *obj) {
    return uart_data[obj->serial.ch].tranferring_obj != NULL;
}

uint8_t serial_rx_active(serial_t *obj) {
    return uart_data[obj->serial.ch].receiving_obj != NULL;
}

int serial_irq_handler_asynch(serial_t *obj) {
    return uart_data[obj->serial.ch].event;
}

void serial_tx_abort_asynch(serial_t *obj) {
    uart_data[obj->serial.ch].tranferring_obj = NULL;
    obj->serial.uart->FCR.BIT.TFRST = 1;
    obj->serial.uart->FCR.BIT.TFRST = 0;
}

void serial_rx_abort_asynch(serial_t *obj) {
    uart_data[obj->serial.ch].receiving_obj = NULL;
    obj->serial.uart->FCR.BIT.RFRST = 1;
    obj->serial.uart->FCR.BIT.RFRST = 0;
}

#endif
#endif