From fbeb52d613b18148328dda99c560e9a1529990d5 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Tue, 3 Dec 2013 10:21:41 +0200 Subject: [PATCH 1/6] Added RTS/CTS flow control Currently implemented only for LPC1768. On this platform, when hardware flow control is not directly supported, it will be emulated. Also added "not_implemented.c" as a placeholder for various HAL functions that might not be implemented on all platforms (in this particular case, serial_set_flow_control). These are weak implementations that default to a "not implemented" error message. --- libraries/mbed/api/SerialBase.h | 15 +++ libraries/mbed/common/SerialBase.cpp | 20 ++++ libraries/mbed/common/not_implemented.c | 28 +++++ libraries/mbed/common/pinmap_common.c | 19 +-- libraries/mbed/hal/pinmap.h | 1 + libraries/mbed/hal/serial_api.h | 9 ++ .../hal/TARGET_NXP/TARGET_LPC176X/objects.h | 4 +- .../TARGET_NXP/TARGET_LPC176X/serial_api.c | 109 ++++++++++++++++-- 8 files changed, 185 insertions(+), 20 deletions(-) create mode 100644 libraries/mbed/common/not_implemented.c diff --git a/libraries/mbed/api/SerialBase.h b/libraries/mbed/api/SerialBase.h index 77c0d006be..f3b1a9e0d7 100644 --- a/libraries/mbed/api/SerialBase.h +++ b/libraries/mbed/api/SerialBase.h @@ -51,6 +51,13 @@ public: TxIrq }; + enum Flow { + Disabled = 0, + RTS, + CTS, + RTSCTS + }; + /** Set the transmission format used by the serial port * * @param bits The number of bits in a word (5-8; default = 8) @@ -99,6 +106,14 @@ public: /** Generate a break condition on the serial line */ void send_break(); + + /** Set the flow control type on the serial port + * + * @param type the flow control type (Disabled, RTS, CTS, RTSCTS) + * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS) + * @param flow2 the second flow control pin (CTS for RTSCTS) + */ + void set_flow_control(Flow type, PinName flow1=NC, PinName flow2=NC); static void _irq_handler(uint32_t id, SerialIrq irq_type); diff --git a/libraries/mbed/common/SerialBase.cpp b/libraries/mbed/common/SerialBase.cpp index 9026080a4f..10a6fb61dd 100644 --- a/libraries/mbed/common/SerialBase.cpp +++ b/libraries/mbed/common/SerialBase.cpp @@ -81,6 +81,26 @@ void SerialBase::send_break() { serial_break_clear(&_serial); } +void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) { + FlowControl flow_type = (FlowControl)type; + switch(type) { + case RTS: + serial_set_flow_control(&_serial, flow_type, flow1, NC); + break; + + case CTS: + serial_set_flow_control(&_serial, flow_type, NC, flow1); + break; + + case RTSCTS: + serial_set_flow_control(&_serial, flow_type, flow1, flow2); + break; + + default: + break; + } +} + } // namespace mbed #endif diff --git a/libraries/mbed/common/not_implemented.c b/libraries/mbed/common/not_implemented.c new file mode 100644 index 0000000000..53170b0dd2 --- /dev/null +++ b/libraries/mbed/common/not_implemented.c @@ -0,0 +1,28 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * 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. + */ + +// Default versions of various HAL functions that might not be implemented for some platforms. + +#include "toolchain.h" +#include "serial_api.h" +#include "error.h" + +WEAK void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow); +WEAK void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) { + if (FlowControlNone != type) + error("hardware flow control not implemented on this platform"); +} + diff --git a/libraries/mbed/common/pinmap_common.c b/libraries/mbed/common/pinmap_common.c index 66ccf963ce..eef617fd45 100644 --- a/libraries/mbed/common/pinmap_common.c +++ b/libraries/mbed/common/pinmap_common.c @@ -44,17 +44,22 @@ uint32_t pinmap_merge(uint32_t a, uint32_t b) { return (uint32_t)NC; } -uint32_t pinmap_peripheral(PinName pin, const PinMap* map) { - if (pin == (PinName)NC) - return (uint32_t)NC; - +uint32_t pinmap_find_peripheral(PinName pin, const PinMap* map) { while (map->pin != NC) { if (map->pin == pin) return map->peripheral; map++; } - - // no mapping available - error("pinmap not found for peripheral"); return (uint32_t)NC; } + +uint32_t pinmap_peripheral(PinName pin, const PinMap* map) { + uint32_t peripheral = (uint32_t)NC; + + if (pin == (PinName)NC) + return (uint32_t)NC; + peripheral = pinmap_find_peripheral(pin, map); + if ((uint32_t)NC == peripheral) // no mapping available + error("pinmap not found for peripheral"); + return peripheral; +} diff --git a/libraries/mbed/hal/pinmap.h b/libraries/mbed/hal/pinmap.h index 0482282eb3..653d5fe9f3 100644 --- a/libraries/mbed/hal/pinmap.h +++ b/libraries/mbed/hal/pinmap.h @@ -34,6 +34,7 @@ void pin_mode (PinName pin, PinMode mode); uint32_t pinmap_peripheral(PinName pin, const PinMap* map); uint32_t pinmap_merge (uint32_t a, uint32_t b); void pinmap_pinout (PinName pin, const PinMap *map); +uint32_t pinmap_find_peripheral(PinName pin, const PinMap* map); #ifdef __cplusplus } diff --git a/libraries/mbed/hal/serial_api.h b/libraries/mbed/hal/serial_api.h index 60a3d0243d..2b0f0c4abe 100644 --- a/libraries/mbed/hal/serial_api.h +++ b/libraries/mbed/hal/serial_api.h @@ -37,6 +37,13 @@ typedef enum { TxIrq } SerialIrq; +typedef enum { + FlowControlNone, + FlowControlRTS, + FlowControlCTS, + FlowControlRTSCTS +} FlowControl; + typedef void (*uart_irq_handler)(uint32_t id, SerialIrq event); typedef struct serial_s serial_t; @@ -60,6 +67,8 @@ void serial_break_clear(serial_t *obj); void serial_pinout_tx(PinName tx); +void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow); + #ifdef __cplusplus } #endif diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/objects.h b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/objects.h index ace5371b46..ecbd354934 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/objects.h +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/objects.h @@ -20,6 +20,7 @@ #include "PortNames.h" #include "PeripheralNames.h" #include "PinNames.h" +#include "gpio_object.h" #ifdef __cplusplus extern "C" { @@ -47,7 +48,6 @@ struct pwmout_s { struct serial_s { LPC_UART_TypeDef *uart; int index; - uint8_t count; }; struct analogin_s { @@ -71,8 +71,6 @@ struct spi_s { LPC_SSP_TypeDef *spi; }; -#include "gpio_object.h" - #ifdef __cplusplus } #endif diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c index 96baef5689..99fb5ed8c9 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c @@ -21,6 +21,7 @@ #include "cmsis.h" #include "pinmap.h" #include "error.h" +#include "gpio_api.h" /****************************************************************************** * INITIALIZATION @@ -51,12 +52,35 @@ static const PinMap PinMap_UART_RX[] = { {NC , NC , 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 uint32_t serial_irq_ids[UART_NUM] = {0}; static uart_irq_handler irq_handler; int stdio_uart_inited = 0; serial_t stdio_uart; +struct serial_global_data_s { + gpio_t sw_rts, sw_cts; + uint8_t count, initialized, irq_set_flow, 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,11 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) { case UART_2: obj->index = 2; break; case UART_3: obj->index = 3; break; } - obj->count = 0; + if (!uart_data[obj->index].initialized) { + uart_data[obj->index].sw_rts.pin = NC; + uart_data[obj->index].sw_cts.pin = NC; + uart_data[obj->index].initialized = 1; + } is_stdio_uart = (uart == STDIO_UART) ? (1) : (0); @@ -234,7 +262,9 @@ static inline void uart_irq(uint32_t iir, uint32_t index) { case 2: irq_type = RxIrq; break; default: return; } - + + if ((RxIrq == irq_type) && (uart_data[index].sw_rts.pin != NC)) + gpio_write(&uart_data[index].sw_rts, 1); if (serial_irq_ids[index] != 0) irq_handler(serial_irq_ids[index], irq_type); } @@ -249,7 +279,7 @@ void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { serial_irq_ids[obj->index] = 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) { @@ -263,7 +293,7 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { obj->uart->IER |= 1 << irq; NVIC_SetVector(irq_n, vector); NVIC_EnableIRQ(irq_n); - } else { // disable + } else if (uart_data[obj->index].irq_set_api + uart_data[obj->index].irq_set_flow == 0) { // disable int all_disabled = 0; SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq); obj->uart->IER &= ~(1 << irq); @@ -273,18 +303,30 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { } } +void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { + uart_data[obj->index].irq_set_api = enable; + serial_irq_set_internal(obj, irq, enable); +} + +static void serial_flow_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { + uart_data[obj->index].irq_set_flow = enable; + serial_irq_set_internal(obj, irq, enable); +} + /****************************************************************************** * READ/WRITE ******************************************************************************/ int serial_getc(serial_t *obj) { while (!serial_readable(obj)); + if (NC != uart_data[obj->index].sw_rts.pin) + gpio_write(&uart_data[obj->index].sw_rts, 0); return obj->uart->RBR; } void serial_putc(serial_t *obj, int c) { while (!serial_writable(obj)); obj->uart->THR = c; - obj->count++; + uart_data[obj->index].count++; } int serial_readable(serial_t *obj) { @@ -293,11 +335,14 @@ int serial_readable(serial_t *obj) { 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) { + if (obj->uart->LSR & 0x20) + uart_data[obj->index].count = 0; + else if (uart_data[obj->index].count >= 16) + isWritable = 0; + } return isWritable; } @@ -320,3 +365,47 @@ void serial_break_clear(serial_t *obj) { 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; + serial_flow_irq_set(obj, RxIrq, 0); + uart_data[index].sw_rts.pin = uart_data[index].sw_cts.pin = NC; + 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; + } 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; + } 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, RxIrq, 1); + } + } +} + From 2ac6c4c53190a358dc75ac78e2109b273b5f6187 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Wed, 4 Dec 2013 19:46:12 +0200 Subject: [PATCH 2/6] Fixed RTS/CTS bit-banging on LPC1768 --- .../TARGET_NXP/TARGET_LPC176X/serial_api.c | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c index 99fb5ed8c9..65c9d1f318 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c @@ -76,7 +76,7 @@ serial_t stdio_uart; struct serial_global_data_s { gpio_t sw_rts, sw_cts; - uint8_t count, initialized, irq_set_flow, irq_set_api; + uint8_t count, initialized, rx_irq_set_flow, rx_irq_set_api; }; static struct serial_global_data_s uart_data[UART_NUM]; @@ -254,7 +254,7 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b /****************************************************************************** * 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) { @@ -263,16 +263,20 @@ static inline void uart_irq(uint32_t iir, uint32_t index) { default: return; } - if ((RxIrq == irq_type) && (uart_data[index].sw_rts.pin != NC)) + 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 (serial_irq_ids[index] != 0) irq_handler(serial_irq_ids[index], 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; @@ -293,7 +297,7 @@ static void serial_irq_set_internal(serial_t *obj, SerialIrq irq, uint32_t enabl obj->uart->IER |= 1 << irq; NVIC_SetVector(irq_n, vector); NVIC_EnableIRQ(irq_n); - } else if (uart_data[obj->index].irq_set_api + uart_data[obj->index].irq_set_flow == 0) { // 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); @@ -304,13 +308,14 @@ static void serial_irq_set_internal(serial_t *obj, SerialIrq irq, uint32_t enabl } void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { - uart_data[obj->index].irq_set_api = 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, SerialIrq irq, uint32_t enable) { - uart_data[obj->index].irq_set_flow = 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); } /****************************************************************************** @@ -318,9 +323,12 @@ static void serial_flow_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { ******************************************************************************/ int serial_getc(serial_t *obj) { while (!serial_readable(obj)); - if (NC != uart_data[obj->index].sw_rts.pin) + int data = obj->uart->RBR; + if (NC != uart_data[obj->index].sw_rts.pin) { gpio_write(&uart_data[obj->index].sw_rts, 0); - return obj->uart->RBR; + obj->uart->IER |= 1 << RxIrq; + } + return data; } void serial_putc(serial_t *obj, int c) { @@ -373,8 +381,8 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi // First, disable flow control completely if (uart1) uart1->MCR = uart1->MCR & ~UART_MCR_FLOWCTRL_MASK; - serial_flow_irq_set(obj, RxIrq, 0); 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 @@ -404,7 +412,7 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi 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, RxIrq, 1); + serial_flow_irq_set(obj, 1); } } } From d0b2fb6c668b1330b58e549e39d09dcdb865efa8 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Wed, 4 Dec 2013 19:46:51 +0200 Subject: [PATCH 3/6] Added flow control test Since this requires a separate serial port connection, added this as a new attribute of the MUTs. --- .../tests/mbed/echo_flow_control/main.cpp | 34 +++++++++++++ .../host_tests/echo_flow_control.py | 48 +++++++++++++++++++ workspace_tools/host_tests/host_test.py | 14 +++++- workspace_tools/server.py | 7 +-- workspace_tools/tests.py | 11 ++++- 5 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 libraries/tests/mbed/echo_flow_control/main.cpp create mode 100644 workspace_tools/host_tests/echo_flow_control.py diff --git a/libraries/tests/mbed/echo_flow_control/main.cpp b/libraries/tests/mbed/echo_flow_control/main.cpp new file mode 100644 index 0000000000..cfb098abea --- /dev/null +++ b/libraries/tests/mbed/echo_flow_control/main.cpp @@ -0,0 +1,34 @@ +#include "mbed.h" + +#if defined(TARGET_LPC1768) +#define UART_TX p9 +#define UART_RX p10 +#define FLOW_CONTROL_RTS p11 +#define FLOW_CONTROL_CTS p12 +#define RTS_CHECK_PIN p13 +#else +#error This test is not supported on this target +#endif + +Serial pc(UART_TX, UART_RX); + +#ifdef RTS_CHECK_PIN +InterruptIn in(RTS_CHECK_PIN); +DigitalOut led(LED1); +static void checker(void) { + led = !led; +} +#endif + +int main() { + char buf[256]; + + pc.set_flow_control(Serial::RTSCTS, FLOW_CONTROL_RTS, FLOW_CONTROL_CTS); +#ifdef RTS_CHECK_PIN + in.fall(checker); +#endif + while (1) { + pc.gets(buf, 256); + pc.printf("%s", buf); + } +} diff --git a/workspace_tools/host_tests/echo_flow_control.py b/workspace_tools/host_tests/echo_flow_control.py new file mode 100644 index 0000000000..b354d0b04c --- /dev/null +++ b/workspace_tools/host_tests/echo_flow_control.py @@ -0,0 +1,48 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +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. +""" +from host_test import Test + + +class EchoTest(Test): + def __init__(self): + Test.__init__(self) + self.mbed.init_serial() + self.mbed.extra_serial.rtscts = True + self.mbed.reset() + + def test(self): + self.mbed.flush() + self.notify("Starting the ECHO test") + TEST="longer serial test" + check = True + for i in range(1, 100): + self.mbed.extra_serial.write(TEST + "\n") + l = self.mbed.extra_serial.readline().strip() + if not l: continue + + if l != TEST: + check = False + self.notify('"%s" != "%s"' % (l, TEST)) + else: + if (i % 10) == 0: + self.notify('.') + + return check + + +if __name__ == '__main__': + EchoTest().run() diff --git a/workspace_tools/host_tests/host_test.py b/workspace_tools/host_tests/host_test.py index d0352d360b..66f4b6d74d 100644 --- a/workspace_tools/host_tests/host_test.py +++ b/workspace_tools/host_tests/host_test.py @@ -38,6 +38,9 @@ class Mbed: parser.add_option("-t", "--timeout", dest="timeout", help="Timeout", metavar="TIMEOUT") + + parser.add_option("-e", "--extra", dest="extra", + help="Extra serial port (used by some tests)", metavar="EXTRA") (self.options, _) = parser.parse_args() @@ -46,14 +49,19 @@ class Mbed: self.port = self.options.port self.disk = self.options.disk + self.extra_port = self.options.extra + self.extra_serial = None self.serial = None self.timeout = 10 if self.options.timeout is None else self.options.timeout print 'Mbed: "%s" "%s"' % (self.port, self.disk) - def init_serial(self, baud=9600): + def init_serial(self, baud=9600, extra_baud=9600): self.serial = Serial(self.port, timeout = 1) self.serial.setBaudrate(baud) + if self.extra_port: + self.extra_serial = Serial(self.extra_port, timeout = 1) + self.extra_serial.setBaudrate(extra_baud) self.flush() def reset(self): @@ -64,7 +72,9 @@ class Mbed: def flush(self): self.serial.flushInput() self.serial.flushOutput() - + if self.extra_serial: + self.extra_serial.flushInput() + self.extra_serial.flushOutput() class Test: def __init__(self): diff --git a/workspace_tools/server.py b/workspace_tools/server.py index 33a05c8aea..e5d9808540 100644 --- a/workspace_tools/server.py +++ b/workspace_tools/server.py @@ -57,9 +57,9 @@ class ProcessObserver(Thread): pass -def run_host_test(client, name, disk, port, duration): +def run_host_test(client, name, disk, port, duration, extra_serial): print "{%s}" % name, - cmd = ["python", "%s.py" % name, '-p', port, '-d', disk, '-t', str(duration)] + cmd = ["python", "%s.py" % name, '-p', port, '-d', disk, '-t', str(duration), "-e", extra_serial] proc = Popen(cmd, stdout=PIPE, cwd=HOST_TESTS) obs = ProcessObserver(proc) start = time() @@ -144,6 +144,7 @@ class Tester(BaseRequestHandler): disk = mut['disk'] port = mut['port'] + extra_serial = mut.get('extra_serial', "") target = TARGET_MAP[mut['mcu']] # Program @@ -169,7 +170,7 @@ class Tester(BaseRequestHandler): # Host test self.request.setblocking(0) - result = run_host_test(self.request, test.host_test, disk, port, duration) + result = run_host_test(self.request, test.host_test, disk, port, duration, extra_serial) self.send_result(result) diff --git a/workspace_tools/tests.py b/workspace_tools/tests.py index 9d7630f0c0..6e9d9a66ef 100644 --- a/workspace_tools/tests.py +++ b/workspace_tools/tests.py @@ -203,6 +203,15 @@ TESTS = [ "dependencies": [MBED_LIBRARIES, TEST_MBED_LIB], "automated": True, }, + { + "id": "MBED_A22", "description": "Serial echo with RTS/CTS flow control", + "source_dir": join(TEST_DIR, "mbed", "echo_flow_control"), + "dependencies": [MBED_LIBRARIES], + "automated": "True", + "host_test": "echo_flow_control", + "mcu": ["LPC1768"], + "peripherals": ["extra_serial"] + }, # Size benchmarks { @@ -392,7 +401,7 @@ TESTS = [ "dependencies": [MBED_LIBRARIES], "mcu": ["LPC1768", "LPC4088"] }, - + # CMSIS RTOS tests { "id": "CMSIS_RTOS_1", "description": "Basic", From 53cd64775d026037cc14b401d7a2d3667645e8b1 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Thu, 5 Dec 2013 16:12:47 +0200 Subject: [PATCH 4/6] Hardware flow control implementation for LPC81X --- .../hal/TARGET_NXP/TARGET_LPC81X/serial_api.c | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/serial_api.c b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/serial_api.c index 9a98f82e87..d71d91c52d 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/serial_api.c @@ -39,6 +39,18 @@ static const SWM_Map SWM_UART_RX[] = { {2, 24}, }; +static const SWM_Map SWM_UART_RTS[] = { + {0, 16}, + {1, 24}, + {3, 0}, +}; + +static const SWM_Map SWM_UART_CTS[] = { + {0, 24}, + {2, 0}, + {3, 8} +}; + // bit flags for used UARTs static unsigned char uart_used = 0; static int get_available_uart(void) { @@ -60,6 +72,7 @@ static int get_available_uart(void) { #define TXRDY (0x01<<2) #define TXBRKEN (0x01<<1) +#define CTSEN (0x01<<9) static uint32_t UARTSysClk; @@ -278,3 +291,34 @@ void serial_break_clear(serial_t *obj) { obj->uart->CTRL &= ~TXBRKEN; } +void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) { + const SWM_Map *swm_rts, *swm_cts; + uint32_t regVal_rts, regVal_cts; + + swm_rts = &SWM_UART_RTS[obj->index]; + swm_cts = &SWM_UART_CTS[obj->index]; + regVal_rts = LPC_SWM->PINASSIGN[swm_rts->n] & ~(0xFF << swm_rts->offset); + regVal_cts = LPC_SWM->PINASSIGN[swm_cts->n] & ~(0xFF << swm_cts->offset); + + if (FlowControlNone == type) { + LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset); + LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset); + obj->uart->CFG &= ~CTSEN; + return; + } + if ((FlowControlRTS == type || FlowControlRTSCTS == type) && (rxflow != NC)) { + LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (rxflow << swm_rts->offset); + if (FlowControlRTS == type) { + LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset); + obj->uart->CFG &= ~CTSEN; + } + } + if ((FlowControlCTS == type || FlowControlRTSCTS == type) && (txflow != NC)) { + LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (txflow << swm_cts->offset); + obj->uart->CFG |= CTSEN; + if (FlowControlCTS == type) { + LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset); + } + } +} + From c3d4d3079fddabe62876c28cc048cf9f4efbf5a0 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Wed, 11 Dec 2013 10:26:18 +0200 Subject: [PATCH 5/6] Added DEVICE_SERIAL_FC as an indicator for the flow control implementation --- libraries/mbed/api/SerialBase.h | 2 ++ libraries/mbed/common/SerialBase.cpp | 2 ++ libraries/mbed/common/not_implemented.c | 28 ------------------- .../hal/TARGET_NXP/TARGET_LPC176X/device.h | 1 + .../hal/TARGET_NXP/TARGET_LPC81X/device.h | 1 + 5 files changed, 6 insertions(+), 28 deletions(-) delete mode 100644 libraries/mbed/common/not_implemented.c diff --git a/libraries/mbed/api/SerialBase.h b/libraries/mbed/api/SerialBase.h index f3b1a9e0d7..57705f3262 100644 --- a/libraries/mbed/api/SerialBase.h +++ b/libraries/mbed/api/SerialBase.h @@ -107,6 +107,7 @@ public: */ void send_break(); +#if DEVICE_SERIAL_FC /** Set the flow control type on the serial port * * @param type the flow control type (Disabled, RTS, CTS, RTSCTS) @@ -114,6 +115,7 @@ public: * @param flow2 the second flow control pin (CTS for RTSCTS) */ void set_flow_control(Flow type, PinName flow1=NC, PinName flow2=NC); +#endif static void _irq_handler(uint32_t id, SerialIrq irq_type); diff --git a/libraries/mbed/common/SerialBase.cpp b/libraries/mbed/common/SerialBase.cpp index 10a6fb61dd..93cbbb9fa4 100644 --- a/libraries/mbed/common/SerialBase.cpp +++ b/libraries/mbed/common/SerialBase.cpp @@ -81,6 +81,7 @@ void SerialBase::send_break() { serial_break_clear(&_serial); } +#ifdef DEVICE_SERIAL_FC void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) { FlowControl flow_type = (FlowControl)type; switch(type) { @@ -100,6 +101,7 @@ void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) { break; } } +#endif } // namespace mbed diff --git a/libraries/mbed/common/not_implemented.c b/libraries/mbed/common/not_implemented.c deleted file mode 100644 index 53170b0dd2..0000000000 --- a/libraries/mbed/common/not_implemented.c +++ /dev/null @@ -1,28 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * 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. - */ - -// Default versions of various HAL functions that might not be implemented for some platforms. - -#include "toolchain.h" -#include "serial_api.h" -#include "error.h" - -WEAK void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow); -WEAK void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) { - if (FlowControlNone != type) - error("hardware flow control not implemented on this platform"); -} - diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/device.h b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/device.h index 50bd1f980a..a4646b7a00 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/device.h +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/device.h @@ -26,6 +26,7 @@ #define DEVICE_ANALOGOUT 1 #define DEVICE_SERIAL 1 +#define DEVICE_SERIAL_FC 1 #define DEVICE_I2C 1 #define DEVICE_I2CSLAVE 1 diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/device.h b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/device.h index 88e5cf66b3..4ec1781cea 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/device.h +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/device.h @@ -26,6 +26,7 @@ #define DEVICE_ANALOGOUT 0 #define DEVICE_SERIAL 1 +#define DEVICE_SERIAL_FC 1 #define DEVICE_I2C 1 #define DEVICE_I2CSLAVE 0 From bb8ed20a47a2b4e73d7c974d743452bba5098664 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Wed, 11 Dec 2013 16:31:59 +0200 Subject: [PATCH 6/6] LPC1768 flow control fixes - Disable TX buffer, this isn't compatible with the software CTS implementation - Properly set hardware RTS/CTS pins when possible - Modified test to use hardware CTS and software RTS --- .../TARGET_NXP/TARGET_LPC176X/serial_api.c | 33 ++++++++----------- .../tests/mbed/echo_flow_control/main.cpp | 8 ++--- workspace_tools/build.py | 2 +- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c index 65c9d1f318..786048471a 100644 --- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c @@ -68,15 +68,15 @@ static const PinMap PinMap_UART_CTS[] = { #define UART_MCR_CTSEN_MASK (1 << 7) #define UART_MCR_FLOWCTRL_MASK (UART_MCR_RTSEN_MASK | UART_MCR_CTSEN_MASK) -static uint32_t serial_irq_ids[UART_NUM] = {0}; 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 count, initialized, rx_irq_set_flow, rx_irq_set_api; + uint8_t rx_irq_set_flow, rx_irq_set_api; }; static struct serial_global_data_s uart_data[UART_NUM]; @@ -130,11 +130,9 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) { case UART_2: obj->index = 2; break; case UART_3: obj->index = 3; break; } - if (!uart_data[obj->index].initialized) { - uart_data[obj->index].sw_rts.pin = NC; - uart_data[obj->index].sw_cts.pin = NC; - uart_data[obj->index].initialized = 1; - } + 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); @@ -145,7 +143,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) { } void serial_free(serial_t *obj) { - serial_irq_ids[obj->index] = 0; + uart_data[obj->index].serial_irq_id = 0; } // serial_baud @@ -262,15 +260,15 @@ static inline void uart_irq(uint32_t iir, uint32_t index, LPC_UART_TypeDef *puar case 2: irq_type = RxIrq; break; default: return; } - 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 (serial_irq_ids[index] != 0) - irq_handler(serial_irq_ids[index], irq_type); + 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, (LPC_UART_TypeDef*)LPC_UART0);} @@ -280,7 +278,7 @@ void uart3_irq() {uart_irq((LPC_UART3->IIR >> 1) & 0x7, 3, (LPC_UART_TypeDef*)LP 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; } static void serial_irq_set_internal(serial_t *obj, SerialIrq irq, uint32_t enable) { @@ -334,7 +332,6 @@ int serial_getc(serial_t *obj) { void serial_putc(serial_t *obj, int c) { while (!serial_writable(obj)); obj->uart->THR = c; - uart_data[obj->index].count++; } int serial_readable(serial_t *obj) { @@ -345,12 +342,8 @@ int serial_writable(serial_t *obj) { int isWritable = 1; if (NC != uart_data[obj->index].sw_cts.pin) isWritable = gpio_read(&uart_data[obj->index].sw_cts) == 0; - if (isWritable) { - if (obj->uart->LSR & 0x20) - uart_data[obj->index].count = 0; - else if (uart_data[obj->index].count >= 16) - isWritable = 0; - } + if (isWritable) + isWritable = obj->uart->LSR & 0x40; return isWritable; } @@ -393,6 +386,7 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi 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); @@ -408,6 +402,7 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi 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); diff --git a/libraries/tests/mbed/echo_flow_control/main.cpp b/libraries/tests/mbed/echo_flow_control/main.cpp index cfb098abea..016d0040e4 100644 --- a/libraries/tests/mbed/echo_flow_control/main.cpp +++ b/libraries/tests/mbed/echo_flow_control/main.cpp @@ -1,11 +1,11 @@ #include "mbed.h" #if defined(TARGET_LPC1768) -#define UART_TX p9 -#define UART_RX p10 -#define FLOW_CONTROL_RTS p11 +#define UART_TX p13 +#define UART_RX p14 +#define FLOW_CONTROL_RTS p30 #define FLOW_CONTROL_CTS p12 -#define RTS_CHECK_PIN p13 +#define RTS_CHECK_PIN p15 #else #error This test is not supported on this target #endif diff --git a/workspace_tools/build.py b/workspace_tools/build.py index bcd11c6138..f3644ba118 100644 --- a/workspace_tools/build.py +++ b/workspace_tools/build.py @@ -23,7 +23,7 @@ from os.path import join, abspath, dirname # Be sure that the tools directory is in the search path ROOT = abspath(join(dirname(__file__), "..")) -sys.path.append(ROOT) +sys.path.insert(0, ROOT) from workspace_tools.toolchains import TOOLCHAINS from workspace_tools.targets import TARGET_NAMES, TARGET_MAP