Serial communication

Timing of the serial communications

The Modbus RTU standard prescribes a silent period corresponding to 3.5 characters between each message, to be able fo figure out where one message ends and the next one starts.

The silent period after the message to the slave is the responsibility of the slave.

The silent period after the message from the slave was previously implemented in MinimalModbus by setting a generous timeout value, and let the serial read() function wait for timeout.

The character time corresponds to 11 bit times, according to https://www.automation.com/en-us/articles/2012-1/introduction-to-modbus

According to the Modbus RTU standard, the minimum silent period should be 1.75 ms regardless of the baud rate.

Baud rate Bit rate Bit time Character time 3.5 character times
2400 2400 bits/s 417 us 4.6 ms 16 ms
4800 4800 bits/s 208 us 2.3 ms 8.0 ms
9600 9600 bits/s 104 us 1.2 ms 4.0 ms
19200 19200 bits/s 52 us 573 us 2.0 ms
38400 38400 bits/s 26 us 286 us 1.75 ms (1.0 ms)
115200 115200 bit/s 8.7 us 95 us 1.75 ms (0.33 ms)

RS-485 introduction

Several nodes (instruments) can be connected to one RS485 bus. The bus consists of two lines, A and B, carrying a differential voltage. In both ends of the bus is a 120 Ohm termination resistor connected between line A and B. Most often a common ground line is connected between the nodes as well.

At idle, both line A and B rest at the same voltage (or almost the same voltage). When a logic 1 is transmitted, line A is pulled towards lower voltage and line B is pulled towards higher voltage. Note that the A/B naming is sometimes mixed up by some manufacturers.

Each node uses a transceiver chip, containing a transmitter (sender) and a receiver. Only one transmitter can be active on the bus simultaneously.

Pins on the RS485 bus side of the transceiver chip:

  • A: inverting line
  • B: non-inverting line
  • GND

Pins on the microcontroller side of the transceiver chip:

  • TX: Data to be transmitted
  • TXENABLE: For enabling/disabling the transmitter
  • RX: Received data
  • RXENABLE: For enabling/disabling the receiver

If the receiver is enabled simultaneusly with the transmitter, the sent data is echoed back to the microcontroller. This echo functionality is sometimes useful, but most often the TXENABLE and RXENABLE pins are connected in such a way that the receiver is disabled when the transmitter is active.

For detailed information, see https://en.wikipedia.org/wiki/RS-485.

Controlling the RS485 transmitter

Controlling the TXENABLE pin on the transceiver chip is the tricky part when it comes to RS485 communication. There are some options:

Using a USB-to-serial conversion chip that is capable of setting the TXENABLE pin properly
See for example the FTDI chip FT232RL, which has a separate output for this purpose (TXDEN in their terminology). The Sparkfun breakout board BOB-09822 combines this FTDI chip with a RS485 transceiver chip. The TXDEN output from the FTDI chip is high (+5 V) when the transmitter is to be activated. The FTDI chip calculates when the transmitter should be activated, so you do not have to do anything in your application software.
Using a RS232-to-RS485 converter capable of figuring out this by it self
This typically requires a microcontroller in the converter, and that you configure the baud rate, stop bits etc. This is a straight-forward and easy-to-use alternative, as you can use it together with a standard USB-to-RS232 cable and nothing needs to be done in your application software. One example of this type of converter is Westermo MDW-45, which I have been using with great success.
Using a converter where the TXENABLE pin is controlled by the TX pin, sometimes via some timer circuit
I am not conviced that it is a good idea to control the TXENABLE pin by the TX pin, as only one of the logic levels are actively driving the bus voltage. If using a timer circuit, the hardware needs to be adjusted to the baudrate.
Have the transmitter constantly enabled
Some users have been reporting on success for this strategy. The problem is that the master and slaves have their transmitters enabled simultaneously. I guess for certain situations (and being lucky with the transceiver chip) it might work. Note that you will receive your own transmitted message (local echo). See minimalmodbus.Instrument for echo detais.
Controlling a separate GPIO pin from kernelspace software on embedded Linux machines
See for example https://blog.savoirfairelinux.com/en-ca/2013/rs-485-for-beaglebone-a-quick-peek-at-the-omap-uart/ This is a very elegant solution, as the TXENABLE pin is controlled by the kernel driver and you don’t have to worry about it in your application program. Unfortunately this is not available for all boards, for example the standard distribution for Beaglebone (September 2014).
Controlling a separate GPIO pin from userspace software on embedded Linux machines
This will give large time delays, but might be acceptable for low speeds. It will probaby take 1-3 ms to turn off the transciver. For this to fit in the 3.5 character time before the slave starts transmitting, max speed can be 9600 bps.
Controlling the RTS pin in the RS232 interface (from userspace), and connecting it to the TXENABLE pin of the transceiver
This will give large time delays, but might be acceptable for low speeds.

Controlling the RS-485 transceiver from userspace

As described above, this should be avoided. Nevertheless, for low speeds (maybe up to 9600 bits/s) it might be useful.

This can be done from userspace, but will then lead to large time delays. I have tested this with a 3.3V FTDI USB-to-serial cable using pySerial on a Linux laptop. The cable has a RTS output, but no TXDEN output. Note that the RTS output is +3.3 V at idle, and 0 V when RTS is set to True. The delay time is around 1 ms, as measured with an oscilloscope. This corresponds to approx 100 bit times when running at 115200 bps, but this value also includes delays caused by the Python intepreter.

If you would like to use this for low speed, it can be implemented as in the contributed pull request: https://github.com/pyhys/minimalmodbus/pull/70 Then you should provide a callback that enables and disables the transmitter.