Strange behavior with python serial and RS485

Hello

I see a strange behavior when I try to communicate with rs485 under python. Here is my test program:

import fcntl
import serial
import struct

print("pyserial version", serial.VERSION)

ser = serial.Serial(port="/dev/ttymxc0",
                      baudrate=4800,
                      parity=serial.PARITY_NONE,
                      bytesize=8,
                      stopbits=1,
                      timeout=5)

serial_rs485 = struct.pack('hhhhhhhh', 3, 0, 0, 0, 0, 0, 0, 0)
fcntl.ioctl(ser.fileno(), 0x542F, serial_rs485)  # enable rs485
ser.flush()

wrdata = b"0123401234\n"
print(">> %r" % wrdata)
n = ser.write(wrdata)
print("%d bytes written" % n)

bytesToRead = len(wrdata) * 2
answer = ser.read(bytesToRead)
print("%d bytes received" % len(answer))
print("<< %r" % answer)
ser.close()

The RS485 interface is connected but there is no response from the other side.
As long as I send less than 32 bytes I see my own echo. For example

pyserial version 3.5
>> b'012340123401234012340123401234\n'
31 bytes written
31 bytes received
<< b'012340123401234012340123401234\n'

If i send 32 bytes or more there is no echo, which is ok from my point of view:

pyserial version 3.5
>> b'0123401234012340123401234012340\n'
32 bytes written
0 bytes received
<< b''

If I connect a device on the remote side that sends back a response and increments each byte by the value 5, i see both the echo and the response from the remote side (if less than 32 bytes):

python3 test2.py 
pyserial version 3.5
>> b'012340123401234012340123401234\n'
31 bytes written
62 bytes received
<< b'012340123401234012340123401234\n567895678956789567895678956789\n'

If I send 32 or more bytes for this case, everything looks good:

python3 test2.py 
pyserial version 3.5
>> b'0123401234012340123401234012340\n'
32 bytes written
32 bytes received
<< b'5678956789567895678956789567895\n'

A similar c-program works.
Edit: This is not true, also with the c-program the “echo” exists.

Can anyone help?

Beste regards
René

sudo tdx-info 

Software summary
------------------------------------------------------------
Bootloader:               U-Boot
Kernel version:           5.15.129-6.5.0+git.6f8fd49366db #1-TorizonCore SMP PREEMPT Fri Dec 22 11:15:52 UTC 2023
Kernel command line:      root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 ostree=/ostree/boot.1/torizon/fe091cbe7b665ff6d9d5d618cb20c42c90c242fffeaceccf204eacd186b2f597/0
Distro name:              NAME="TorizonCore"
Distro version:           VERSION_ID=6.5.0-build.8
Distro variant:           VARIANT="Docker"
Hostname:                 v80labor
------------------------------------------------------------

Hardware info
------------------------------------------------------------
HW model:                 Toradex Verdin iMX8M Plus on Mallow Board
Toradex version:          0070 V1.1A
Serial number:            15128074
Processor arch:           aarch64
------------------------------------------------------------

Greetings @rema,

At the moment it’s hard to say with certainty what the exact issue here could be. But let me list some common issues that you could check on your side.

First of all, I see you only set a single ioctl to enable rs485, is that correct? We typically recommend a few ioctls to be enabled as documented here: UART (Linux) | Toradex Developer Center

Perhaps try enabling the recommended ioctls and try again.

Another thing to check is whether the rs485 connections you have are terminated with 120ohm resistors. Also I’ve heard that if the lines are too long this could cause an echo effect as well.

Finally there’s also a few threads I’ve found that reported similar issues, perhaps your issue is the same or similar to one of these:

Let me know if any of these helped or not.

Best Regards,
Jeremias

Thank you very much for answering Jeremias.

The provided link gave me the solution to the problem, namely that SER_RS485_RX_DURING_TX must be set.

I have now:

def enable_rs485(ser):
    # Set the following Bits:
    # + SER_RS485_ENABLED (0x01)
    # + SER_RS485_RTS_ON_SEND (0x02)
    # + SER_RS485_RX_DURING_TX (0x10)
    fd = ser.fileno()
    flags = 0x01 + 0x02 + 0x10;
    serial_rs485 = struct.pack('hhhhhhhh', flags, 0, 0, 0, 0, 0, 0, 0)
    ret = fcntl.ioctl(fd, 0x542F, serial_rs485)

And it works exactly as I expect.

Thank you very much and best regards
René

Perfect! Glad to hear it was a fairly simple solution.

Best Regards,
Jeremias