RS485 Blues… i.e. lots of questions...

Status
Not open for further replies.

Constantin

Well-known member
So I discovered the undocumented Teensy 2 feature that automatically enables/disables the DE pin on a RS485 transceiver for transmissions simply by declaring the pin in question when the Serial.begin is called. This feature is brilliant for RS485 communications because it allows a program to fill the serial buffer with a payload, ship it off in background and focus on something else in the meantime. Once the background task has finished, the DE pin is automatically pulled LOW (!!!) and the serial buffer can await the next transmission/receive.

Unfortunately, this feature does not seem to be enabled on the Teensy 3 - when I tried using it, there was no reaction by the DE pin. Paul, if this is on your Teensy 3 wish list, awesome, if not, I totally understand. I'm likely in the total minority re: the auto-on-off DE feature but DMX/Modbus folk would likely be very happy too if RS485 could be as easy as Serial in terms of implementation.

In the meantime, it appears that I have two options to control the RS485 DE pin without losing data - after initiating a transmission by pulling the DE HIGH and squirting serial data into the DI pin on the RS485 transceiver,
  • Using Serial.flush() in a blocking fashion or
  • (in a non-blocking fashion) periodically polling Serial.available() after initiating a transmission to see when the transmission is done
(and then pulling the DE pin LOW).

I would prefer a non-blocking approach simply because I'd like to keep the CPU busy with other tasks, if possible. But I wonder what the best method is… Perhaps Nick Gammons first stab at the problem where if one can calculate the size of the transmission, one can basically pre-calculate how long it will take, then pull the DE low when the elapsed time has passed? I'll have to see if the structs created by EasyTransfer allow a sizeof calculation to be used on them.

Another question I have is around serial speeds and why folk standardized on the speeds that they have for MCU-MCU communications. Simply multiplying yesterdays modem speeds is counterintuitive when the results are not even clock divisors for MCU's out there. The Atmel 328P spec sheet claims 0% error for 1Mbit/s communications with a 16MHz MCU clock (see page 195) presumably because 1Mbit/s is clean 16:1 clock ratio. I've also used 1Mbit/s between Teensy 3's over RS485 without issues so far. Is there an inherent reason not to use a serial speed that results in zero error if there is no intent to have a Arduino IDE monitor session running?

The only issues I can foresee is the recipient MCU 'missing' the signals due to speed and lack of buffer while busy with something else. I understand HardwareSerial.cpp can be modified to allow up to 255 bytes of buffer, which should be more than any message I intend my units to send to each other. Given how much RAM the Teensy 3.1 has, why not make use of the entire allowed buffer(s)?
 
Last edited:
Using threads are the usual way to do asynchronous (parallel thread) I/O.
main creates thread A which initializes then does a blocking or long timeout read, say on a serial port. When A has data from the read, it can post that in a queue. Meanwhile, main or some other thread can do a non-blocking read on the queue to see if data can be had.

Without using threads, on a serial port, there is a non-blocking call to read n bytes.

BAUD Rates
Today's well done MCUs have a fractional baud rate divisor. So the normal baud rates can have little or no error no matter the MCU's I/O clock frequency.
 
Thanks for the reply! I really appreciate it. I took a look at DuinoOS, which is a layer on top of FreeRTOS to make it more beginner-friendly. Seems like a pretty good possibility, though I wonder how well, for example, sdfatlib would play running alongside higher-priority UART transactions. May be simpler to have a deeper buffer at 255 bytes, seeing that the longest 'transaction' will likely remain under 100 bytes (i.e. 12 1-wire channels sending a float each, along with 2 long counters = about 56 bytes).

Paul's brilliant DI pin solution for the Teensy 2 makes me rethink my counter/temp board strategy. I probably should have designed that from the ground up using his 'u2 chip. It would have also given me access to more pins and made interfacing (via USB vs. Serial) that much easier. My mistake. Maybe in the next revision!

As for the baud rate divisor, I'm a bit perplexed. If there is such a divisor, why would there be published expected error rates by baud rate and MCU clock speed? Or is it perhaps a feature not found in all MCU's? I remember the gentleman who programmed the bahbot (name escapes me, sorry) choosing a very odd-looking MCU clock rate (18.4MHz) that turned out to be optimized for a particular baud rate that he wanted to nail for the serial port.
 
As for the baud rate divisor, I'm a bit perplexed. If there is such a divisor, why would there be published expected error rates by baud rate and MCU clock speed? Or is it perhaps a feature not found in all MCU's? I remember the gentleman who programmed the bahbot (name escapes me, sorry) choosing a very odd-looking MCU clock rate (18.4MHz) that turned out to be optimized for a particular baud rate that he wanted to nail for the serial port.
Yes, the MCUs designed long ago but still popular, and the very low end, lack the fractional divider. As I recall, the Teensy 3.x has at least one UART with a fractional divider. As do even older ARM7's. But I've not seen an Atmel 8 bit mega with a fractional divider.
 
Hi Steve and thanks for the insight. I've learned a lot today, from the benefits of a RTOS to fractional clock dividers! I'll see what I can dig up on those in the 1200+page K20 manual but given that I have two teensy 3.0's talking to each other at 1Mbit/s, the serial UARTs (1 and 3, respectively) seem to be OK with that speed - at least for the cable length used. I'll experiment again later when I have a 100' ethernet cable handy to see if they still communicate happily at that point. Given all the RAM in the Teensy 3.1 (the platform of choice for me going forward), maximizing buffer depth seems like a inexpensive insurance policy.

