Forums

Linux embedded and direction control of RS485 transceiver

Started by pozz March 23, 2021
I have an half-duplex RS485 bus with 10-20 different nodes. Some of them 
are 8-bit MCU based, one of them could be Linux embedded.

It's half-duplex, so it's important for the transmitter node to disable 
the driver as soon as the last transmitted bit is shifted out.

Many small low-cost MCU has interrupt on transmission complete, so the 
delay of disabling the driver is usually on the order of microseconds.

Some new Cortex-M MCUs have an automatic control of external RS485 
transceiver, so the delay is really zero.

What happens in Linux embedded systems? Many of them are based on NXP 
i.MX CPUs and it seems they aren't able to control the RS485 direction 
in hardware, but some code is needed. This approach could increase the 
delay of disabling the driver in the order of milliseconds.

Is it possible that a powerful CPU isn't able to control RS485 driver in 
hardware?
On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozzugno@gmail.com> wrote:

>I have an half-duplex RS485 bus with 10-20 different nodes. Some of them >are 8-bit MCU based, one of them could be Linux embedded. > >It's half-duplex, so it's important for the transmitter node to disable >the driver as soon as the last transmitted bit is shifted out. > >Many small low-cost MCU has interrupt on transmission complete, so the >delay of disabling the driver is usually on the order of microseconds.
Look very carefully _when_ the interrupt occurs. Some UARTs generate an interrupt when the last character is moved from the FIFO into the shift register, some (also) generate an interrupt, when actually the (last) stop bit has completely shifted out from the shift register. If you turn off the Tx based of the FIFO to shift register interrupt, the Tx can be turned off, while the last character is actually being transmitted and the 'fail safe' termination will pull the line to "1" i.e. idle. The receiver often gets the last character as FF, FE,.. , F0 etc. especially at low line speeds.
> >Some new Cortex-M MCUs have an automatic control of external RS485 >transceiver, so the delay is really zero.
This is the proper way of doing low latency half duplex. Otherwise, you have to add some extra delay, before the slave starts the response.
> >What happens in Linux embedded systems? Many of them are based on NXP >i.MX CPUs and it seems they aren't able to control the RS485 direction >in hardware, but some code is needed. This approach could increase the >delay of disabling the driver in the order of milliseconds. > >Is it possible that a powerful CPU isn't able to control RS485 driver in >hardware?
Un bel giorno pozz digit&#2013265922;:

