Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with RS485 direction control #68

Open
ondrej1024 opened this issue Mar 30, 2023 · 12 comments
Open

Problem with RS485 direction control #68

ondrej1024 opened this issue Mar 30, 2023 · 12 comments
Labels
bug Something isn't working question Further information is requested

Comments

@ondrej1024
Copy link

Description

I am using a ST3485 RS485 transceiver with the DE/RE pins shortened and connected to a GPIO pin.

Running as Modbus master, the request is received correctly by the slave but the response is not received and umodbus throws an error (see below).

I suspect some timing issue with the transceiver switching to read mode but can't quite find the root cause of this.

Any ideas?

Reproduction steps

Initialization:

mbm0 = ModbusRTUMaster(pins=(Pin(GP_UART0_TX), Pin(GP_UART0_RX)),ctrl_pin=GP_UART0_DC, uart_id=0)

Send request to slave

mbm0.read_holding_registers(42,1,1)

MicroPython version

MicroPython v1.19.1-994-ga4672149b

MicroPython board

Raspberry Pico

MicroPython Modbus version

v2.3.4

Relevant log output

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/umodbus/common.py", line 199, in read_holding_registers
  File "/lib/umodbus/serial.py", line 287, in _send_receive
  File "/lib/umodbus/serial.py", line 177, in _uart_read
  File "/lib/umodbus/serial.py", line 149, in _exit_read
IndexError: bytearray index out of range

User code

No response

Additional informations

No response

@ondrej1024
Copy link
Author

I did some more testing and found that when reading the response I always get first a single byte 0x00 and after that the actual response frame. The single byte causes the reported IndexError in _exit_read

So I did a simple modification throwing away always the first single byte of the response. This basically works. However quite often the response frame is not received completely, leading to CRC error.

So I was wondering if software direction control via IO pin has actually been tested and if it is reliable?

@kommando828
Copy link

Have you fitted a 120 ohm resistor on the line connection on the slave. I run RS485 over wifi and all my slaves need a 120 ohm resistor as they all think they are the last one on the cable.

@ondrej1024
Copy link
Author

I have a regular RS485 bus with 120 Ohm termination. The bus itself works fine. When using HW direction control I don't get any errors.

@beyonlo
Copy link

beyonlo commented Mar 30, 2023

@ondrej1024 Hello!

So I was wondering if software direction control via IO pin has actually been tested and if it is reliable?

I'm using this lib for RS-485 using the MAX485CSA chip, that use a control pin, like do you are using, and are working without errors mostly of time - here you can see one of my tests. I wrote mostly of time because sometimes happen Invalid CRC reading COILS WHEN first I write multiple COILS and after that I try to read the COILS again - here you can see this problem happening. Bellow a example of error:

>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=16)
[True, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True]
>>> host.write_multiple_coils(slave_addr=10, starting_address=125, output_values=[1,1,0])
True
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/umodbus/common.py", line 136, in read_coils
  File "/lib/umodbus/serial.py", line 289, in _send_receive
  File "/lib/umodbus/serial.py", line 322, in _validate_resp_hdr
OSError: invalid response CRC

Look that first read_coils() works, but after write_multiple_coils() the read_coils() stop to works, or sometimes works and sometimes not works

I don't know if your problem is the same of that, or if your problem has something to do with this problem, but the @brainelectronics opened an issue for that #52

@ondrej1024
Copy link
Author

I use only reading/writing holding registers, no coils.

Anyway I found that I have some issue with the ground reference of my circuitry. With a proper reference I always get a valid response from the slave, so SW direction control is working fine.

However I still see an initial 0x00 byte in the RX buffer immediately after sending the request. So I have to take care of this, otherwise I get a CRC error. I don't have an explanation for this.

@brainelectronics
Copy link
Owner

Hey @ondrej1024 may you can give release 2.3.5 a try again? MicroPython v1.20.0 is recommended as it introduces the flush function for UART, implemented in #75, for older MicroPython firmware versions the timing has been improved as well. In case the reported issue was based on a HW problem you might close this issue

@brainelectronics brainelectronics added bug Something isn't working question Further information is requested labels Jul 2, 2023
@ondrej1024
Copy link
Author

Yes, I will test this the next days and report back.

@ondrej1024
Copy link
Author

I have tested release 2.3.5 now with MP 1.20.0 but I still see the same issue. I get CRC error.

This is the code I use:

from machine import Pin
from umodbus.serial import Serial as ModbusRTUMaster

GP_UART0_TX =  0  # RS485 DI
GP_UART0_RX =  1  # RS485 RO
GP_UART0_DC =  2  # RS485 DC

mbm0 = ModbusRTUMaster(pins=(Pin(GP_UART0_TX), Pin(GP_UART0_RX)), ctrl_pin=GP_UART0_DC, uart_id=0)
mbm0.read_holding_registers(1,1,1)

And this is the error message:

Traceback (most recent call last):
  File "<stdin>", line 10, in <module>
  File "/lib/umodbus/common.py", line 199, in read_holding_registers
  File "/lib/umodbus/serial.py", line 314, in _send_receive
  File "/lib/umodbus/serial.py", line 347, in _validate_resp_hdr
OSError: invalid response CRC

The above code works fine with release 2.3.4 and this patched version of serial.py:
serial.txt

@brainelectronics
Copy link
Owner

Hi again @ondrej1024 may you can give release 2.3.7 another try again?
I've added you proposed wait time after the flush.
In case the reported issue was based on a HW problem you might close this issue

@icchalmers
Copy link

icchalmers commented Nov 7, 2023

Just wanted to say this is likely a hardware issue and add a potential fix for anyone else that ends up here from searching.

I use the same SP3485. The datasheet says that if ~RE and DE are both pulled high (as they are when using a common GPIO to enable transmission) then the RO output should be High-Z. On my shoddy breadboard setup, RO was actually getting pulled low. This looks like a start bit on the UART RX, resulting in the reception of a 0x00 character.

Adding a pullup on RO is a hardware fix. If you need a software bodge fix, clear any bytes received before the peripheral should have had a chance to respond.

while self._uart.any() > 0:
    # print('ditching bad rx')
    self._uart.read()

For example, somewhere in the _send(...) method around here (or just right before/after if you don't care too much about affecting the timings):

if self._has_uart_flush:
self._uart.flush()
time.sleep_us(self._t1char)
else:
sleep_time_us = (
self._t1char * len(modbus_adu) - # total frame time in us
time.ticks_diff(send_finish_time, send_start_time) +
100 # only required at baudrates above 57600, but hey 100us
)
time.sleep_us(sleep_time_us)

@icchalmers
Copy link

Comparison of without pullup resistor on RO vs with pullup, showing what looks like a failed RX to the UART as it is missing the stop bit. Top orange trace is RO (UART RX on the Pico I'm using).

Without:
without_pullup

With:
with_pullup

With the pullup in place, the expected packets are received and CRCs pass etc.

@ondrej1024
Copy link
Author

I agree, also my problem seems to be a hardware issue. There is no pullup on the RO line here and, although I haven't tried to solder one, I am pretty sure it would fix it. So I guess we can close this issue now.

hmaerki pushed a commit to hmaerki/fork_micropython-modbus that referenced this issue Dec 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants