mbed library sources. Supersedes mbed-src.
Fork of mbed-dev by
Diff: targets/TARGET_NUVOTON/TARGET_M451/serial_api.c
- Revision:
- 165:e614a9f1c9e2
- Parent:
- 161:2cc1468da177
- Child:
- 172:7d866c31b3c5
--- a/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c Wed May 10 12:06:41 2017 +0100 +++ b/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c Fri May 26 12:39:01 2017 +0100 @@ -24,6 +24,7 @@ #include "PeripheralPins.h" #include "nu_modutil.h" #include "nu_bitutil.h" +#include <string.h> #if DEVICE_SERIAL_ASYNCH #include "dma_api.h" @@ -61,6 +62,8 @@ static void serial_tx_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable); static void serial_rx_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable); +static void serial_enable_interrupt(serial_t *obj, SerialIrq irq, uint32_t enable); +static void serial_rollback_interrupt(serial_t *obj, SerialIrq irq); static int serial_write_async(serial_t *obj); static int serial_read_async(serial_t *obj); @@ -159,7 +162,7 @@ const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; @@ -186,6 +189,7 @@ serial_format(obj, 8, ParityNone, 1); obj->serial.vec = var->vec; + obj->serial.irq_en = 0; #if DEVICE_SERIAL_ASYNCH obj->serial.dma_usage_tx = DMA_USAGE_NEVER; @@ -212,7 +216,7 @@ { const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; @@ -329,7 +333,7 @@ const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); obj->serial.irq_handler = (uint32_t) handler; obj->serial.irq_id = id; @@ -340,51 +344,18 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { - if (enable) { - const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); - MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); - - NVIC_SetVector(modinit->irq_n, (uint32_t) obj->serial.vec); - NVIC_EnableIRQ(modinit->irq_n); - - struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; - // Multiple serial S/W objects for single UART H/W module possibly. - // Bind serial S/W object to UART H/W module as interrupt is enabled. - var->obj = obj; - - switch (irq) { - // NOTE: Setting inten_msk first to avoid race condition - case RxIrq: - obj->serial.inten_msk = obj->serial.inten_msk | (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); - UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); - break; - case TxIrq: - obj->serial.inten_msk = obj->serial.inten_msk | UART_INTEN_THREIEN_Msk; - UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); - break; - } - } else { // disable - switch (irq) { - case RxIrq: - UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); - obj->serial.inten_msk = obj->serial.inten_msk & ~(UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); - break; - case TxIrq: - UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); - obj->serial.inten_msk = obj->serial.inten_msk & ~UART_INTEN_THREIEN_Msk; - break; - } - } + obj->serial.irq_en = enable; + serial_enable_interrupt(obj, irq, enable); } int serial_getc(serial_t *obj) { - // TODO: Fix every byte access requires accompaniness of one interrupt. This degrades performance much. + // NOTE: Every byte access requires accompaniment of one interrupt. This has side effect of performance degradation. while (! serial_readable(obj)); int c = UART_READ(((UART_T *) NU_MODBASE(obj->serial.uart))); - // Simulate clear of the interrupt flag + // NOTE: On Nuvoton targets, no H/W IRQ to match TxIrq/RxIrq. + // Simulation of TxIrq/RxIrq requires the call to Serial::putc()/Serial::getc() respectively. if (obj->serial.inten_msk & (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)) { UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); } @@ -394,11 +365,12 @@ void serial_putc(serial_t *obj, int c) { - // TODO: Fix every byte access requires accompaniness of one interrupt. This degrades performance much. + // NOTE: Every byte access requires accompaniment of one interrupt. This has side effect of performance degradation. while (! serial_writable(obj)); UART_WRITE(((UART_T *) NU_MODBASE(obj->serial.uart)), c); - // Simulate clear of the interrupt flag + // NOTE: On Nuvoton targets, no H/W IRQ to match TxIrq/RxIrq. + // Simulation of TxIrq/RxIrq requires the call to Serial::putc()/Serial::getc() respectively. if (obj->serial.inten_msk & UART_INTEN_THREIEN_Msk) { UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); } @@ -500,7 +472,7 @@ // DMA way const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); PDMA_T *pdma_base = dma_modbase(); @@ -563,7 +535,7 @@ // DMA way const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); PDMA_T *pdma_base = dma_modbase(); @@ -612,10 +584,8 @@ } // Necessary for both interrupt way and DMA way - serial_irq_set(obj, TxIrq, 0); - // FIXME: more complete abort operation - //UART_HAL_DisableTransmitter(obj->serial.serial.address); - //UART_HAL_FlushTxFifo(obj->serial.serial.address); + serial_enable_interrupt(obj, TxIrq, 0); + serial_rollback_interrupt(obj, TxIrq); } void serial_rx_abort_asynch(serial_t *obj) @@ -633,20 +603,30 @@ } // Necessary for both interrupt way and DMA way - serial_irq_set(obj, RxIrq, 0); - // FIXME: more complete abort operation - //UART_HAL_DisableReceiver(obj->serial.serial.address); - //UART_HAL_FlushRxFifo(obj->serial.serial.address); + serial_enable_interrupt(obj, RxIrq, 0); + serial_rollback_interrupt(obj, RxIrq); } uint8_t serial_tx_active(serial_t *obj) { - return serial_is_irq_en(obj, TxIrq); + // NOTE: Judge by serial_is_irq_en(obj, TxIrq) doesn't work with sync/async modes interleaved. Change with TX FIFO empty flag. + const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); + + struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; + return (obj->serial.vec == var->vec_async); } uint8_t serial_rx_active(serial_t *obj) { - return serial_is_irq_en(obj, RxIrq); + // NOTE: Judge by serial_is_irq_en(obj, RxIrq) doesn't work with sync/async modes interleaved. Change with RX FIFO empty flag. + const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); + + struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; + return (obj->serial.vec == var->vec_async); } int serial_irq_handler_asynch(serial_t *obj) @@ -886,7 +866,7 @@ { const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); UART_T *uart_base = (UART_T *) NU_MODBASE(obj->serial.uart); @@ -938,7 +918,7 @@ { const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); uint32_t rx_fifo_busy = (((UART_T *) NU_MODBASE(obj->serial.uart))->FIFOSTS & UART_FIFOSTS_RXPTR_Msk) >> UART_FIFOSTS_RXPTR_Pos; //uint32_t rx_fifo_free = ((struct nu_uart_var *) modinit->var)->fifo_size_rx - rx_fifo_busy; @@ -1013,28 +993,81 @@ { const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); // Necessary for both interrupt way and DMA way struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; // With our own async vector, tx/rx handlers can be different. obj->serial.vec = var->vec_async; obj->serial.irq_handler_tx_async = (void (*)(void)) handler; - serial_irq_set(obj, TxIrq, enable); + serial_enable_interrupt(obj, TxIrq, enable); } static void serial_rx_enable_interrupt(serial_t *obj, uint32_t handler, uint8_t enable) { const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); MBED_ASSERT(modinit != NULL); - MBED_ASSERT(modinit->modname == obj->serial.uart); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); // Necessary for both interrupt way and DMA way struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; // With our own async vector, tx/rx handlers can be different. obj->serial.vec = var->vec_async; obj->serial.irq_handler_rx_async = (void (*) (void)) handler; - serial_irq_set(obj, RxIrq, enable); + serial_enable_interrupt(obj, RxIrq, enable); +} + +static void serial_enable_interrupt(serial_t *obj, SerialIrq irq, uint32_t enable) +{ + if (enable) { + const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); + + NVIC_SetVector(modinit->irq_n, (uint32_t) obj->serial.vec); + NVIC_EnableIRQ(modinit->irq_n); + + struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; + // Multiple serial S/W objects for single UART H/W module possibly. + // Bind serial S/W object to UART H/W module as interrupt is enabled. + var->obj = obj; + + switch (irq) { + // NOTE: Setting inten_msk first to avoid race condition + case RxIrq: + obj->serial.inten_msk = obj->serial.inten_msk | (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); + UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); + break; + case TxIrq: + obj->serial.inten_msk = obj->serial.inten_msk | UART_INTEN_THREIEN_Msk; + UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); + break; + } + } + else { // disable + switch (irq) { + case RxIrq: + UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); + obj->serial.inten_msk = obj->serial.inten_msk & ~(UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); + break; + case TxIrq: + UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); + obj->serial.inten_msk = obj->serial.inten_msk & ~UART_INTEN_THREIEN_Msk; + break; + } + } +} + +static void serial_rollback_interrupt(serial_t *obj, SerialIrq irq) +{ + const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == (int) obj->serial.uart); + + struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; + + obj->serial.vec = var->vec; + serial_enable_interrupt(obj, irq, obj->serial.irq_en); } static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch)