Linux embedded and direction control of RS485 transceiver

45 views
Skip to first unread message

pozz

unread,
Mar 23, 2021, 7:06:26 PMMar 23
to
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?

upsid...@downunder.com

unread,
Mar 24, 2021, 1:28:18 AMMar 24
to
On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozz...@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.

dalai lamah

unread,
Mar 24, 2021, 6:48:22 AMMar 24
to
Un bel giorno pozz digitň:
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.

Don Y

unread,
Mar 24, 2021, 9:18:07 AMMar 24
to
On 3/23/2021 10:28 PM, upsid...@downunder.com wrote:
> On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozz...@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?" :< )

upsid...@downunder.com

unread,
Mar 24, 2021, 11:49:31 AMMar 24
to
On Wed, 24 Mar 2021 06:17:46 -0700, Don Y
<blocked...@foo.invalid> wrote:

>On 3/23/2021 10:28 PM, upsid...@downunder.com wrote:
>> On Wed, 24 Mar 2021 00:06:21 +0100, pozz <pozz...@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.


Tauno Voipio

unread,
Mar 24, 2021, 12:32:41 PMMar 24
to
The Modbus RTU is rotten - a protocol so badly designed that it
is difficult to exceed. Modbus on TCP is no better.

--

-TV

upsid...@downunder.com

unread,
Mar 24, 2021, 1:22:16 PMMar 24
to
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 ?


David Brown

unread,
Mar 24, 2021, 2:44:45 PMMar 24
to
On 24/03/2021 18:22, upsid...@downunder.com wrote:
> On Wed, 24 Mar 2021 18:32:36 +0200, Tauno Voipio
> <tauno....@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.

Tauno Voipio

unread,
Mar 24, 2021, 3:13:20 PMMar 24
to
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


Don Y

unread,
Mar 24, 2021, 5:31:11 PMMar 24
to
On 3/24/2021 8:49 AM, upsid...@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!

pozz

unread,
Mar 24, 2021, 7:23:30 PMMar 24
to
Il 24/03/2021 11:48, dalai lamah ha scritto:
> Un bel giorno pozz digitò:
Yes, you can use RTS, but some software MUST change a register bit to
move that signal!!!


upsid...@downunder.com

unread,
Mar 25, 2021, 1:34:22 AMMar 25
to
On Wed, 24 Mar 2021 19:44:39 +0100, David Brown
<david...@hesbynett.no> wrote:

>On 24/03/2021 18:22, upsid...@downunder.com wrote:
>> On Wed, 24 Mar 2021 18:32:36 +0200, Tauno Voipio
>> <tauno....@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.

In the human readable format, e.g. the "4" format (40001 .. 49999)
seem to imply only 9999 holding registers, but the 4 in the address is
not usually transmitted, only 0 .. 9998 in the message. However, you
can put 0000h to FFFFh in the message field. It is just the human
readable form that has problems. Some use 499999 or 4'99999. Very old
implementation used 4001 to 4999 for the human readable format.

upsid...@downunder.com

unread,
Mar 25, 2021, 1:39:06 AMMar 25
to
On Wed, 24 Mar 2021 21:13:14 +0200, Tauno Voipio
Quite a few vendors support also Modbus/UDP.

upsid...@downunder.com

unread,
Mar 25, 2021, 1:48:03 AMMar 25
to
On Wed, 24 Mar 2021 19:44:39 +0100, David Brown
<david...@hesbynett.no> wrote:

>On 24/03/2021 18:22, upsid...@downunder.com wrote:
>> On Wed, 24 Mar 2021 18:32:36 +0200, Tauno Voipio
>> <tauno....@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.

Modbus RTU registers are big endian Modbus RTU did not support 32 bit
integers or floats. However, many vendors needed to transfer 32 bit
entities, so they used their own format for these double register
pairs. The vendors have carried these formats also to Modbus/TCP.

David Brown

unread,
Mar 25, 2021, 5:48:36 AMMar 25
to
It would have made sense for Modbus to be standardised on UDP as well.
But TCP/IP has advantages over UDP - it is a lot more reliable if you
have a complicated network setup, or multiple masters.

Omron have a "FINS" protocol that is much the same principle as Modbus,
with both UDP and TCP/IP versions, and where I have experience with both
versions.

