Tenssyduino RTS and CTS implementation: is it bitbanged or the processor handles it?

Status
Not open for further replies.

pramilo

Well-known member
Hi all

I'm currently working on a project using Teensy 3.2 where we have two high speed UART lines set up as One wire half duplex lines.
The setup is similar to RS485 where you need RX, TX and the direction pin. In this case we're working at TTL level so it's the same electrical design minus the RS485 signal shifter.

To the point:
From reading the processor datasheet I can see that a good choice to use as a direction pin is the RTS signal. This is a fairly common implementation and I can see the Teensy processor supports it.

At this point note we're looking at high speed communications (up to 4.5 Mbps) using one wire so our aim is to have a mechanism that shifts the Transmit Enable on and off as quickly as possible and keeps it enabled, for as little time as possible.


This is where I'm getting confused:
- I can see an early Git commit where Teensyduino seems to be using the native RTS implementation in the chip. This commit is here https://github.com/PaulStoffregen/cores/commit/c2f550d3780cba3c49cfc34bab724b268a11b7a6
The downside to doing this si that the RTS pin is basically fixed by the processor so you need to respect it.
The upside is that it seems the processor handles assertion and de-assertion of the RTS line once you configure it to this in the xxx_MODEM register.

- However on the current commit for serial1.c for example, https://github.com/PaulStoffregen/cores/blob/master/teensy3/serial1.c the code of the above commit is commented out and it seems that RTS assertion and de-assertion is being bit banged.
The upside is of course the flexibility in assigning the RTS pin to any digital pin.
The downside is more overhead which is something we're desperately trying to cut down to make sure our timings are right to get all characters and not lose bytes.

My questions are:

1) Why was there a change from using the native RTS mechanism to what seems like a bit banged approach?
At first glance the native approach looks simpler, cleaner and likely more efficient with less overhead, right?

2) Has anyone used the native RTS mechanism? If so, does the processor reliably assert and de assert the lines?
(I know the answer can be biased by the actual hardware design and the time it takes to react to the pin changes, but let's all assume the hardware responds with appropriate speed)

[EDIT] after looking into this a little better, I can see RTS is implemented as a flow control signal in teensyduino (in both variants: either native or bit banged).
I can also see RS485 is handled by the transmitEnable(pin) and that this has now been ported to all serials.

My question persists: the processor has the TXRTSE bit that can make RTS act like a Transmit Enable pin so is there a particular advantage for having it bit banged?
[/EDIT]
Thank you
Pedro
 
Last edited:
Hi

Apologies for replying to myself but since there were o replies I seem to have been able to make sense of this.

I am writing the summary below in a simple attempt to help others who are looking for this functionality.

- For RS485 operation
the Serial library in teensy, has a function called SerialX.transmitterEnable(pin). This will set the direction pin and the pin is automatically asserted and de asserted by the library when it needs to transmit.
So this works for RS485 or if you're using any other signal levels but that also require a tristate buffer (such as a one wire half duplex TTL) you can use this native functionality to set up a the direction pin.

Furthemore - and more importantly - the transmitterEnable(pin) function is available on ALL serial ports of Teensy.
At first glance, the documentation here https://www.pjrc.com/teensy/td_uart.html seems to imply this only works for Serial1 but the reality is that it works for all Serials. (suggestion to Paul, replace "Serial1." with "SerialX." to make it more generic and easier to understand it's implemented for all UARTs )

- If you need flow control then use the setRTS(pin) and setCTS(pin).

Note however that in the current Teensyduino version, this is a bitbanged approach and the HIGH WATERMARK is set in software, based on how full the library buffer is (and not how full the processor buffer is). This means that the current code might still allow for a buffer overflow of the processor's internal buffer if your code hogs or halts the interrupts for too long.

AFAIK the Teensy 3 processor has an internal buffer of 8 bytes (I think..). If your code halts interruptions for too long (either by disabling them or if you just have interrupts that run for too long), it is possible that an overflow occurs in the processor buffer - thus causing lost bytes - simply because the interrupt on the serial library won't be able to pull the characters from the processor buffer and de assert RTS to signal on time, to halt sending.

If you need to have the RTS controlling overflow on the processor buffer instead of the library buffer (for the most precise flow control, and to be independent of any interrupt hogging), PJRC has actually written code for this too, so use the code for serialX_set_rts and serialX_set_cts available here: https://github.com/PaulStoffregen/cores/commit/c2f550d3780cba3c49cfc34bab724b268a11b7a6
Note that in this case it's the processor that controls the RTS signal internally based on the status of its own internal buffer; for this reason you can't just select any pin to work as RTS: you must use the ones set in the processor design but it might work more reliably.


As for the transmitterEnable(pin) function, the processor can also handle it natively but it seems the bit banged approach used in the Serial library is sufficient and has the advantage of allowing any digital pin to be used, so there's probably an advantage here for that.

Sorry for posting the question and in the end replying to myself. Since I managed to work this out, I wanted to share my findings in case they might be helpful to others.

All the best
Pedro
 
Last edited:
Yes, the design is intended to allow any pin to be used.

The RTS approach for the software controlled buffer is intended typical Arduino applications where interrupt latency is usually not a problem, but latency in the application is. Only a few libraries disable interrupts for lengthy times. However, blocking functions and libraries that spend substantial time processing data are very common. Those will cause the software buffer to overflow. That's why the code is designed with the high watermark on the software buffer, not the hardware's FIFO.
 
I see. It makes a lot of sense :) thank you for clarifying this.

You probably know your customer base a lot better than me but I get the feeling a lot of "pro" developers tend to move to teensy because of the ease of use of teensyduino
(despite the overhead of the libraries the extra processing power of the chip makes up for it)
So this is to say that I get the feeling Teensy is catering more and more to developers with a decent amount of "under the hood" knowledge as opposed to the typical Arduino user. I think this makes it interesting and I can see how the whole 'duino' libraries get more and more advanced features.

Anyway thank you for both your great work on Teensyduino and also on your great support here on the forum.

All the best,
Pedro
 
Last edited:
Status
Not open for further replies.
Back
Top