Skip to content

Commit fbeb52d

Browse files
author
Bogdan Marinescu
committed
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.
1 parent 72a9529 commit fbeb52d

File tree

8 files changed

+185
-20
lines changed

8 files changed

+185
-20
lines changed

libraries/mbed/api/SerialBase.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ class SerialBase {
5151
TxIrq
5252
};
5353

54+
enum Flow {
55+
Disabled = 0,
56+
RTS,
57+
CTS,
58+
RTSCTS
59+
};
60+
5461
/** Set the transmission format used by the serial port
5562
*
5663
* @param bits The number of bits in a word (5-8; default = 8)
@@ -99,6 +106,14 @@ class SerialBase {
99106
/** Generate a break condition on the serial line
100107
*/
101108
void send_break();
109+
110+
/** Set the flow control type on the serial port
111+
*
112+
* @param type the flow control type (Disabled, RTS, CTS, RTSCTS)
113+
* @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS)
114+
* @param flow2 the second flow control pin (CTS for RTSCTS)
115+
*/
116+
void set_flow_control(Flow type, PinName flow1=NC, PinName flow2=NC);
102117

103118
static void _irq_handler(uint32_t id, SerialIrq irq_type);
104119

libraries/mbed/common/SerialBase.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,26 @@ void SerialBase::send_break() {
8181
serial_break_clear(&_serial);
8282
}
8383

84+
void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) {
85+
FlowControl flow_type = (FlowControl)type;
86+
switch(type) {
87+
case RTS:
88+
serial_set_flow_control(&_serial, flow_type, flow1, NC);
89+
break;
90+
91+
case CTS:
92+
serial_set_flow_control(&_serial, flow_type, NC, flow1);
93+
break;
94+
95+
case RTSCTS:
96+
serial_set_flow_control(&_serial, flow_type, flow1, flow2);
97+
break;
98+
99+
default:
100+
break;
101+
}
102+
}
103+
84104
} // namespace mbed
85105

86106
#endif
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2013 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// Default versions of various HAL functions that might not be implemented for some platforms.
18+
19+
#include "toolchain.h"
20+
#include "serial_api.h"
21+
#include "error.h"
22+
23+
WEAK void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow);
24+
WEAK void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
25+
if (FlowControlNone != type)
26+
error("hardware flow control not implemented on this platform");
27+
}
28+

libraries/mbed/common/pinmap_common.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,22 @@ uint32_t pinmap_merge(uint32_t a, uint32_t b) {
4444
return (uint32_t)NC;
4545
}
4646

47-
uint32_t pinmap_peripheral(PinName pin, const PinMap* map) {
48-
if (pin == (PinName)NC)
49-
return (uint32_t)NC;
50-
47+
uint32_t pinmap_find_peripheral(PinName pin, const PinMap* map) {
5148
while (map->pin != NC) {
5249
if (map->pin == pin)
5350
return map->peripheral;
5451
map++;
5552
}
56-
57-
// no mapping available
58-
error("pinmap not found for peripheral");
5953
return (uint32_t)NC;
6054
}
55+
56+
uint32_t pinmap_peripheral(PinName pin, const PinMap* map) {
57+
uint32_t peripheral = (uint32_t)NC;
58+
59+
if (pin == (PinName)NC)
60+
return (uint32_t)NC;
61+
peripheral = pinmap_find_peripheral(pin, map);
62+
if ((uint32_t)NC == peripheral) // no mapping available
63+
error("pinmap not found for peripheral");
64+
return peripheral;
65+
}

libraries/mbed/hal/pinmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ void pin_mode (PinName pin, PinMode mode);
3434
uint32_t pinmap_peripheral(PinName pin, const PinMap* map);
3535
uint32_t pinmap_merge (uint32_t a, uint32_t b);
3636
void pinmap_pinout (PinName pin, const PinMap *map);
37+
uint32_t pinmap_find_peripheral(PinName pin, const PinMap* map);
3738

3839
#ifdef __cplusplus
3940
}

libraries/mbed/hal/serial_api.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ typedef enum {
3737
TxIrq
3838
} SerialIrq;
3939

40+
typedef enum {
41+
FlowControlNone,
42+
FlowControlRTS,
43+
FlowControlCTS,
44+
FlowControlRTSCTS
45+
} FlowControl;
46+
4047
typedef void (*uart_irq_handler)(uint32_t id, SerialIrq event);
4148

4249
typedef struct serial_s serial_t;
@@ -60,6 +67,8 @@ void serial_break_clear(serial_t *obj);
6067

