Forked.

Fork of mbed-dev by mbed official

Revision:
151:5eaa88a5bcc7
Parent:
149:156823d33999
Child:
153:fa9ff456f731
--- a/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c	Tue Nov 08 17:45:16 2016 +0000
+++ b/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c	Thu Nov 24 17:03:03 2016 +0000
@@ -31,6 +31,7 @@
 #endif
 
 struct nu_uart_var {
+    uint32_t    ref_cnt;                // Reference count of the H/W module
     serial_t *  obj;
     uint32_t    fifo_size_tx;
     uint32_t    fifo_size_rx;
@@ -84,6 +85,7 @@
 #endif
 
 static struct nu_uart_var uart0_var = {
+    .ref_cnt            =   0,
     .obj                =   NULL,
     .fifo_size_tx       =   64,
     .fifo_size_rx       =   64,
@@ -95,6 +97,7 @@
 #endif
 };
 static struct nu_uart_var uart1_var = {
+    .ref_cnt            =   0,
     .obj                =   NULL,
     .fifo_size_tx       =   16,
     .fifo_size_rx       =   16,
@@ -106,6 +109,7 @@
 #endif
 };
 static struct nu_uart_var uart2_var = {
+    .ref_cnt            =   0,
     .obj                =   NULL,
     .fifo_size_tx       =   16,
     .fifo_size_rx       =   16,
@@ -117,6 +121,7 @@
 #endif
 };
 static struct nu_uart_var uart3_var = {
+    .ref_cnt            =   0,
     .obj                =   NULL,
     .fifo_size_tx       =   16,
     .fifo_size_rx       =   16,
@@ -128,6 +133,7 @@
 #endif
 };
 static struct nu_uart_var uart4_var = {
+    .ref_cnt            =   0,
     .obj                =   NULL,
     .fifo_size_tx       =   16,
     .fifo_size_rx       =   16,
@@ -139,6 +145,7 @@
 #endif
 };
 static struct nu_uart_var uart5_var = {
+    .ref_cnt            =   0,
     .obj                =   NULL,
     .fifo_size_tx       =   16,
     .fifo_size_rx       =   16,
@@ -170,7 +177,7 @@
 
 void serial_init(serial_t *obj, PinName tx, PinName rx)
 {
-    // NOTE: serial_init() gets called from _sys_open() timing of which is before main()/mbed_sdk_init().
+    // NOTE: With armcc, serial_init() gets called from _sys_open() timing of which is before main()/mbed_sdk_init().
     mbed_sdk_init();
     
     // Determine which UART_x the pins are used for
@@ -184,32 +191,31 @@
     MBED_ASSERT(modinit != NULL);
     MBED_ASSERT(modinit->modname == obj->serial.uart);
     
-    // Reset this module
-    SYS_ResetModule(modinit->rsetidx);
+    struct nu_uart_var *var = (struct nu_uart_var *) modinit->var;
     
-    // Select IP clock source
-    CLK_SetModuleClock(modinit->clkidx, modinit->clksrc, modinit->clkdiv);
-    // Enable IP clock
-    CLK_EnableModuleClock(modinit->clkidx);
+    if (! var->ref_cnt) {
+        // Reset this module
+        SYS_ResetModule(modinit->rsetidx);
+    
+        // Select IP clock source
+        CLK_SetModuleClock(modinit->clkidx, modinit->clksrc, modinit->clkdiv);
+        // Enable IP clock
+        CLK_EnableModuleClock(modinit->clkidx);
 
-    pinmap_pinout(tx, PinMap_UART_TX);
-    pinmap_pinout(rx, PinMap_UART_RX);
-    // FIXME: Why PullUp?
-    //if (tx != NC) {
-    //    pin_mode(tx, PullUp);
-    //}
-    //if (rx != NC) {
-    //    pin_mode(rx, PullUp);
-    //}
-    obj->serial.pin_tx = tx;
-    obj->serial.pin_rx = rx;
+        pinmap_pinout(tx, PinMap_UART_TX);
+        pinmap_pinout(rx, PinMap_UART_RX);
+    
+        obj->serial.pin_tx = tx;
+        obj->serial.pin_rx = rx;
+    }
+    var->ref_cnt ++;
     
     // Configure the UART module and set its baudrate
     serial_baud(obj, 9600);
     // Configure data bits, parity, and stop bits
     serial_format(obj, 8, ParityNone, 1);
     
-    obj->serial.vec = ((struct nu_uart_var *) modinit->var)->vec;
+    obj->serial.vec = var->vec;
     
 #if DEVICE_SERIAL_ASYNCH
     obj->serial.dma_usage_tx = DMA_USAGE_NEVER;
@@ -220,51 +226,61 @@
 #endif
 
     // For stdio management
-    if (obj == &stdio_uart) {
+    if (obj->serial.uart == STDIO_UART) {
         stdio_uart_inited = 1;
-        /* NOTE: Not required anymore because stdio_uart will be manually initialized in mbed-drivers/source/retarget.cpp from mbed beta */
-        //memcpy(&stdio_uart, obj, sizeof(serial_t));
+        memcpy(&stdio_uart, obj, sizeof(serial_t));
     }
     
-    // Mark this module to be inited.
-    int i = modinit - uart_modinit_tab;
-    uart_modinit_mask |= 1 << i;
+    if (var->ref_cnt) {
+        // Mark this module to be inited.
+        int i = modinit - uart_modinit_tab;
+        uart_modinit_mask |= 1 << i;
+    }
 }
 
 void serial_free(serial_t *obj)
 {
-#if DEVICE_SERIAL_ASYNCH
-    if (obj->serial.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) {
-        dma_channel_free(obj->serial.dma_chn_id_tx);
-        obj->serial.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
-    }
-    if (obj->serial.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) {
-        dma_channel_free(obj->serial.dma_chn_id_rx);
-        obj->serial.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
-    }
-#endif
-
-    UART_Close((UART_T *) NU_MODBASE(obj->serial.uart));
-    
     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);
     
-    UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_THREIEN_Msk | UART_INTEN_RXTOIEN_Msk));
-    NVIC_DisableIRQ(modinit->irq_n);
+    struct nu_uart_var *var = (struct nu_uart_var *) modinit->var;
     
-    // Disable IP clock
-    CLK_DisableModuleClock(modinit->clkidx);
+    var->ref_cnt --;
+    if (! var->ref_cnt) {
+#if DEVICE_SERIAL_ASYNCH
+        if (obj->serial.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) {
+            dma_channel_free(obj->serial.dma_chn_id_tx);
+            obj->serial.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
+        }
+        if (obj->serial.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) {
+            dma_channel_free(obj->serial.dma_chn_id_rx);
+            obj->serial.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
+        }
+#endif
+
+        UART_Close((UART_T *) NU_MODBASE(obj->serial.uart));
     
-    ((struct nu_uart_var *) modinit->var)->obj = NULL;
+        UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_THREIEN_Msk | UART_INTEN_RXTOIEN_Msk));
+        NVIC_DisableIRQ(modinit->irq_n);
     
