Forked.

Fork of mbed-dev by mbed official

Revision:
165:e614a9f1c9e2
Parent:
161:2cc1468da177
Child:
172:7d866c31b3c5
diff -r 289d4deac6e4 -r e614a9f1c9e2 targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c
--- a/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c	Wed May 10 12:06:41 2017 +0100
+++ b/targets/TARGET_NUVOTON/TARGET_NUC472/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"
@@ -65,6 +66,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);
 
@@ -189,7 +192,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;
     
@@ -216,6 +219,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;
@@ -242,7 +246,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;
     
@@ -361,7 +365,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;
@@ -372,51 +376,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));
     }
@@ -426,11 +397,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);
     }
@@ -542,7 +514,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();
         
@@ -603,7 +575,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();
         
@@ -650,10 +622,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)
@@ -671,20 +641,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)
@@ -934,7 +914,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);
     
@@ -986,7 +966,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;
@@ -1061,28 +1041,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)