I also find it somewhat amusing that the Teensy MCU could likely give me almost twice as many digital inputs on my one-wire board than a 328P MCU. The only downside is figuring out how to accommodate all the additional channels from a 'room on the board?' point of view. I.e. would I consider wire-terminal inputs on less than 0.2" centers, for example. Or double-deckers? Something would have to give...
 
I added Serial1.transmitterEnable(pin) today, on Teensy 2.0, 3.0 and 3.1.

The code is on github.

https://github.com/PaulStoffregen/cores

Please let me know if this works for you?


Edit: All three serial ports on Teensy 3.0 and 3.1 have high-res fractional baud rate dividers. The AVR chips on Teensy 2.0, Teensy++ 2.0 and all AVR-based Arduino boards do not have fractional baud rate dividers.
 
Last edited:
Please let me know if this works for you?

Paul,

Thank you for the update and apologies for being on the road and hence unable to try out the code. I will attempt to do it this week when I am back home. The good news is that at least one of my home-baked boards uses RX1/TX1 for RS485 communications, so it should be pretty simple to try out.

Many thanks for taking the time to address this feature request,

Constantin
 
Last edited:
Paul,
Has the transmitterEnable(pin) feature been added to Serial 1-3 ? I would like to have transmitterEnable on Serial2 as well, is that possible ?
I have an application where I have (2) RS-485 comms in use.
I would like to have transmitterEnable on Serial2 as well, is that possible ?
 
Oh, looks like I only implemented it on Serial1.

I guess at the time, my thinking was to do only one of the 3, test it with my 'scope, and wait to hear feedback from users with real applications. So far, not much of that feedback has come in. Maybe it's a case of "no news is good news"?

Duplicating it to the other 2 shouldn't be terribly difficult. Are you using it now on Serial1? I'm curious if you're doing Modbus or some other RS-485 protocol and how it's working. Please let me know. Feedback from real RS-485 applications is the thing that's missing here....
 
Paul,
I am fairly new to the teensy's. During a brief review I discovered the transmitpin option and made a prototype layout with osh park assuming all 3 ports would have the same options.

Currently it is working on port 1 at a data rate of 19,200 with short data modbus packets.
Serial port 2 will be Rs485 also but at 9600 baud and using a custom protocol.

I have not scoped the timing yet as I was trying to figure out the issues with port 2.

Is there a quick edit to,adding to port 2 to test ?

Thanks for the quick reply.



Oh, looks like I only implemented it on Serial1.

I guess at the time, my thinking was to do only one of the 3, test it with my 'scope, and wait to hear feedback from users with real applications. So far, not much of that feedback has come in. Maybe it's a case of "no news is good news"?

Duplicating it to the other 2 shouldn't be terribly difficult. Are you using it now on Serial1? I'm curious if you're doing Modbus or some other RS-485 protocol and how it's working. Please let me know. Feedback from real RS-485 applications is the thing that's missing here....
 
Is there a quick edit to,adding to port 2 to test ?

Open serial1.c and serial2.c in 2 side-by-side windows. Find all the enable pin stuff in serial1.c and try replicating it in serial2.c.

I don't know if you consider that "quick", but that's how I'd do it.
 
Open serial1.c and serial2.c in 2 side-by-side windows. Find all the enable pin stuff in serial1.c and try replicating it in serial2.c.

I don't know if you consider that "quick", but that's how I'd do it.

Thanks for the suggestion Paul.
Sounds easy enough, I will try and give that a try tomorrow and put it through the paces.
 
Thanks for the suggestion Paul.
Sounds easy enough, I will try and give that a try tomorrow and put it through the paces.

Well I tried copying transmitpin references from Serial1 to serial2 without success.
Serial1 had quite a bit more code then serial2 and is above my programming experience.
I have used pin(6) as my Transmit Enable pin, and with scope attached, i am not getting any triggering.

I really hope you will add those features to all (3) serial ports, else I will have to re-make my board and just use a transistor to implement a hardware (auto-transmit) function.
 
I'll do this in a couple weeks, but first I really need to fix the pin 33 issue and get SPI transactions working.

Apologies for not testing this for you, Paul. My project has been in suspended animation thanks to work, wife, and kids. IIRC, I couldn't test it on the board since the RS485 was on Serial2 or 3 not Serial1. I had planned to muck something together to get it tested sooner, however.
 
Paul,

Fantastic !
I have been on travel the last 3 weeks, so I had to put my project on the back burner.
I will certainly give this a trial in the next day or so.

Thanks so much !
 
I was just thinking today that I can replace an Uno32 application with the Teensy 3.1. I use RS485 at 2.5 Mbps for that application. So this is great news.

Thanks Paul!
 
Paul,

Thank you for taking the time to add the Serial Transmitter pin to the other ports.
I finally got a chance to get back to my projects that were holding due to the Transmit Pin issue.
Everything is working wonderfully, and has been running the last few days non-stop without issue.
 
Status
Not open for further replies.
Back
Top