6168
void serial_pinout_tx(PinName tx);
6269

70+
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow);
71+
6372
#ifdef __cplusplus
6473
}
6574
#endif

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/objects.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "PortNames.h"
2121
#include "PeripheralNames.h"
2222
#include "PinNames.h"
23+
#include "gpio_object.h"
2324

2425
#ifdef __cplusplus
2526
extern "C" {
@@ -47,7 +48,6 @@ struct pwmout_s {
4748
struct serial_s {
4849
LPC_UART_TypeDef *uart;
4950
int index;
50-
uint8_t count;
5151
};
5252

5353
struct analogin_s {
@@ -71,8 +71,6 @@ struct spi_s {
7171
LPC_SSP_TypeDef *spi;
7272
};
7373

74-
#include "gpio_object.h"
75-
7674
#ifdef __cplusplus
7775
}
7876
#endif

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "cmsis.h"
2222
#include "pinmap.h"
2323
#include "error.h"
24+
#include "gpio_api.h"
2425

2526
/******************************************************************************
2627
* INITIALIZATION
@@ -51,12 +52,35 @@ static const PinMap PinMap_UART_RX[] = {
5152
{NC , NC , 0}
5253
};
5354

55+
static const PinMap PinMap_UART_RTS[] = {
56+
{P0_22, UART_1, 1},
57+
{P2_7, UART_1, 2},
58+
{NC, NC, 0}
59+
};
60+
61+
static const PinMap PinMap_UART_CTS[] = {
62+
{P0_17, UART_1, 1},
63+
{P2_2, UART_1, 2},
64+
{NC, NC, 0}
65+
};
66+
67+
#define UART_MCR_RTSEN_MASK (1 << 6)
68+
#define UART_MCR_CTSEN_MASK (1 << 7)
69+
#define UART_MCR_FLOWCTRL_MASK (UART_MCR_RTSEN_MASK | UART_MCR_CTSEN_MASK)
70+
5471
static uint32_t serial_irq_ids[UART_NUM] = {0};
5572
static uart_irq_handler irq_handler;
5673

5774
int stdio_uart_inited = 0;
5875
serial_t stdio_uart;
5976

77+
struct serial_global_data_s {
78+
gpio_t sw_rts, sw_cts;
79+
uint8_t count, initialized, irq_set_flow, irq_set_api;
80+
};
81+
82+
static struct serial_global_data_s uart_data[UART_NUM];
83+
6084
void serial_init(serial_t *obj, PinName tx, PinName rx) {
6185
int is_stdio_uart = 0;
6286

@@ -106,7 +130,11 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
106130
case UART_2: obj->index = 2; break;
107131
case UART_3: obj->index = 3; break;
108132
}
109-
obj->count = 0;
133+
if (!uart_data[obj->index].initialized) {
134+
uart_data[obj->index].sw_rts.pin = NC;
135+
uart_data[obj->index].sw_cts.pin = NC;
136+
uart_data[obj->index].initialized = 1;
137+
}
110138

111139
is_stdio_uart = (uart == STDIO_UART) ? (1) : (0);
112140

@@ -234,7 +262,9 @@ static inline void uart_irq(uint32_t iir, uint32_t index) {
234262
case 2: irq_type = RxIrq; break;
235263
default: return;
236264
}
237-
265+
266+
if ((RxIrq == irq_type) && (uart_data[index].sw_rts.pin != NC))
267+
gpio_write(&uart_data[index].sw_rts, 1);
238268
if (serial_irq_ids[index] != 0)
239269
irq_handler(serial_irq_ids[index], irq_type);
240270
}
@@ -249,7 +279,7 @@ void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
249279
serial_irq_ids[obj->index] = id;
250280
}
251281

252-
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
282+
static void serial_irq_set_internal(serial_t *obj, SerialIrq irq, uint32_t enable) {
253283
IRQn_Type irq_n = (IRQn_Type)0;
254284
uint32_t vector = 0;
255285
switch ((int)obj->uart) {
@@ -263,7 +293,7 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
263293
obj->uart->IER |= 1 << irq;
264294
NVIC_SetVector(irq_n, vector);
265295
NVIC_EnableIRQ(irq_n);
266-
} else { // disable
296+
} else if (uart_data[obj->index].irq_set_api + uart_data[obj->index].irq_set_flow == 0) { // disable
267297
int all_disabled = 0;
268298
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
269299
obj->uart->IER &= ~(1 << irq);
@@ -273,18 +303,30 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
273303
}
274304
}
275305

306+
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
307+
uart_data[obj->index].irq_set_api = enable;
308+
serial_irq_set_internal(obj, irq, enable);
309+
}
310+
311+
static void serial_flow_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
312+
uart_data[obj->index].irq_set_flow = enable;
313+
serial_irq_set_internal(obj, irq, enable);
314+
}
315+
276316
/******************************************************************************
277317
* READ/WRITE
278318
******************************************************************************/
279319
int serial_getc(serial_t *obj) {
280320
while (!serial_readable(obj));
321+
if (NC != uart_data[obj->index].sw_rts.pin)
322+
gpio_write(&uart_data[obj->index].sw_rts, 0);
281323
return obj->uart->RBR;
282324
}
283325

284326
void serial_putc(serial_t *obj, int c) {
285327
while (!serial_writable(obj));
286328
obj->uart->THR = c;
287-
obj->count++;
329+
uart_data[obj->index].count++;
288330
}
289331

290332
int serial_readable(serial_t *obj) {
@@ -293,11 +335,14 @@ int serial_readable(serial_t *obj) {
293335

294336
int serial_writable(serial_t *obj) {
295337
int isWritable = 1;
296-
if (obj->uart->LSR & 0x20)
297-
obj->count = 0;
298-
else if (obj->count >= 16)
299-
isWritable = 0;
300-
338+
if (NC != uart_data[obj->index].sw_cts.pin)
339+
isWritable = gpio_read(&uart_data[obj->index].sw_cts) == 0;
340+
if (isWritable) {
341+
if (obj->uart->LSR & 0x20)
342+
uart_data[obj->index].count = 0;
343+
else if (uart_data[obj->index].count >= 16)
344+
isWritable = 0;
345+
}
301346
return isWritable;
302347
}
303348

@@ -320,3 +365,47 @@ void serial_break_clear(serial_t *obj) {
320365
obj->uart->LCR &= ~(1 << 6);
321366
}
322367

368+
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
369+
// Only UART1 has hardware flow control on LPC176x
370+
LPC_UART1_TypeDef *uart1 = (uint32_t)obj->uart == (uint32_t)LPC_UART1 ? LPC_UART1 : NULL;
371+
int index = obj->index;
372+
373+
// First, disable flow control completely
374+
if (uart1)
375+
uart1->MCR = uart1->MCR & ~UART_MCR_FLOWCTRL_MASK;
376+
serial_flow_irq_set(obj, RxIrq, 0);
377+
uart_data[index].sw_rts.pin = uart_data[index].sw_cts.pin = NC;
378+
if (FlowControlNone == type)
379+
return;
380+
// Check type(s) of flow control to use
381+
UARTName uart_rts = (UARTName)pinmap_find_peripheral(rxflow, PinMap_UART_RTS);
382+
UARTName uart_cts = (UARTName)pinmap_find_peripheral(txflow, PinMap_UART_CTS);
383+
if (((FlowControlCTS == type) || (FlowControlRTSCTS == type)) && (NC != txflow)) {
384+
// Can this be enabled in hardware?
385+
if ((UART_1 == uart_cts) && (NULL != uart1)) {
386+
// Enable auto-CTS mode
387+
uart1->MCR |= UART_MCR_CTSEN_MASK;
388+
} else {
389+
// Can't enable in hardware, use software emulation
390+
gpio_init(&uart_data[index].sw_cts, txflow, PIN_INPUT);
391+
}
392+
}
393+
if (((FlowControlRTS == type) || (FlowControlRTSCTS == type)) && (NC != rxflow)) {
394+
// Enable FIFOs, trigger level of 1 char on RX FIFO
395+
obj->uart->FCR = 1 << 0 // FIFO Enable - 0 = Disables, 1 = Enabled
396+
| 1 << 1 // Rx Fifo Reset
397+
| 1 << 2 // Tx Fifo Reset
398+
| 0 << 6; // Rx irq trigger level - 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars
399+
// Can this be enabled in hardware?
400+
if ((UART_1 == uart_rts) && (NULL != uart1)) {
401+
// Enable auto-RTS mode
402+
uart1->MCR |= UART_MCR_RTSEN_MASK;
403+
} else { // can't enable in hardware, use software emulation
404+
gpio_init(&uart_data[index].sw_rts, rxflow, PIN_OUTPUT);
405+
gpio_write(&uart_data[index].sw_rts, 0);
406+
// Enable RX interrupt
407+
serial_flow_irq_set(obj, RxIrq, 1);
408+
}
409+
}
410+
}
411+

0 commit comments

Comments
 (0)