Skip to content

Commit c262a03

Browse files
committed
UARTSerial: add flow control and format APIs
Add passthrough APIs to enable the flow control and format methods from SerialBase to be accessed. Modify the RX data pump so it stops reading data and disables the IRQ when the buffer is full, to allow UART automatic flow control to work. In principle it would also be possible as a future enhancement to provide XON/XOFF flow control, or manual RTS/CTS control using GPIO, but this commit at least restores the functionality present in Serial, SerialBase and RawSerial that was missing in UARTSerial.
1 parent 7b42891 commit c262a03

File tree

2 files changed

+71
-6
lines changed

2 files changed

+71
-6
lines changed

drivers/UARTSerial.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
2727
SerialBase(tx, rx, baud),
2828
_blocking(true),
2929
_tx_irq_enabled(false),
30+
_rx_irq_enabled(true),
3031
_dcd_irq(NULL)
3132
{
3233
/* Attatch IRQ routines to the serial device. */
@@ -63,6 +64,22 @@ void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
6364
}
6465
}
6566

67+
void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
68+
{
69+
api_lock();
70+
SerialBase::format(bits, parity, stop_bits);
71+
api_unlock();
72+
}
73+
74+
#if DEVICE_SERIAL_FC
75+
void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
76+
{
77+
api_lock();
78+
SerialBase::set_flow_control(type, flow1, flow2);
79+
api_unlock();
80+
}
81+
#endif
82+
6683
int UARTSerial::close()
6784
{
6885
/* Does not let us pass a file descriptor. So how to close ?
@@ -171,6 +188,16 @@ ssize_t UARTSerial::read(void* buffer, size_t length)
171188
data_read++;
172189
}
173190

191+
core_util_critical_section_enter();
192+
if (!_rx_irq_enabled) {
193+
UARTSerial::rx_irq(); // only read from hardware in one place
194+
if (!_rxbuf.full()) {
195+
SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
196+
_rx_irq_enabled = true;
197+
}
198+
}
199+
core_util_critical_section_exit();
200+
174201
api_unlock();
175202

176203
return data_read;
@@ -238,13 +265,14 @@ void UARTSerial::rx_irq(void)
238265

239266
/* Fill in the receive buffer if the peripheral is readable
240267
* and receive buffer is not full. */
241-
while (SerialBase::readable()) {
268+
while (!_rxbuf.full() && SerialBase::readable()) {
242269
char data = SerialBase::_base_getc();
243-
if (!_rxbuf.full()) {
244-
_rxbuf.push(data);
245-
} else {
246-
/* Drop - can we report in some way? */
247-
}
270+
_rxbuf.push(data);
271+
}
272+
273+
if (_rx_irq_enabled && _rxbuf.full()) {
274+
SerialBase::attach(NULL, RxIrq);
275+
_rx_irq_enabled = false;
248276
}
249277

250278
/* Report the File handler that data is ready to be read from the buffer. */

drivers/UARTSerial.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,42 @@ class UARTSerial : private SerialBase, public FileHandle, private NonCopyable<UA
158158
*/
159159
void set_baud(int baud);
160160

161+
// Expose private SerialBase::Parity as UARTSerial::Parity
162+
using SerialBase::Parity;
163+
// In C++11, we wouldn't need to also have using directives for each value
164+
using SerialBase::None;
165+
using SerialBase::Odd;
166+
using SerialBase::Even;
167+
using SerialBase::Forced1;
168+
using SerialBase::Forced0;
169+
170+
/** Set the transmission format used by the serial port
171+
*
172+
* @param bits The number of bits in a word (5-8; default = 8)
173+
* @param parity The parity used (None, Odd, Even, Forced1, Forced0; default = None)
174+
* @param stop_bits The number of stop bits (1 or 2; default = 1)
175+
*/
176+
void set_format(int bits=8, Parity parity=UARTSerial::None, int stop_bits=1);
177+
178+
#if DEVICE_SERIAL_FC
179+
// For now use the base enum - but in future we may have extra options
180+
// such as XON/XOFF or manual GPIO RTSCTS.
181+
using SerialBase::Flow;
182+
// In C++11, we wouldn't need to also have using directives for each value
183+
using SerialBase::Disabled;
184+
using SerialBase::RTS;
185+
using SerialBase::CTS;
186+
using SerialBase::RTSCTS;
187+
188+
/** Set the flow control type on the serial port
189+
*
190+
* @param type the flow control type (Disabled, RTS, CTS, RTSCTS)
191+
* @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS)
192+
* @param flow2 the second flow control pin (CTS for RTSCTS)
193+
*/
194+
void set_flow_control(Flow type, PinName flow1=NC, PinName flow2=NC);
195+
#endif
196+
161197
private:
162198

163199
/** SerialBase lock override */
@@ -184,6 +220,7 @@ class UARTSerial : private SerialBase, public FileHandle, private NonCopyable<UA
184220

185221
bool _blocking;
186222
bool _tx_irq_enabled;
223+
bool _rx_irq_enabled;
187224
InterruptIn *_dcd_irq;
188225

189226
/** Device Hanged up

0 commit comments

Comments
 (0)