> I have an half-duplex RS485 bus with 10-20 different nodes. Some of them > are 8-bit MCU based, one of them could be Linux embedded. > > It's half-duplex, so it's important for the transmitter node to disable > the driver as soon as the last transmitted bit is shifted out. > > Many small low-cost MCU has interrupt on transmission complete, so the > delay of disabling the driver is usually on the order of microseconds. > > Some new Cortex-M MCUs have an automatic control of external RS485 > transceiver, so the delay is really zero. > > What happens in Linux embedded systems? Many of them are based on NXP > i.MX CPUs and it seems they aren't able to control the RS485 direction > in hardware, but some code is needed. This approach could increase the > delay of disabling the driver in the order of milliseconds. > > Is it possible that a powerful CPU isn't able to control RS485 driver in > hardware?
You should use the RS232 handshake signals (i.e. the RTS signal) in order to do that. i.MX UARTs should support them, but it doesn't look very straightforward indeed: https://community.nxp.com/t5/i-MX-Processors/RTS-CTS-handshake-confusion/m-p/237057 -- Fletto i muscoli e sono nel vuoto.
On 3/23/2021 10:28 PM, upsidedown@downunder.com wrote:
> On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozzugno@gmail.com> wrote: > >> I have an half-duplex RS485 bus with 10-20 different nodes. Some of them >> are 8-bit MCU based, one of them could be Linux embedded. >> >> It's half-duplex, so it's important for the transmitter node to disable >> the driver as soon as the last transmitted bit is shifted out. >> >> Many small low-cost MCU has interrupt on transmission complete, so the >> delay of disabling the driver is usually on the order of microseconds. > > Look very carefully _when_ the interrupt occurs. Some UARTs generate > an interrupt when the last character is moved from the FIFO into the > shift register, some (also) generate an interrupt, when actually the > (last) stop bit has completely shifted out from the shift register. > > If you turn off the Tx based of the FIFO to shift register interrupt, > the Tx can be turned off, while the last character is actually being > transmitted and the 'fail safe' termination will pull the line to "1" > i.e. idle. The receiver often gets the last character as FF, FE,.. , > F0 etc. especially at low line speeds.
As you likely have the line connected to the Rx input (to *receive* replies), you can use the Rx IRQ to tell you when the character has cleared the Tx shift register (and made it out onto the wire). But, you also have to check the timing of that IRQ wrt the actual serial data in. Sometimes, the stop bits aren't checked. However, anomalies/faults on the line can prevent the Rx interrupt from coinciding with the end of the Tx (e.g., if a voltage is effectively impressed on the line). The loopback will allow your code to detect that transmissions are not happening as expected. But, it will confuse the timing of the disabling of the transceiver. A better solution is to route the Tx *pin* on the device to a spare Rx pin (another UART) and use that for timing information as it is entirely local to the board -- not impacted by faults on the wire.
>> Some new Cortex-M MCUs have an automatic control of external RS485 >> transceiver, so the delay is really zero. > > This is the proper way of doing low latency half duplex. Otherwise, > you have to add some extra delay, before the slave starts the > response.
That's often desirable to let the line "settle" (assuming the software is incredibly responsive and the slave receiver was fortunate in how it synchronized to the incoming datum). In the real world, folks don't always wire things the way they should (e.g., using crappy cable for longer than intended runs -- "Wire is wire, right?" :< )
On Wed, 24 Mar 2021 06:17:46 -0700, Don Y
<blockedofcourse@foo.invalid> wrote:

>On 3/23/2021 10:28 PM, upsidedown@downunder.com wrote: >> On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozzugno@gmail.com> wrote: >> >>> I have an half-duplex RS485 bus with 10-20 different nodes. Some of them >>> are 8-bit MCU based, one of them could be Linux embedded. >>> >>> It's half-duplex, so it's important for the transmitter node to disable >>> the driver as soon as the last transmitted bit is shifted out. >>> >>> Many small low-cost MCU has interrupt on transmission complete, so the >>> delay of disabling the driver is usually on the order of microseconds. >> >> Look very carefully _when_ the interrupt occurs. Some UARTs generate >> an interrupt when the last character is moved from the FIFO into the >> shift register, some (also) generate an interrupt, when actually the >> (last) stop bit has completely shifted out from the shift register. >> >> If you turn off the Tx based of the FIFO to shift register interrupt, >> the Tx can be turned off, while the last character is actually being >> transmitted and the 'fail safe' termination will pull the line to "1" >> i.e. idle. The receiver often gets the last character as FF, FE,.. , >> F0 etc. especially at low line speeds. > >As you likely have the line connected to the Rx input (to *receive* >replies), you can use the Rx IRQ to tell you when the character has >cleared the Tx shift register (and made it out onto the wire).
Yes, I have sometimes used this, but it requires that the Rx path is always active. Some RS-485 chips disable the Rx side when transmitting, so you do not hear your own transmission, thus no echo canceling is required in the software.
>But, you also have to check the timing of that IRQ wrt the actual serial >data in. Sometimes, the stop bits aren't checked. > >However, anomalies/faults on the line can prevent the Rx interrupt >from coinciding with the end of the Tx (e.g., if a voltage is effectively >impressed on the line). The loopback will allow your code to detect that >transmissions are not happening as expected. But, it will confuse the >timing of the disabling of the transceiver.
If he line is shorted or connected to Vcc, loosing timing is the smallest problem :-) Even if the problem is at the remote end of the cable, the problem must be pretty severe, if you can't detect your own transmission on the PCB before entering the line.
> >A better solution is to route the Tx *pin* on the device to a spare >Rx pin (another UART) and use that for timing information as it >is entirely local to the board -- not impacted by faults on the >wire.
What is the point of doing loopbacK on TTL, if the RS-485 is bad ?
> >>> Some new Cortex-M MCUs have an automatic control of external RS485 >>> transceiver, so the delay is really zero. >> >> This is the proper way of doing low latency half duplex. Otherwise, >> you have to add some extra delay, before the slave starts the >> response. > >That's often desirable to let the line "settle" (assuming the software >is incredibly responsive and the slave receiver was fortunate in how it >synchronized to the incoming datum). In the real world, folks don't >always wire things the way they should (e.g., using crappy cable for >longer than intended runs -- "Wire is wire, right?" :< )
In the Modbus RTU protocol specification it is required to turn on the transmitter (set to idle "1" state), wait 3.5 character times, then send the actual message, then keep the transmitter in active idle ("1") state for an other 3.5 character times, before turning off the transmitter, i.e. put the transmitter into tri-state. When the transmitter is turned into rtri-state and there are 'fail safe' pull up/down resistors, the line remains in the idle "1" state until next transmitter takes over the bus. BTW, the quotes around 'fail safe' termination is in the actual standard text, at least in early versions. If no passive pull up/down resistors are present on the bus, old signal reflections and external noise will cause some variable unknown noise voltages on the bus. However, when the next node turns the transmitter on for 3.5 character times in idle state, after it the first start bit of the first character is reliably detected. In Modbus RTU, there is at least 3.5 character times idle period between actual data transmitter between two stations since it is perfectly legal for station A to have the trailing 3.5 trailing idle and station B sends 3.5 preamble on simultaneously. Actually there are 5 (1.5+3.5) character times to turn of the Tx transmitter, since the Rx uses a 1.5 character time idle period as end of frame marker. In half duplex communication with short messages, the latencies between frames will reduce the throughput considerably. With long messages, the throughput loss is not significant.
On 24.3.21 17.49, upsidedown@downunder.com wrote:
> On Wed, 24 Mar 2021 06:17:46 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >> On 3/23/2021 10:28 PM, upsidedown@downunder.com wrote: >>> On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozzugno@gmail.com> wrote: >>> >>>> I have an half-duplex RS485 bus with 10-20 different nodes. Some of them >>>> are 8-bit MCU based, one of them could be Linux embedded. >>>> >>>> It's half-duplex, so it's important for the transmitter node to disable >>>> the driver as soon as the last transmitted bit is shifted out. >>>> >>>> Many small low-cost MCU has interrupt on transmission complete, so the >>>> delay of disabling the driver is usually on the order of microseconds. >>> >>> Look very carefully _when_ the interrupt occurs. Some UARTs generate >>> an interrupt when the last character is moved from the FIFO into the >>> shift register, some (also) generate an interrupt, when actually the >>> (last) stop bit has completely shifted out from the shift register. >>> >>> If you turn off the Tx based of the FIFO to shift register interrupt, >>> the Tx can be turned off, while the last character is actually being >>> transmitted and the 'fail safe' termination will pull the line to "1" >>> i.e. idle. The receiver often gets the last character as FF, FE,.. , >>> F0 etc. especially at low line speeds. >> >> As you likely have the line connected to the Rx input (to *receive* >> replies), you can use the Rx IRQ to tell you when the character has >> cleared the Tx shift register (and made it out onto the wire). > > Yes, I have sometimes used this, but it requires that the Rx path is > always active. Some RS-485 chips disable the Rx side when > transmitting, so you do not hear your own transmission, thus no echo > canceling is required in the software. > > >> But, you also have to check the timing of that IRQ wrt the actual serial >> data in. Sometimes, the stop bits aren't checked. >> >> However, anomalies/faults on the line can prevent the Rx interrupt >>from coinciding with the end of the Tx (e.g., if a voltage is effectively >> impressed on the line). The loopback will allow your code to detect that >> transmissions are not happening as expected. But, it will confuse the >> timing of the disabling of the transceiver. > > If he line is shorted or connected to Vcc, loosing timing is the > smallest problem :-) Even if the problem is at the remote end of the > cable, the problem must be pretty severe, if you can't detect your own > transmission on the PCB before entering the line. > >> >> A better solution is to route the Tx *pin* on the device to a spare >> Rx pin (another UART) and use that for timing information as it >> is entirely local to the board -- not impacted by faults on the >> wire. > > What is the point of doing loopbacK on TTL, if the RS-485 is bad ? > >> >>>> Some new Cortex-M MCUs have an automatic control of external RS485 >>>> transceiver, so the delay is really zero. >>> >>> This is the proper way of doing low latency half duplex. Otherwise, >>> you have to add some extra delay, before the slave starts the >>> response. >> >> That's often desirable to let the line "settle" (assuming the software >> is incredibly responsive and the slave receiver was fortunate in how it >> synchronized to the incoming datum). In the real world, folks don't >> always wire things the way they should (e.g., using crappy cable for >> longer than intended runs -- "Wire is wire, right?" :< ) > > In the Modbus RTU protocol specification it is required to turn on the > transmitter (set to idle "1" state), wait 3.5 character times, then > send the actual message, then keep the transmitter in active idle > ("1") state for an other 3.5 character times, before turning off the > transmitter, i.e. put the transmitter into tri-state. > > When the transmitter is turned into rtri-state and there are 'fail > safe' pull up/down resistors, the line remains in the idle "1" state > until next transmitter takes over the bus. BTW, the quotes around > 'fail safe' termination is in the actual standard text, at least in > early versions. > > If no passive pull up/down resistors are present on the bus, old > signal reflections and external noise will cause some variable unknown > noise voltages on the bus. However, when the next node turns the > transmitter on for 3.5 character times in idle state, after it the > first start bit of the first character is reliably detected. > > In Modbus RTU, there is at least 3.5 character times idle period > between actual data transmitter between two stations since it is > perfectly legal for station A to have the trailing 3.5 trailing idle > and station B sends 3.5 preamble on simultaneously. Actually there are > 5 (1.5+3.5) character times to turn of the Tx transmitter, since the > Rx uses a 1.5 character time idle period as end of frame marker. > > In half duplex communication with short messages, the latencies > between frames will reduce the throughput considerably. With long > messages, the throughput loss is not significant.
The Modbus RTU is rotten - a protocol so badly designed that it is difficult to exceed. Modbus on TCP is no better. -- -TV
On Wed, 24 Mar 2021 18:32:36 +0200, Tauno Voipio
<tauno.voipio@notused.fi.invalid> wrote:

>> In the Modbus RTU protocol specification it is required to turn on the >> transmitter (set to idle "1" state), wait 3.5 character times, then >> send the actual message, then keep the transmitter in active idle >> ("1") state for an other 3.5 character times, before turning off the >> transmitter, i.e. put the transmitter into tri-state. >> >> When the transmitter is turned into rtri-state and there are 'fail >> safe' pull up/down resistors, the line remains in the idle "1" state >> until next transmitter takes over the bus. BTW, the quotes around >> 'fail safe' termination is in the actual standard text, at least in >> early versions. >> >> If no passive pull up/down resistors are present on the bus, old >> signal reflections and external noise will cause some variable unknown >> noise voltages on the bus. However, when the next node turns the >> transmitter on for 3.5 character times in idle state, after it the >> first start bit of the first character is reliably detected. >> >> In Modbus RTU, there is at least 3.5 character times idle period >> between actual data transmitter between two stations since it is >> perfectly legal for station A to have the trailing 3.5 trailing idle >> and station B sends 3.5 preamble on simultaneously. Actually there are >> 5 (1.5+3.5) character times to turn of the Tx transmitter, since the >> Rx uses a 1.5 character time idle period as end of frame marker. >> >> In half duplex communication with short messages, the latencies >> between frames will reduce the throughput considerably. With long >> messages, the throughput loss is not significant. > > >The Modbus RTU is rotten - a protocol so badly designed that it >is difficult to exceed. Modbus on TCP is no better.
While the Modbus RTU timing specifications look hard, quite a lot slack is possible in practice. Not much problem in point-to-point. In a multidrop slave configuration the only critical timing is the pause between slave A response before the master sends the next command to slave B. Slave B must be able to detect the end of slave A transmission, i.e. at least a 1.5 character time pause. This is easy if the slave UART has hardware idle detection. If the pause is not properly detected, response from slave A and master command to slave B are appended and the CRC doesn't match. This will cause a timeout and a retransmission by the master to slave B. What is wrong with Modbus/TCP ? It is a nice request/response protocol with a fixed size header (including byte count) and variable size payload ?
On 24/03/2021 18:22, upsidedown@downunder.com wrote:
> On Wed, 24 Mar 2021 18:32:36 +0200, Tauno Voipio > <tauno.voipio@notused.fi.invalid> wrote: >
>> The Modbus RTU is rotten - a protocol so badly designed that it >> is difficult to exceed. Modbus on TCP is no better. > > What is wrong with Modbus/TCP ? It is a nice request/response protocol > with a fixed size header (including byte count) and variable size > payload ? > >
Modbus/TCP has a bit of redundancy in its headers, and some limits that exist only because of its heritage (like the maximum number of registers you are allowed to transfer at a time being 127, and the highest register address being 9999). If you are writing your own server code, you can easily ignore them, but the master side has to know that the server supports them. There are a number of underspecified issues, such as endianness (especially for multi-register items) and atomicity of transfers. And there is the silly mixup of register numbers (1 to 10000) and addresses (0 to 9999). Then there are a whole bunch of rarely used function codes that made little sense for Modbus RTU, and no sense at all when you have Ethernet. However, none of these are major hinders to writing and using Modbus/TCP. It is quite simple to write and use, and is well supported by off-the-shelf stuff. It is not perfect, and not how you would design a modern Ethernet-based register access protocol from scratch, but is fine enough in practice. It is infinitely better than Profinet and some of the other PLC protocols in use.
On 24.3.21 19.22, upsidedown@downunder.com wrote:
> On Wed, 24 Mar 2021 18:32:36 +0200, Tauno Voipio > <tauno.voipio@notused.fi.invalid> wrote: > >>> In the Modbus RTU protocol specification it is required to turn on the >>> transmitter (set to idle "1" state), wait 3.5 character times, then >>> send the actual message, then keep the transmitter in active idle >>> ("1") state for an other 3.5 character times, before turning off the >>> transmitter, i.e. put the transmitter into tri-state. >>> >>> When the transmitter is turned into rtri-state and there are 'fail >>> safe' pull up/down resistors, the line remains in the idle "1" state >>> until next transmitter takes over the bus. BTW, the quotes around >>> 'fail safe' termination is in the actual standard text, at least in >>> early versions. >>> >>> If no passive pull up/down resistors are present on the bus, old >>> signal reflections and external noise will cause some variable unknown >>> noise voltages on the bus. However, when the next node turns the >>> transmitter on for 3.5 character times in idle state, after it the >>> first start bit of the first character is reliably detected. >>> >>> In Modbus RTU, there is at least 3.5 character times idle period >>> between actual data transmitter between two stations since it is >>> perfectly legal for station A to have the trailing 3.5 trailing idle >>> and station B sends 3.5 preamble on simultaneously. Actually there are >>> 5 (1.5+3.5) character times to turn of the Tx transmitter, since the >>> Rx uses a 1.5 character time idle period as end of frame marker. >>> >>> In half duplex communication with short messages, the latencies >>> between frames will reduce the throughput considerably. With long >>> messages, the throughput loss is not significant. >> >> >> The Modbus RTU is rotten - a protocol so badly designed that it >> is difficult to exceed. Modbus on TCP is no better. > > While the Modbus RTU timing specifications look hard, quite a lot > slack is possible in practice. Not much problem in point-to-point. > > In a multidrop slave configuration the only critical timing is the > pause between slave A response before the master sends the next > command to slave B. Slave B must be able to detect the end of slave A > transmission, i.e. at least a 1.5 character time pause. This is easy > if the slave UART has hardware idle detection. > > If the pause is not properly detected, response from slave A and > master command to slave B are appended and the CRC doesn't match. This > will cause a timeout and a retransmission by the master to slave B. > > What is wrong with Modbus/TCP ? It is a nice request/response protocol > with a fixed size header (including byte count) and variable size > payload ?
The main problem is TCP. The modbus messages are datagrams by their very nature, and they should be using UDP/IP instead. TCP explicitly does *not* preserve record boundaries, but UDP does. The RTU packet framing is bad: it prevents using any hardware UART buffering if the timing specifications are to be obeyed. All Modbus handlers on PCs I have met do not obey the packet timing constraints except occasionally. I wrote the first Modbus drivers for MC68332 with 16450 UARTs, and it was quite a fight to make the system conform fully to the timing specs. The framing should be timing-independent, and just depending on special characters in the data stream, like PPP in HDLC-style framing (RFC 1662). -- -TV
On 3/24/2021 8:49 AM, upsidedown@downunder.com wrote:
> On Wed, 24 Mar 2021 06:17:46 -0700, Don Y
>> As you likely have the line connected to the Rx input (to *receive* >> replies), you can use the Rx IRQ to tell you when the character has >> cleared the Tx shift register (and made it out onto the wire). > > Yes, I have sometimes used this, but it requires that the Rx path is > always active. Some RS-485 chips disable the Rx side when > transmitting, so you do not hear your own transmission, thus no echo > canceling is required in the software.
I always use separate Tx and Rx devices -- so I *can* hear my own transmissions. Otherwise, I have to rely on timeouts to discover when I didn't get an expected reply -- and then, all I can do is complain (I can't provide any additional information to the user to help him sort to what the problem may be -- big difference between "slave not responding" and "comm line has faulted"!) I've designed devices where a relay allows me to galvanically disconnect from the line (as a *functional* slave) while the master applies a super-voltage to blow the "fuses" of any devices that were hung and interfering with comms. (i.e., if you can't hear what you -- as a slave -- are saying, you know you should disconnect from the line cuz bad things are going to happen RSN!)
>> However, anomalies/faults on the line can prevent the Rx interrupt >>from coinciding with the end of the Tx (e.g., if a voltage is effectively >> impressed on the line). The loopback will allow your code to detect that >> transmissions are not happening as expected. But, it will confuse the >> timing of the disabling of the transceiver. > > If he line is shorted or connected to Vcc, loosing timing is the > smallest problem :-) Even if the problem is at the remote end of the > cable, the problem must be pretty severe, if you can't detect your own > transmission on the PCB before entering the line.
The point is that you will never get the information necessary to tell *you* to disable your driver! (unless you add another timeout mechanism on top of that)
>> A better solution is to route the Tx *pin* on the device to a spare >> Rx pin (another UART) and use that for timing information as it >> is entirely local to the board -- not impacted by faults on the >> wire. > > What is the point of doing loopbacK on TTL, if the RS-485 is bad ?
You're not doing the loopback on the TTL. You're using the extra Rx input for *timing* (because you KNOW the Tx character must have cleared the transmit shift register before the receiver can claim to have received it). If you don't have a spare UART, you can also use a timer input; trigger the timer on a start bit (even if it has to retrigger on subsequent data bits) and then let the timer timeout in a character time. All of these are more efficient than having the OS schedule a system timer event for you to do the deed. You don't want to promote such a low-level "driver activity" to anything more significant than it needs to be!