Teensy Hardware Flow Control RTS/CTS

An alternate way is to set RTS via digitalWrite (when buffer is full).. supersimple, reliable, no fiddling with interrupts and bugs in hardware....
...can use any pin and every Serial on T3.. works with fifo and without.

edit: used this with my "audiostreaming"-experiment. Worked great.


I think I tried this method and it did not work as it leaves data stranded in the fifo if it was during an idle interrupt when you set RTS in software. You will have to add code in read function to drain the fifo, which then makes the change not simple anymore.
 
I think I tried this method and it did not work as it leaves data stranded in the fifo if it was during an idle interrupt when you set RTS in software. You will have to add code in read function to drain the fifo, which then makes the change not simple anymore.

Err... you don't need the idle interrupt!
Just take pauls original source, add the digitialWrite to disable RTS in the ISR when buffer is full (~minus a few bytes ) and enable it in the read function. Ignore the fifo, it works with and without the same way...keep it simple..nothing else has to be changed*
-that worked for me (i added a lot of other stuff there and have "giant" (some kb) buffers, otherwise i would post my code.

*Think of RTS as a flag that tells the sender to stop sending bytes. Not more, not less. You could even do it in your loop()
 
Last edited:
Err... you don't need the idle interrupt!
Just take pauls original source, add the digitialWrite to disable RTS in the ISR when buffer is full (~minus a few bytes ) and enable it in the read function. Ignore the fifo, it works with and without the same way...keep it simple..nothing else has to be changed.
that worked for me (i added a lot of other stuff there and have "giant" (some kb) buffers, otherwise i would post my code.

You do know how the idle interrupt works right? and you know the original source handles idle interrupt right?
if say there is one more byte that arrives and then no more, your receive interrupt will not trigger, but the idle interrupt will to let the ISR collect that last byte. If during that interrupt the buffer is full and you cannot pull that one byte, so you raise RTS. If there are no more bytes that will arrive, then receive interrupt will not occur anymore and likewise idle interrupt will not occur anymore. hence your last byte is stranded.

It is also a little bit more complicated than how you described. You have to choose whether to clear the interrupt flag or not. If you do not clear it, the interrupt will not occur again even if interrupt condition is satisfied. If you clear it, the interrupt will keep occurring.

As I said, I tried all permutations of code I can think of, and it is not as simple as you think it is. :)
 
You do know how the idle interrupt works right? and you know the original source handles idle interrupt right?
if say there is one more byte that arrives and then no more, your receive interrupt will not trigger, but the idle interrupt will to let the ISR collect that last byte. If during that interrupt the buffer is full and you cannot pull that one byte, so you raise RTS. If there are no more bytes that will arrive, then receive interrupt will not occur anymore and likewise idle interrupt will not occur anymore. hence your last byte is stranded.

It is also a little bit more complicated than how you described. You have to choose whether to clear the interrupt flag or not. If you do not clear it, the interrupt will not occur again even if interrupt condition is satisfied. If you clear it, the interrupt will keep occurring.

As I said, I tried all permutations of code I can think of, and it is not as simple as you think it is. :)

Just try it out! Disable rts in loop(), dont change anything else. You will see it works.
Its the same situation when the sender has nothing to send. No difference. The isr does not need to know about the existanse of rts.. (well ok you switch rts there but without doing anything else)

There is no difference if it is idle because the sender doesnt have data to send or idle because it does not send because it got the command to stop.

ignore the idle-condition. ignore the hw-fifo.
 
Last edited:
..and re-read my post..#52 i wrote "ISR when buffer is full (~minus a few bytes )"

minus a few bytes (fifo-size +x) , which means, there is allways room in the buffer
 
