mbed library sources

Dependents:   frdm_kl05z_gpio_test

Fork of mbed-src by mbed official

Revision:
64:7b352733b00a
Parent:
51:7838415c99e7
Child:
108:4cb9db2ced35
--- a/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c	Thu Dec 19 09:00:06 2013 +0000
+++ b/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c	Thu Dec 19 13:15:07 2013 +0000
@@ -21,6 +21,7 @@
 #include "cmsis.h"
 #include "pinmap.h"
 #include "error.h"
+#include "gpio_api.h"
 
 /******************************************************************************
  * INITIALIZATION
@@ -51,12 +52,35 @@
     {NC   , NC    , 0}
 };
 
-static uint32_t serial_irq_ids[UART_NUM] = {0};
+static const PinMap PinMap_UART_RTS[] = {
+    {P0_22, UART_1, 1},
+    {P2_7,  UART_1, 2},
+    {NC,    NC,     0}
+};
+
+static const PinMap PinMap_UART_CTS[] = {
+    {P0_17, UART_1, 1},
+    {P2_2,  UART_1, 2},
+    {NC,    NC,     0}
+};
+
+#define UART_MCR_RTSEN_MASK     (1 << 6)
+#define UART_MCR_CTSEN_MASK     (1 << 7)
+#define UART_MCR_FLOWCTRL_MASK  (UART_MCR_RTSEN_MASK | UART_MCR_CTSEN_MASK)
+
 static uart_irq_handler irq_handler;
 
 int stdio_uart_inited = 0;
 serial_t stdio_uart;
 
+struct serial_global_data_s {
+    uint32_t serial_irq_id;
+    gpio_t sw_rts, sw_cts;
+    uint8_t rx_irq_set_flow, rx_irq_set_api;
+};
+
+static struct serial_global_data_s uart_data[UART_NUM];
+
 void serial_init(serial_t *obj, PinName tx, PinName rx) {
     int is_stdio_uart = 0;
     
@@ -106,7 +130,9 @@
         case UART_2: obj->index = 2; break;
         case UART_3: obj->index = 3; break;
     }
-    obj->count = 0;
+    uart_data[obj->index].sw_rts.pin = NC;
+    uart_data[obj->index].sw_cts.pin = NC;
+    serial_set_flow_control(obj, FlowControlNone, NC, NC);
     
     is_stdio_uart = (uart == STDIO_UART) ? (1) : (0);
     
@@ -117,7 +143,7 @@
 }
 
 void serial_free(serial_t *obj) {
-    serial_irq_ids[obj->index] = 0;
+    uart_data[obj->index].serial_irq_id = 0;
 }
 
 // serial_baud
@@ -251,7 +277,7 @@
 /******************************************************************************
  * INTERRUPTS HANDLING
  ******************************************************************************/
-static inline void uart_irq(uint32_t iir, uint32_t index) {
+static inline void uart_irq(uint32_t iir, uint32_t index, LPC_UART_TypeDef *puart) {
     // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
     SerialIrq irq_type;
     switch (iir) {
@@ -259,22 +285,28 @@
         case 2: irq_type = RxIrq; break;
         default: return;
     }
-    
-    if (serial_irq_ids[index] != 0)
-        irq_handler(serial_irq_ids[index], irq_type);
+    if ((RxIrq == irq_type) && (NC != uart_data[index].sw_rts.pin)) {
+        gpio_write(&uart_data[index].sw_rts, 1);
+        // Disable interrupt if it wasn't enabled by other part of the application
+        if (!uart_data[index].rx_irq_set_api)
+            puart->IER &= ~(1 << RxIrq);
+    }
+    if (uart_data[index].serial_irq_id != 0)
+        if ((irq_type != RxIrq) || (uart_data[index].rx_irq_set_api))
+            irq_handler(uart_data[index].serial_irq_id, irq_type);
 }
 
-void uart0_irq() {uart_irq((LPC_UART0->IIR >> 1) & 0x7, 0);}
-void uart1_irq() {uart_irq((LPC_UART1->IIR >> 1) & 0x7, 1);}
-void uart2_irq() {uart_irq((LPC_UART2->IIR >> 1) & 0x7, 2);}
-void uart3_irq() {uart_irq((LPC_UART3->IIR >> 1) & 0x7, 3);}
+void uart0_irq() {uart_irq((LPC_UART0->IIR >> 1) & 0x7, 0, (LPC_UART_TypeDef*)LPC_UART0);}
+void uart1_irq() {uart_irq((LPC_UART1->IIR >> 1) & 0x7, 1, (LPC_UART_TypeDef*)LPC_UART1);}
+void uart2_irq() {uart_irq((LPC_UART2->IIR >> 1) & 0x7, 2, (LPC_UART_TypeDef*)LPC_UART2);}
+void uart3_irq() {uart_irq((LPC_UART3->IIR >> 1) & 0x7, 3, (LPC_UART_TypeDef*)LPC_UART3);}
 
 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
     irq_handler = handler;
-    serial_irq_ids[obj->index] = id;
+    uart_data[obj->index].serial_irq_id = id;
 }
 