UDP is fine on a simple local Ethernet connection, but often has trouble
when you have routers, VPN's, gateways, and other complications on the
network. More importantly, perhaps, is that with UDP there is no
"connection". One node sends a request message to another node, that
node sends a reply message to the first node. With TCP/IP, the reply is
sent back up the same connection - with UDP, there is no connection. So
there is no way to tell if a reply is to the correct message, or the
correct connection, or even the correct node if you have routers
involved. It quickly becomes a reliability mess - it almost always
works, and sometimes fails depending on timing details between nodes.
Horrible.

So while we use UDP FINS between nodes directly on the same network
segment, we /always/ use TCP/IP for routed traffic, VPN traffic, or
anything else "complicated".

For Modbus, I have used Modbus/TCP on several systems, including
networks with large numbers of nodes. The overhead of TCP/IP
(acknowledge packets) usually has negligible cost, and it is not
difficult to handle the streaming nature of the protocol.

>
> 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.

That's a different matter - and I agree.

>
> 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).
>

Yes, within limits - it's important to have timeouts of some sort so
that you can re-synchronise in the case of lost characters. But the
timeouts should be large enough so that they are not an inconvenience
for normal handling.

Tauno Voipio

unread,
Mar 25, 2021, 10:34:04 AMMar 25
to
Right - and the protocol should make it easy to grab frame boundaries,
as PPP flags (0x7e, gullwing) do.

--

-TV

Grant Edwards

unread,
Mar 25, 2021, 10:49:44 AMMar 25
to
On 2021-03-25, Tauno Voipio <tauno....@notused.fi.invalid> wrote:
>>>
>>> The framing should be timing-independent, and just depending on special
>>> characters in the data stream, like PPP in HDLC-style framing
>>> (RFC 1662).
>>
>> Yes, within limits - it's important to have timeouts of some sort so
>> that you can re-synchronise in the case of lost characters. But the
>> timeouts should be large enough so that they are not an inconvenience
>> for normal handling.
>
>
> Right - and the protocol should make it easy to grab frame boundaries,
> as PPP flags (0x7e, gullwing) do.

And Modbus ASCII. ;)


upsid...@downunder.com

unread,
Mar 25, 2021, 12:43:54 PMMar 25
to
UDP (or raw Ethernet framing) can be handy in redundant systems, if
you do not care which physical redundant station responds. This is
true, especially if multicasts / broadcasts are used.

David Brown

unread,
Mar 26, 2021, 4:47:14 AMMar 26
to
Sure. I've used UDP for that kind of thing (like broadcasts for
identifying devices on a network). But it is a pain if you /do/ care
which node responds, because the response is a direct answer to a
request. You can always add tags or identifiers to your messages, and
perhaps extra messages for acknowledging that each end actually received
the telegram they were supposed to get - and suddenly you find you've
gone to a lot of effort to re-invent a poor man's TCP/IP.

The best solution would be for SCTP to become popular. I have only read
about it, not used it, but it seems to combine the best features of
TCP/IP with the best features of UDP, while avoiding the worst features
of both. Reliable transmission (with /your/ choice of reliability vs.
overhead tradeoffs), connections, datagrams. But Windows does not
support it natively, nor do most standard routers.

A.P.Richelieu

unread,
May 9, 2021, 7:24:34 AMMay 9
to
Atmel (now Microchip) ARM products has a serial port which supports
handling the RS-485 direction in hardware. It also has an interrupt
which is triggered after a programmable delay has occured without any
receied characters.


Uwe Bonnes

unread,
May 9, 2021, 8:01:07 AMMay 9
to
A.P.Richelieu <apric...@gmail.com> wrote:

> Atmel (now Microchip) ARM products has a serial port which supports
> handling the RS-485 direction in hardware. It also has an interrupt
> which is triggered after a programmable delay has occured without any
> receied characters.
>
Similar for recent STM32 U(s)arts.
--
Uwe Bonnes b...@elektron.ikp.physik.tu-darmstadt.de

Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 1623569 ------- Fax. 06151 1623305 ---------
(Phone also available during "mobile work")

pozz

unread,
May 10, 2021, 3:46:19 AMMay 10
to
I know SAM D family MCUs has a nice SERCOM peripheral with RS485
direction in hardware.

But my discussion was for Linux embedded, so MPUs (Cortex-A).

Reply all
Reply to author
Forward
0 new messages