... i can do a pull-request next weekend (if you or Paul aren't faster :) )
are there any issues with cts ?
 
You have to choose whether to clear the interrupt flag or not. If you do not clear it, the interrupt will not occur again even if interrupt condition is satisfied. If you clear it, the interrupt will keep occurring.
If the IDLE or RDRF flags are not cleared it will actually keep calling the isr and eat up all the CPU time. I checked it on my scope. To remedy this you can do like dougboy does and disable the IDLE and RDRF interrupts (Hardware RTS) or you have to read the UARTx_D register which will clear the flags but then you lose that byte if the buffer is full (SOFTWARE). Yes, you can signal RTS before the buffer or fifo is full but then you are adding alot of supporting code to the uart isr. Unless I'm missing something? Frank, do you have the software rts/cts available so i could see how you did it?
 
I did only rts, not cts. Not in the isr because that made not much sense in my special use-case.

But i can write somthing, sure. Not today - have not enough time. i think i can post it sundoay or monday.
Of course it add needs some additional lines in the isr (to get the available buffer space).
But it only needs to disable RTS.

Enabling is done when emptying the buffer in..i don't remember the name now..is it read() ?

Edit: Again: There is always space in the hw-fifo when using that technique (well, if the transmitting devices supports hw-handshake of course - if not you have an other problem..)

Edit: i don't know what is so complicated to understand it ?
- setup a sender which sends a byte every second
- take the old original teensy-source which does not know anything about rts
- simulate rts by hand by connecting a wire from time to time.
you will see it works, the sender stops sending and the teensy keeps working as expected (well, it does not know about the "handshake" so no codechange is needed!)

using my proposed digitalwrite does the same, but automatically.
 
Last edited:
Yes, you can signal RTS before the buffer or fifo is full but then you are adding alot of supporting code to the uart isr.

It's not too much code, and the benefit is huge. You can implement any "high watermark" number. I'd like to see a default at least 20 bytes away from the buffer size, so we always signal RTS with enough space for the other side to respond.

For the FIFO versions, the check if the buffer has filled beyond the high watermark only needs to be done after all the bytes are copied from FIFO to memory.


But i can write somthing, sure. Not today - have not enough time. i think i can post it sundoay or monday.

I was going to do this last weekend, but got distracted with other urgent stuff, plus the regular answering of questions and running PJRC.

Sadly, with the audio workshop coming up, I probably won't get back to this until mid-November. The audio workshop is forcing me to write better documentation and tutorial material. I'm not good at finding time to do that, so it takes a hard deadline. Unfortunately, it does mean I'm not going to work on other stuff much until after Nov 15.

Enabling is done when emptying the buffer in..i don't remember the name now..is it read() ?

Yes, the low watermark needs to be checked in serial_getchar() and of course serial_clear() needs to clear RTS.
 
No problem, i'll see what i can do next weekend und upload the code here for a review before doing a pull-request.
I did'nt look at the details of CTS, is it ok to use doughboys' code for CTS ?
 
Ok, i invested 1 hour.. for programming and a *very* incomplete little test.
So pls. don't expect that it is perfect and well tested, but it should show what i mean. And i only checked it for Teensy 3.1. LC might not work.

And I did RTS only, so if there is something to do regarding CTS this must wait.
(i don't know what doughboy did with cts? perhaps just copy&paste his cts changes, if there are any. i did'nt look at this)

It isn't a couple of lines in the ISR..it's ONE line (ok, a little cheateding because of the macro) :rolleyes:
I did not use "digitalWrite" - i just copy&pasted the existing code for "transmit". i think it's faster.

I hope it works for you ?

edit: code removed , had inverted RTS
 
Last edited:
@Frank: What was the test bed? It would need a CTS aware device on the other end? Without CTS support it wasn't a Teensy to Teensy sample?
 
@Frank: What was the test bed? It would need a CTS aware device on the other end? Without CTS support it wasn't a Teensy to Teensy sample?

Code:
#define HWSERIAL Serial1

void setup() {
    Serial.begin(9600);
  HWSERIAL.begin(38400);
 Serial1.rts_enable(2);
 delay(1000);
}

void loop() {
    int incomingByte; 

 for (int i=0; i< 44; i++) {
 delay(100);
 Serial.printf("RXAvailable:%d  TXFree:%d\r\n",HWSERIAL.available(), HWSERIAL.availableForWrite());
 HWSERIAL.print("a");
 yield();
 }
//musss hier aus sein

//BLINK:
do {
    delay(1000);
    HWSERIAL.read();
    //muss hier an sein
    delay(1000);
    HWSERIAL.print("a");
    //muss hier aus sein
    yield();
} while(1);
}

- Short pin 0 & 1 with a wire
- Short pin 2 & 13 with a wire.
After a few seconds it should start to blink - as indication that RTS switches on and off.

Sry.. more tomorrow.. its 23:42 :)
 
