Serial API for flow control pins (RTS & CTS)

2,218 views
Skip to first unread message

Paul Stoffregen

unread,
Aug 24, 2015, 9:21:42 AM8/24/15
to devel...@arduino.cc
Recently I've been hearing requests for serial RTS/CTS hardware flow
control on Teensy.

Many chips have RTS/CTS support in their UART hardware. Arduino Micro
(ATMEGA32U4) has it. Teensy-LC and Teensy 3.1 have it on all 3 serial
ports. Arduino Due has it on 3 of 4 ports. Arduino Zero might too...
at least it's mentioned in section 25.6.3.2 of the datasheet. In
theory, RTS/CTS can be implemented within the serial interrupts using
ordinary digital pins.

My question is whether there's any opinions about how RTS/CTS should be
implemented, API-wise? My goal is always to work for compatibility, so
I'm asking now... before simply making up function names and other API
details.

An obvious choice might look like Serial1.setRTS(pin) or maybe just
Serial1.RTS(pin), since the get/set aren't used anywhere else in
HardwareSerial. Maybe these ought to return a boolean to indicate
success, or unsupported pin numbers? On some chips, only a single pin
can be used for each signal, but many other support 2 or more possible
pins, and a (hypothetical) software-only implementation could probably
support any digital pins.

I should also mention, this API would be specific to the HardwareSerial
class. A similar-sounding conversation about RTS & DTR on USB Serial
exists on pull request #3343. Despite the same terminology, that is
about delivering USB virtual data (which doesn't even have CTS). This
is about enabling physical RTS/CTS flow control on actual hardware pins.

Paul Stoffregen

unread,
Oct 23, 2015, 7:42:46 AM10/23/15
to devel...@arduino.cc
I'm guessing from the lack of response there's little interest in flow
control. Perhaps not even imagining what an Arduino API for RTS/CTS
flow control might look like in the (perhaps distant) future?

Soon I'm going to implement RTS/CTS flow control on Teensy. Many users
are connecting serial-based wireless modules. Fast baud rates are very
desirable for these projects. Often the radios can't keep up,
especially if they need to retransmit data due to weak signals or
interference. Likewise, the reality of many Arduino libraries is
blocking functions, where the 64 byte serial buffer overruns very
quickly at 1 to 6 Mbit/sec baud rates.

My preference is always to be as compatible as possible. Long-term,
everybody benefits from compatible APIs. Even if flow control seems
like a feature Arduino is never likely to implement, maybe we could at
least talk hypothetically about what the API ought to be?

Thibaut VIARD

unread,
Oct 23, 2015, 8:26:54 AM10/23/15
to devel...@arduino.cc

Hi Paul,

Sorry I missed you first mail.

I'm interested in flow control for the same purpose and would be interested into discussing how to integrate this feature inside current API without causing problems.

I didn't investigate yet on this matter, however.

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Massimo Banzi

unread,
Oct 23, 2015, 9:00:39 AM10/23/15
to Arduino Developers
Sorry I missed the mail.

Adding an API for flow control will be a very useful thing.

Propose some API and we’ll make sure it gets added as part of the standard Arduino API

m

Cristian Maglie

unread,
Oct 23, 2015, 9:06:28 AM10/23/15
to devel...@arduino.cc
Il 23/10/2015 13:41, Paul Stoffregen ha scritto:
> I'm guessing from the lack of response there's little interest in flow
> control. Perhaps not even imagining what an Arduino API for RTS/CTS
> flow control might look like in the (perhaps distant) future?

This is a mid-term goal, another related issue is

https://github.com/arduino/Arduino/issues/3947

(I remember another more but I'm not able to find it right now...)

So, it's definitely a good idea to discuss the API here, thanks for
bringing up this topic again.

>> An obvious choice might look like Serial1.setRTS(pin) or maybe just
>> Serial1.RTS(pin), since the get/set aren't used anywhere else in
>> HardwareSerial. Maybe these ought to return a boolean to indicate
>> success, or unsupported pin numbers? On some chips, only a single pin
>> can be used for each signal, but many other support 2 or more possible
>> pins, and a (hypothetical) software-only implementation could probably
>> support any digital pins.

your proposal looks good, the only thing that I'll add is a boolean
return value that is true if the operation is successful or false
otherwise (this way we have a quick test to see if the operation on the
specified pin is supported or not). So:

bool Serial::RTS(pin)
bool Serial::CTS(pin)

Those two functions should be enough to implement RTS/CTS handshake right?

--
Cristian Maglie <c.ma...@arduino.cc>

Paul Stoffregen

unread,
Oct 23, 2015, 9:14:41 AM10/23/15
to devel...@arduino.cc
On 10/23/2015 06:06 AM, Cristian Maglie wrote:
> ... the only thing that I'll add is a boolean
> return value that is true if the operation is successful or false
> otherwise (this way we have a quick test to see if the operation on the
> specified pin is supported or not). So:
>
> bool Serial::RTS(pin)
> bool Serial::CTS(pin)
>
> Those two functions should be enough to implement RTS/CTS handshake right?
>

Yes, that looks great.

Adrian Godwin

unread,
Oct 23, 2015, 9:39:17 AM10/23/15
to devel...@arduino.cc
Please make sure it doesn't load the library size if it's not in use.

Hardware flow control is very useful for some things and I'm glad you want to add it, but in my experience is not standardised enough to work without tweaking for the situation.  A library will either need modifying or need further code wrapped around it.

It's a really bad solution for communicating between two fast things over a slow channel (happy to expand on that but in a different thread please)

I'd just like to ask that it can be as simple as possible for those things that need it and disabled for those applications that don't use it, with little or no overhead when it's not used.

-adrian



Paul Stoffregen

unread,
Oct 23, 2015, 10:09:21 AM10/23/15
to devel...@arduino.cc
First of all, I do like this API. It's concise nature is appealing.

bool HardwareSerial::RTS(pin)
bool HardwareSerial::CTS(pin)


I believe it's pretty clear, at least in the context of HardwareSerial,
these functions designate a pin to function as these well-known serial
signals. Even if someone has no idea what "CTS" does, it's clear that
serial devices have a "CTS" signal.

However, one possible point of confusion might be the dtr() and rts()
functions in the not-yet-released USB CDC Serial API (for Leonardo,
Micro, Yun, etc):

bool Serial_::dtr()
bool Serial_::rts()


For USB CDC serial, these functions allow the sketch to observe the
state of these virtual signals.

Perhaps more verbose functions should be used? Or maybe the distinction
between reading the state of virtual signals versus designating a
digital pin to become a physical signal is clear?



On 10/23/2015 06:06 AM, Cristian Maglie wrote:

Cristian Maglie

unread,
Oct 23, 2015, 11:11:10 AM10/23/15
to devel...@arduino.cc
Il 23/10/2015 16:08, Paul Stoffregen ha scritto:
> Perhaps more verbose functions should be used? Or maybe the distinction
> between reading the state of virtual signals versus designating a
> digital pin to become a physical signal is clear?

right right right,

the name without the verb like rts(), baudrate(), whatever(), in Arduino
APIs is (generally..) used to query the device, (it does the equivalent
of isRts(), getBaudrate(), getWhatever()).

We must be more descriptive for setting up things, like:

bool Serial::attachRts(pin)
bool Serial::attachCts(pin)

that is more similar to other APIs already released.

C

Cristian Maglie

unread,
Oct 23, 2015, 11:13:02 AM10/23/15
to devel...@arduino.cc
Il 23/10/2015 15:39, Adrian Godwin ha scritto:
> It's a really bad solution for communicating between two fast things
> over a slow channel (happy to expand on that but in a different thread
> please)

Happy to see more on this topic from your experience, feel free to start
a new discussion on that! :-)

C


--
Cristian Maglie <c.ma...@arduino.cc>

Tom Igoe

unread,
Oct 23, 2015, 11:17:24 AM10/23/15
to devel...@arduino.cc
Oh Cristian, you warm my heart when you say things like this. I agree with Paul’s reasoning and with your suggestions in response.

Tom Igoe

Andrew Kroll

unread,
Oct 23, 2015, 3:07:58 PM10/23/15
to devel...@arduino.cc

My question is why everyone always ignores flow control. Its very important, and should be handled automatically, much like all the modern autoflow uarts that have been in existance for well over 10 years.
The proper way to utilize it should be that your code only checks free buffer space, and sends only that amount if you want to do non-blocking. Otherwise it should block your code.

Tom Igoe

unread,
Oct 23, 2015, 3:41:52 PM10/23/15
to devel...@arduino.cc
I teach it in software, if that makes you feel any better. But I can see Paul’s point about doing it in hardware too. Sometimes you don’t get to pick the software protocol, and hardware handshaking is, well, handy then.

Tom Igoe


Andrew Kroll

unread,
Oct 24, 2015, 4:26:48 AM10/24/15
to devel...@arduino.cc

I've had to teach 1byte fifo uarts how to autoflow in hardware. This same circuit can be used on any cpu or mcu. Works great on 66551 ACIA but the sender needs to properly respect rts/cts. Many older uarts (16550, and many modems too) don't properly work, and dump the entire fifo. Autoflow means you don't send anymore. My circuit detects and deasserts CTS on the first edge of the incoming start bit or break signal.
Check it out, it is open source. http://dr.ea.ms/hw/hardware/ACIAFIX/

Matthijs Kooijman

unread,
Oct 27, 2015, 4:14:42 AM10/27/15
to devel...@arduino.cc
+1 for this API for me.

One thing to think about is that adding flow control might cause a
write to block potentially indefinitely. Without flow control, you can
always be sure that buffer space will be available in a bounded amount
of time, but with flow control, this could be indefinite (and if both
ends are blocking waiting for each other, this could cause a deadlock).

This probably doesn't influence the flow control API in any way, and it
is up to the sketch coder to make sure this doesn't cause problems. They
can use the availableForWrite() API for that, which allows the sketch
coder to prevent blocking entirely.

I wonder if it would be useful to have an API to read the remote side's
flow control pin (e.g. read if the other side has room in the buffer)? I
guess that just using a digitalRead for this is probably sufficient
though, at least on AVR where you can (AFAIK) still read pins that are
in use by specific hardware functions.

Gr.

Matthijs
signature.asc

Andrew Kroll

unread,
Oct 27, 2015, 5:17:22 AM10/27/15
to devel...@arduino.cc

Deadlocks and blocking is fully expected, acceptable, and easily avoided. Need an example?

Paul Stoffregen

unread,
Oct 27, 2015, 6:57:17 AM10/27/15
to devel...@arduino.cc
On 10/23/2015 08:11 AM, Cristian Maglie wrote:
> the name without the verb like rts(), baudrate(), whatever(), in Arduino
> APIs is (generally..) used to query the device, (it does the equivalent
> of isRts(), getBaudrate(), getWhatever()).
>
> We must be more descriptive for setting up things, like:
>
> bool Serial::attachRts(pin)
> bool Serial::attachCts(pin)
>
> that is more similar to other APIs already released.

Yes, "attach" seems good.

While Arduino style generally uses camel case, these flow control signal
names are acronyms which are almost always written in all caps. Maybe
this would be clearer?

bool HardwareSerial::attachRTS(pin)
bool HardwareSerial::attachCTS(pin)

I believe the most important point is for every board to at least
implement these with fixed return of false, if flow control isn't supported.


On 10/27/2015 01:14 AM, Matthijs Kooijman wrote:
> I wonder if it would be useful to have an API to read the remote side's
> flow control pin (e.g. read if the other side has room in the buffer)?

That might be useful. Since conventional operating systems and embedded
systems generally don't provide anything like this, I'd recommend
waiting until someone has a strong need. My gut feeling is
availableForWrite() should be enough. If it isn't, we should look at
the reason why before designing a solution.

Cristian Maglie

unread,
Oct 27, 2015, 11:53:30 AM10/27/15
to devel...@arduino.cc
Il 27/10/2015 11:56, Paul Stoffregen ha scritto:
> While Arduino style generally uses camel case, these flow control signal
> names are acronyms which are almost always written in all caps. Maybe
> this would be clearer?
>
> bool HardwareSerial::attachRTS(pin)
> bool HardwareSerial::attachCTS(pin)

as you already noticed, we have also Serial_::rts() and Serial_::cts()
on the USB-CDC, so these should be changed to upper case too.

I don't know, I don't have strong feelings here, so let's follow
camel-case strictly and just go with the current set:

Serial_::rts()
Serial_::cts()

HardwareSerial::attachRts
HardwareSerial::attachCts

> I believe the most important point is for every board to at least
> implement these with fixed return of false, if flow control isn't
> supported.

Yes, of course, that's a really good point.

--
Cristian Maglie <c.ma...@arduino.cc>

Matthijs Kooijman

unread,
Oct 27, 2015, 12:22:27 PM10/27/15
to devel...@arduino.cc
Hi folks,

> > While Arduino style generally uses camel case, these flow control signal
> > names are acronyms which are almost always written in all caps. Maybe
> > this would be clearer?
Usually, I prefer using a single capital letter for acronyms in
identifiers. This is mostly an advantage when another word is added
_after_ the acronym, for example consider setTXPin vs setTxPin - the
former has "TXP" at first glance, though it really should be "TX"
instead.

Gr.

Matthijs
signature.asc

Kyle Mercer

unread,
Nov 5, 2015, 9:02:58 AM11/5/15
to Developers
At the moment I am trying to find a suitable platform that will allow me to communicate with several serial devices and log some data. One of these devices is a LTE M2M module that requires a 115200 speed connection and RTS/CTS. I don't think an Arduino is up to the task of dealing with the M2M module, but the Teensy sounds like a candidate.

Now I consider myself a very basic enthusiast whose has only been working with platforms like Arduino and Raspberry Pi for a year or so. I am certainly not at the same level as many of the contributors to this topic are, but as Paul mentioned in his response in Adrian's "off topic" thread talking about the many complexities of flow control, the overall goal is to develop an API that makes it easier for the average user to interface with higher speed serial devices they are likely to encounter. I can appreciate the fact that there are many different situations that each demand application specific flow control solutions, but for users like myself, it is difficult to comprehend even the most basic nuances of flow control without some examples to follow, backed up by experimentation on the bench.

I would absolutely be interested in a serial API that provides support for hardware based RTS/CTS flow control.
Reply all
Reply to author
Forward
0 new messages