-void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
+static void serial_irq_set_internal(serial_t *obj, SerialIrq irq, uint32_t enable) {
     IRQn_Type irq_n = (IRQn_Type)0;
     uint32_t vector = 0;
     switch ((int)obj->uart) {
@@ -288,7 +320,7 @@
         obj->uart->IER |= 1 << irq;
         NVIC_SetVector(irq_n, vector);
         NVIC_EnableIRQ(irq_n);
-    } else { // disable
+    } else if ((TxIrq == irq) || (uart_data[obj->index].rx_irq_set_api + uart_data[obj->index].rx_irq_set_flow == 0)) { // disable
         int all_disabled = 0;
         SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
         obj->uart->IER &= ~(1 << irq);
@@ -298,18 +330,33 @@
     }
 }
 
+void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
+    if (RxIrq == irq)
+        uart_data[obj->index].rx_irq_set_api = enable;
+    serial_irq_set_internal(obj, irq, enable);
+}
+
+static void serial_flow_irq_set(serial_t *obj, uint32_t enable) {
+    uart_data[obj->index].rx_irq_set_flow = enable;
+    serial_irq_set_internal(obj, RxIrq, enable);
+}
+
 /******************************************************************************
  * READ/WRITE
  ******************************************************************************/
 int serial_getc(serial_t *obj) {
     while (!serial_readable(obj));
-    return obj->uart->RBR;
+    int data = obj->uart->RBR;
+    if (NC != uart_data[obj->index].sw_rts.pin) {
+        gpio_write(&uart_data[obj->index].sw_rts, 0);
+        obj->uart->IER |= 1 << RxIrq;
+    }
+    return data;
 }
 
 void serial_putc(serial_t *obj, int c) {
     while (!serial_writable(obj));
     obj->uart->THR = c;
-    obj->count++;
 }
 
 int serial_readable(serial_t *obj) {
@@ -318,11 +365,10 @@
 
 int serial_writable(serial_t *obj) {
     int isWritable = 1;
-    if (obj->uart->LSR & 0x20)
-        obj->count = 0;
-    else if (obj->count >= 16)
-        isWritable = 0;
-        
+    if (NC != uart_data[obj->index].sw_cts.pin)
+        isWritable = gpio_read(&uart_data[obj->index].sw_cts) == 0;
+    if (isWritable)
+        isWritable = obj->uart->LSR & 0x40;
     return isWritable;
 }
 
@@ -345,3 +391,49 @@
     obj->uart->LCR &= ~(1 << 6);
 }
 
+void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
+    // Only UART1 has hardware flow control on LPC176x
+    LPC_UART1_TypeDef *uart1 = (uint32_t)obj->uart == (uint32_t)LPC_UART1 ? LPC_UART1 : NULL;
+    int index = obj->index;
+
+    // First, disable flow control completely
+    if (uart1)
+        uart1->MCR = uart1->MCR & ~UART_MCR_FLOWCTRL_MASK;
+    uart_data[index].sw_rts.pin = uart_data[index].sw_cts.pin = NC;
+    serial_flow_irq_set(obj, 0);
+    if (FlowControlNone == type)
+        return;
+    // Check type(s) of flow control to use
+    UARTName uart_rts = (UARTName)pinmap_find_peripheral(rxflow, PinMap_UART_RTS);
+    UARTName uart_cts = (UARTName)pinmap_find_peripheral(txflow, PinMap_UART_CTS);
+    if (((FlowControlCTS == type) || (FlowControlRTSCTS == type)) && (NC != txflow)) {
+        // Can this be enabled in hardware?
+        if ((UART_1 == uart_cts) && (NULL != uart1)) {
+            // Enable auto-CTS mode
+            uart1->MCR |= UART_MCR_CTSEN_MASK;
+            pinmap_pinout(txflow, PinMap_UART_CTS);
+        } else {
+            // Can't enable in hardware, use software emulation
+            gpio_init(&uart_data[index].sw_cts, txflow, PIN_INPUT);
+        }
+    }
+    if (((FlowControlRTS == type) || (FlowControlRTSCTS == type)) && (NC != rxflow)) {
+        // Enable FIFOs, trigger level of 1 char on RX FIFO
+        obj->uart->FCR = 1 << 0  // FIFO Enable - 0 = Disables, 1 = Enabled
+                       | 1 << 1  // Rx Fifo Reset
+                       | 1 << 2  // Tx Fifo Reset
+                       | 0 << 6; // Rx irq trigger level - 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars
+         // Can this be enabled in hardware?
+        if ((UART_1 == uart_rts) && (NULL != uart1)) {
+            // Enable auto-RTS mode
+            uart1->MCR |= UART_MCR_RTSEN_MASK;
+            pinmap_pinout(rxflow, PinMap_UART_RTS);
+        } else { // can't enable in hardware, use software emulation
+            gpio_init(&uart_data[index].sw_rts, rxflow, PIN_OUTPUT);
+            gpio_write(&uart_data[index].sw_rts, 0);
+            // Enable RX interrupt
+            serial_flow_irq_set(obj, 1);
+        }
+    }
+}
+