-    if (obj == &stdio_uart) {
+        // Disable IP clock
+        CLK_DisableModuleClock(modinit->clkidx);
+    }
+    
+    if (var->obj == obj) {
+        var->obj = NULL;
+    }
+    
+    if (obj->serial.uart == STDIO_UART) {
         stdio_uart_inited = 0;
     }
     
-    // Mark this module to be deinited.
-    int i = modinit - uart_modinit_tab;
-    uart_modinit_mask &= ~(1 << i);
+    if (! var->ref_cnt) {
+        // Mark this module to be deinited.
+        int i = modinit - uart_modinit_tab;
+        uart_modinit_mask &= ~(1 << i);
+    }
 }
 
 void serial_baud(serial_t *obj, int baudrate) {
@@ -345,7 +361,6 @@
     MBED_ASSERT(modinit != NULL);
     MBED_ASSERT(modinit->modname == obj->serial.uart);
     
-    ((struct nu_uart_var *) modinit->var)->obj = obj;
     obj->serial.irq_handler = (uint32_t) handler;
     obj->serial.irq_id = id;
     
@@ -363,6 +378,11 @@
         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:
@@ -668,7 +688,7 @@
     int event_rx = 0;
     int event_tx = 0;
     
-    // Necessary for both interrup way and DMA way
+    // Necessary for both interrupt way and DMA way
     if (serial_is_irq_en(obj, RxIrq)) {
         event_rx = serial_rx_event_check(obj);
         if (event_rx) {
@@ -1040,9 +1060,9 @@
     MBED_ASSERT(modinit->modname == obj->serial.uart);
     
     // Necessary for both interrupt way and DMA way
-    ((struct nu_uart_var *) modinit->var)->obj = obj;
+    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 = ((struct nu_uart_var *) modinit->var)->vec_async;
+    obj->serial.vec = var->vec_async;
     obj->serial.irq_handler_tx_async = (void (*)(void)) handler;
     serial_irq_set(obj, TxIrq, enable);
 }
@@ -1054,9 +1074,9 @@
     MBED_ASSERT(modinit->modname == obj->serial.uart);
     
     // Necessary for both interrupt way and DMA way
-    ((struct nu_uart_var *) modinit->var)->obj = obj;
+    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 = ((struct nu_uart_var *) modinit->var)->vec_async;
+    obj->serial.vec = var->vec_async;
     obj->serial.irq_handler_rx_async = (void (*) (void)) handler;
     serial_irq_set(obj, RxIrq, enable);
 }