Ok, i invested 1 hour.. for programming and a *very* incomplete little test.
So pls. don't expect that it is perfect and well tested, but it should show what i mean. And i only checked it for Teensy 3.1. LC might not work.
Thanks, just got back home so I'll check it out tonight and let you know.

And I did RTS only, so if there is something to do regarding CTS this must wait.
(i don't know what doughboy did with cts? perhaps just copy&paste his cts changes, if there are any. i did'nt look at this)
I have the hardware cts going so I'm good on this, works like a charm.

It isn't a couple of lines in the ISR..it's ONE line (ok, a little cheateding because of the macro) :rolleyes:
Haha, I guess you can say that its one line;)
 
@Frank: Thanks - got it. Except this line won't compile :) "//musss hier aus sein" . . . oh wait - just an extra 's'. Gute Nacht
 
@Frank: Thanks - got it. Except this line won't compile :) "//musss hier aus sein" . . . oh wait - just an extra 's'. Gute Nacht

Sorry .)
You can translate it with "LED should be off" and "LED should be on"

I tried to merge both versions (doughboys CTS changes and my RTS changes(post#63)) :

Here's the diff to serial1.c :
https://github.com/PaulStoffregen/cores/compare/master...FrankBoesing:patch_serial1

I hope that i caught all his changes. If not please shout :)
Here's the download:
https://raw.githubusercontent.com/FrankBoesing/cores/patch_serial1/teensy3/serial1.c

This is my branch of the new version (complete Repo) :
https://github.com/FrankBoesing/cores/blob/patch_serial1/teensy3/serial1.c
 
Last edited:
Sorry .)
You can translate it with "LED should be off" and "LED should be on"

I tried to merge both versions (doughboys CTS changes and my RTS changes(post#63)) :

Here's the diff to serial1.c :
https://github.com/PaulStoffregen/cores/compare/master...FrankBoesing:patch_serial1

I hope that i caught all his changes. If not please shout :)
Here's the download:
https://raw.githubusercontent.com/FrankBoesing/cores/patch_serial1/teensy3/serial1.c

This is my branch of the new version (complete Repo) :
https://github.com/FrankBoesing/cores/blob/patch_serial1/teensy3/serial1.c

oops :)

I did some tests with coolterm and an usb<-->serial converter
Had rts=1 where it should have been 0 and vice versa.
That is fixed on github now.

Seems to work good!


edit: testcode:
Code:
#define HWSERIAL Serial1

void setup() {
  Serial.begin(9600);
  HWSERIAL.begin(9600);
  Serial1.rts_enable(2);
}

void loop() {
  char incoming;
  if (HWSERIAL.available() > 0) {
    incoming = HWSERIAL.read();
    Serial.print(incoming);
    Serial1.print(incoming);
    }
  delay(100);
}
1) Connect the usb<->serial to the Teensy
2) Start Coolterm, & setup hw-handshake
3) Copy & and paste "Jabberwocky" (Lewis Carroll) to the coolterm-window. You'll see: the handshake works.
 
Last edited:
I had some time last night to run some tests and yes it works good! Oh ya I did change the assert and deasserts but besides that all good as far as I can tell. One thing is if a higher priority ISR is eating up most of the CPU time your code does fail where the hardware rts seems to be able to deal with that. If i find anything I'll update this thread.
 
I'm really looking forward to having a rts / cts function in the serial port.
so I'm marking this thread to keep eye on.

A little side chat !
its very common to have inverted levels on RS232 / V24. on the data and the control lines.
I think it all boils down to the orriginal ITU spec being ambigous on what is a '1' and what is a '0'.

its a great spec, that goes out of its way to avoid saying voltage levels,

the best it gets to is

'Asserrt, is something like 4 volts to 20, and is a '0'
'de asset is something like -4 to -20 volts, and is a '1'

to most engineers, a '1' is a positive voltage , whilst on the line, a '1' is a negative voltage.
add to that that most , not all RS232 receivers / transmitters invert the line levels, and you have a great ground for confusion !!

You will find many an RS232 circuit / system that has the option to invert levels,
dons't mean we should not get it right by default, but option to invert a pin is always useful in software...
 
Back
Top