brainelectronics / micropython-modbus

MicroPython Modbus RTU Slave/Master and TCP Server/Slave library
GNU General Public License v3.0
104 stars 45 forks source link

Invalid CRC on reading multiple COILS #52

Closed brainelectronics closed 1 year ago

brainelectronics commented 1 year ago
    > @beyonlo yes, this is expected. As you set the coils of 125 to `[1,1,0]` but then request 16 coils (which are not available, only 3) the CRC is invalid. This again relates to #35 and will be solved after this PR

@brainelectronics unfortunately that error happen with coil_qty=3 as well. Details below:

Slave:

$ mpremote run rtu_client_example_with_callback.py 
Running ModBus version: 2.3.0-rc22.dev51
Custom callback, called on getting COILS at 125, currently: [1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1]
Custom callback, called on setting COILS at 125 to: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True]
Custom callback, called on getting COILS at 125, currently: [False]
Custom callback, called on getting COILS at 125, currently: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True, True]

Master:

>>> from umodbus.serial import Serial as ModbusRTUMaster
>>> rtu_pins = (17, 18)
>>> host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
>>> 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
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=2)
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
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=1)
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
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
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
>>> 
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
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
>>>

Originally posted by @beyonlo in https://github.com/brainelectronics/micropython-modbus/issues/51#issuecomment-1373013015

brainelectronics commented 1 year ago

@beyonlo could you try to debug the issue and print the modbus_pdu, response of read_coils in common.py as well as the finaly response of _uart_read() in serial.py

I again assume the flow control pin is turned of to early or to late

beyonlo commented 1 year ago

@beyonlo could you try to debug the issue and print the modbus_pdu, response of read_coils in common.py as well as the finaly response of _uart_read() in serial.py

@brainelectronics follow the tests as requested:

register_definitions = {
    "COILS": {
        "RESET_REGISTER_DATA_COIL": {
            "register": 42,
            "len": 1,
            "val": 0
        },
        "EXAMPLE_COIL": {
            "register": 123,
            "len": 16,
            "val": [1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1]
        }
    },
    "HREGS": {
        "EXAMPLE_HREG": {
            "register": 93,
            "len": 1,
            "val": 19
        }
    },
    "ISTS": {
        "EXAMPLE_ISTS": {
            "register": 67,
            "len": 1,
            "val": 0
        }
    },
    "IREGS": {
        "EXAMPLE_IREG": {
            "register": 10,
            "len": 1,
            "val": 60001
        }
    }
}

Slave RTU:

$ mpremote run rtu_client_example.py 
Running ModBus version: 2.3.1-rc26.dev53
Setting up registers ...
Register setup done

Master RTU:

$ mpremote 
Connected to MicroPython at /dev/ttyACM1
Use Ctrl-] to exit this shell

>>> from umodbus import version
>>> print('Running ModBus version: {}'.format(version.__version__))
Running ModBus version: 2.3.1-rc26.dev53
>>> from umodbus.serial import Serial as ModbusRTUMaster
>>> rtu_pins = (17, 18)
>>> host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=16)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xf8q\x9f\xd9')
response var from common.py file is: bytearray(b'\xf8q')
[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])
response var from serial.py file is: bytearray(b'\n\x0f\x00}\x00\x03\x84\xa9')
True
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xee')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/umodbus/common.py", line 137, in read_coils
  File "/lib/umodbus/serial.py", line 290, in _send_receive
  File "/lib/umodbus/serial.py", line 323, in _validate_resp_hdr
OSError: invalid response CRC
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=2)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x02'
response var from serial.py file is: bytearray(b'\n\x01\x01\x03\x13\xed')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/umodbus/common.py", line 137, in read_coils
  File "/lib/umodbus/serial.py", line 290, in _send_receive
  File "/lib/umodbus/serial.py", line 323, in _validate_resp_hdr
OSError: invalid response CRC
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=8)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x08'
response var from serial.py file is: bytearray(b'\n\x01\x01\xd8S\xf6')
response var from common.py file is: bytearray(b'\xd8')
[True, True, False, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=8)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x08'
response var from serial.py file is: bytearray(b'\n\x01\x01\xd8S\xf6')
response var from common.py file is: bytearray(b'\xd8')
[True, True, False, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=16)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xd8q\x86\x19')
response var from common.py file is: bytearray(b'\xd8q')
[True, True, False, True, True, False, False, False, False, True, True, True, False, False, False, True]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xae')
response var from common.py file is: bytearray(b'\x06')
[True, True, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xae')
response var from common.py file is: bytearray(b'\x06')
[True, True, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xae')
response var from common.py file is: bytearray(b'\x06')
[True, True, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=7)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x07'
response var from serial.py file is: bytearray(b'\n\x01\x01lS\xe1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/umodbus/common.py", line 137, in read_coils
  File "/lib/umodbus/serial.py", line 290, in _send_receive
  File "/lib/umodbus/serial.py", line 323, in _validate_resp_hdr
OSError: invalid response CRC
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=7)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x07'
response var from serial.py file is: bytearray(b'\n\x01\x01lS\x81')
response var from common.py file is: bytearray(b'l')
[True, True, False, True, True, False, False]
>>> 

I again assume the flow control pin is turned of to early or to late

This make sense, because as you can see in the reads_coils(), some times works and some times do not - for the same command.

beyonlo commented 1 year ago

Is there a relation between this bug and the #50?

beyonlo commented 1 year ago

Good afternoon @brainelectronics

Do you have any news (or a roadmap) to fix this issue?

Thank you in advance!

beyonlo commented 1 year ago

Hello @brainelectronics how are you? :smiley:

I would like to add 3 more information:

  1. In my application I need to read many COILS and many holding registers. This CRC problem do not happen just to read multiple COILS, but to read multiple holding registers has the same problem. So, sometimes works, sometimes do not works.
  2. That CRC problem happen also reading just one COIL and just ONE register.
  3. I'm using ESP32-S3, and I need to use a thread to do a specific task together the ModBus Slave. In this scenario those CRC errors is more intense, I mean, the problem happen with bigger frequency. Still works sometimes, but mostly do not works.

Unfortunately this CRC bug is a big problem for the application. Could you please give a attention for this issue?

Off topic: I saw that one user from Belgium talk about how to donate for this project. In the past I told you about that as well. I would be happy do donate for this project helping a bit more than just the tests and support, because this lib is really important for my project. And I think that this lib will be important for many many people that can to donate too and all that donate can help this project for always have back to community a better lib.

Thank you very much for your attention!

Here a example of RTU with thread just as test:

$ cat rtu_client_example_with_callback_with_thread.py 
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

"""
Main script

Do your stuff here, this file is similar to the loop() function on Arduino

Create a Modbus RTU client (slave) which can be requested for data or set with
specific values by a host device.

The RTU communication pins can be choosen freely. The register definitions of
the client as well as its connection settings like bus address and UART
communication speed can be defined by the user.
"""

import network, time, _thread

def testThread():
    c = 0
    c2 = 0
    delta = 0
    while True:
        start_time = time.ticks_ms()
        res = delta
        if res > 100:
            print(res, c)
        for i in range(120):
            c2 += i ** i
        c2 = 0
        c += 1
        #time.sleep_ms(100)
        end_time = time.ticks_ms()
        delta = time.ticks_diff(end_time, start_time)

_thread.start_new_thread(testThread, ())

from umodbus import version
print('Running ModBus version: {}'.format(version.__version__))

# import modbus client classes
from umodbus.serial import ModbusRTU

# ===============================================
# RTU Slave setup
# act as client, provide Modbus data via RTU to a host device
# ModbusRTU can get serial requests from a host device to provide/set data
rtu_pins = (17, 18)         # (TX, RX)
slave_addr = 10             # address on bus as client
baudrate = 115200
client = ModbusRTU(
    addr=slave_addr,        # address on bus
    baudrate=baudrate,      # optional, default 9600
    # data_bits=8,            # optional, default 8
    # stop_bits=1,            # optional, default 1
    # parity=None,            # optional, default None
    pins=rtu_pins,
    ctrl_pin=15)

def my_coil_set_cb(reg_type, address, val):
    print('Custom callback, called on setting {} at {} to: {}'.
          format(reg_type, address, val))

def my_coil_get_cb(reg_type, address, val):
    print('Custom callback, called on getting {} at {}, currently: {}'.
          format(reg_type, address, val))

def my_hregs_set_cb(reg_type, address, val):
    print('Custom callback, called on setting {} at {} to: {}'.
          format(reg_type, address, val))

def my_hregs_get_cb(reg_type, address, val):
    print('Custom callback, called on getting {} at {}, currently: {}'.
          format(reg_type, address, val))

# common slave register setup, to be used with the Master example above
register_definitions = {
    "COILS": {
        "EXAMPLE_COIL": {
            "register": 123,
            "len": 1,
            "val": 1
        },
        "COIL_SIGNALS": {
            "register": 125,
            "len": 16,
            "val": [1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1],
            "on_get_cb": my_coil_get_cb,
            "on_set_cb": my_coil_set_cb            
        }
    },
    "HREGS": {
        "EXAMPLE_HREG": {
            "register": 93,
            "len": 1,
            "val": 19
        },
        "HREG_VALUES": {
            "register": 130,
            "len": 33,
            "val": [34, 12, 14, 0, 10, 4, 2, 1345, 34, 8, 1100, 350, 456, 754, 324, 423, 530, 90, 320, 34, 244, 355, 606, 656, 640, 620, 677, 623, 234, 567, 34, 56, 68],
            "on_get_cb": my_hregs_get_cb,
            "on_set_cb": my_hregs_set_cb            
        }
    },
    "ISTS": {
        "EXAMPLE_ISTS": {
            "register": 67,
            "len": 1,
            "val": 0
        }
    },
    "IREGS": {
        "EXAMPLE_IREG": {
            "register": 10,
            "len": 2,
            "val": 60001
        }
    }
}

"""
# alternatively the register definitions can also be loaded from a JSON file
import json

with open('registers/example.json', 'r') as file:
    register_definitions = json.load(file)
"""

# use the defined values of each register type provided by register_definitions
client.setup_registers(registers=register_definitions)
# alternatively use dummy default values (True for bool regs, 999 otherwise)
# client.setup_registers(registers=register_definitions, use_default_vals=True)

while True:
    result = client.process()

print("Finished providing/accepting data as client")

Here reading multiple COILS:

$ cat read_coils.py 
import time
from umodbus import version
print('Running ModBus version: {}'.format(version.__version__))

from umodbus.serial import Serial as ModbusRTUMaster
rtu_pins = (17, 18)

address = 125
qty = 16
host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
print('COIL request test.')
print('Reading qty={} from address {}:'.format(qty, address))
values = host.read_coils(slave_addr=10, starting_addr=address, coil_qty=qty)
print('Result: {}'.format(values))

success = True
counter_requests = 100
fred_time = 30
print('Testing {} requests, each {}ms. Wait...'.format(counter_requests, fred_time))
start_time = time.ticks_ms()
for i in range(counter_requests):
    res = host.read_coils(slave_addr=10, starting_addr=address, coil_qty=qty)
    #print(res)
    time.sleep_ms(fred_time)
    if res != values:
        print('Error found')
        success = False
        break
end_time = time.ticks_ms()
delta_time = time.ticks_diff(end_time, start_time)
delta_time_div_counter_requests = delta_time/counter_requests
modbus_time_operation = delta_time_div_counter_requests - fred_time
if success:
    print('Done ModBus RTU (via RS485) requests without error in {}ms.'.format(delta_time))
    print('The total time was {}ms. So {} / {} requests is {}ms. So, {}ms - {}ms (freq_time delay) = {}ms. So the total time operation used by Modbus Protocol is {}ms'.format(delta_time, delta_time, counter_requests, delta_time_div_counter_requests, delta_time_div_counter_requests, fred_time, modbus_time_operation, modbus_time_operation))

And here reading multiple HOLDING REGISTERS:

$ cat read_holding_registers.py 
import time
from umodbus import version
print('Running ModBus version: {}'.format(version.__version__))

from umodbus.serial import Serial as ModbusRTUMaster
rtu_pins = (17, 18)

address = 130
qty = 33
host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
print('HOLDING REGISTER request test.')
print('Reading qty={} from address {}:'.format(qty, address))
values = host.read_holding_registers(slave_addr=10, starting_addr=address, register_qty=qty, signed=False)
print('Result: {}'.format(values))

success = True
counter_requests = 100
fred_time = 30
print('Testing {} requests, each {}ms. Wait...'.format(counter_requests, fred_time))
start_time = time.ticks_ms()
for i in range(counter_requests):
    res = host.read_holding_registers(slave_addr=10, starting_addr=address, register_qty=qty, signed=False)
    #print(res)
    time.sleep_ms(fred_time)
    if res != values:
        print('Error found')
        success = False
        break
end_time = time.ticks_ms()
delta_time = time.ticks_diff(end_time, start_time)
delta_time_div_counter_requests = delta_time/counter_requests
modbus_time_operation = delta_time_div_counter_requests - fred_time
if success:
    print('Done ModBus RTU (via RS485) requests without error in {}ms.'.format(delta_time))
    print('The total time was {}ms. So {} / {} requests is {}ms. So, {}ms - {}ms (freq_time delay) = {}ms. So the total time operation used by Modbus Protocol is {}ms'.format(delta_time, delta_time, counter_requests, delta_time_div_counter_requests, delta_time_div_counter_requests, fred_time, modbus_time_operation, modbus_time_operation))
beyonlo commented 1 year ago

About the thread together modbus lib I checked that error response (in addition to CRC error) is OSError: no data received from slave

$ mpremote run read_coils.py 
Running ModBus version: 2.3.1-rc26.dev53
COIL request test.
Reading qty=16 from address 125:
modbus_pdu var from common.py file is: b'\x01\x00}\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xf8q\x9f\xd9')
response var from common.py file is: bytearray(b'\xf8q')
Result: [True, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True]
Testing 100 requests, each 30ms. Wait...
modbus_pdu var from common.py file is: b'\x01\x00}\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xf8q\x9f\xd9')
response var from common.py file is: bytearray(b'\xf8q')
modbus_pdu var from common.py file is: b'\x01\x00}\x00\x10'
response var from serial.py file is: bytearray(b'')
Traceback (most recent call last):
  File "<stdin>", line 22, in <module>
  File "/lib/umodbus/common.py", line 137, in read_coils
  File "/lib/umodbus/serial.py", line 290, in _send_receive
  File "/lib/umodbus/serial.py", line 314, in _validate_resp_hdr
OSError: no data received from slave

Look that it read the first time OK, and after when start the loop to read show error OSError: no data received from slave. How can be solved that?

Thank you.

beyonlo commented 1 year ago

Hello @brainelectronics

Please, ignore that problem with ModBus together the thread, was just my programming mistake. I need to put a sleep time inside the thread and another sleep time on the while True of ModBus client.process()

I put a time.sleep_ms(10) in that two parts of source code and works fine:

Thread:

def testThread2():
    c = 0
    while True:
        print(c)
        time.sleep_ms(10)
        c += 1

ModBus rtu example modified to use thread:

while True:
    result = client.process()
    time.sleep_ms(10)

So, the bug is just still with CRC!

beyonlo commented 1 year ago

@brainelectronics some news for this issue? :smile:

brainelectronics commented 1 year ago

Hey @beyonlo not yet 😞 I've started into a new job and have other projects ongoing, but I'm still building up a real HW test with RS485 with and without flow control pin to fix this issue

beyonlo commented 1 year ago

Hello @brainelectronics

Hey @beyonlo not yet disappointed I've started into a new job and have other projects ongoing

Congratulations. I wish you the best in the new job and the projects :balloon:

but I'm still building up a real HW test with RS485 with and without flow control pin to fix this issue

Anyway, that is so far a good news!

Thank you so much!

beyonlo commented 1 year ago

Hello @brainelectronics how are doing?

I need a help from you, about this CRC errors :) Do you have any news/plans to fix that? It is very difficult to use RS-485 because that CRC errors. Many tests in other issues here (as the new PR #56 for async support and other tests) show always the same CRC errors in sync mode. We was thinking that PR #73 could fix or reduce the CRC errors, but unfortunately as I reported the tests there (#73) it do not help :cry:

If you can found a time to dedicate with this bug will be amazing :partying_face:

And, as you know, any tests that need to do in new code, I can do that!

Thank you in advanced!

brainelectronics commented 1 year ago

Hey @beyonlo may you can give release 2.3.5 a try again? Not sure whether your test in #75 did already cover these issues or not

beyonlo commented 1 year ago

@brainelectronics I tested again this issue and I confirm that errors do not happen anymore with 2.3.5 (that shows 0.0.0) :partying_face:

Follow the tests used in the first thread of this issue:

Slave RTU (sync):

$ mpremote run rtu_client_example_with_callback.py 
Running ModBus version: 0.0.0
Custom callback, called on getting COILS at 125, currently: [1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1]
Custom callback, called on setting COILS at 125 to: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True]
Custom callback, called on getting COILS at 125, currently: [False]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, False, False]

Master RTU (sync):

$ mpremote 
Connected to MicroPython at /dev/ttyACM1
Use Ctrl-] to exit this shell
>>> 
>>> from umodbus.serial import Serial as ModbusRTUMaster
>>> rtu_pins = (17, 18)
>>> host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
>>> 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)
[False, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=2)
[False, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=1)
[False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
[False, True, True, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
[False, True, True, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=18)
[False, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True, False, False]
>>> 
papercodeIN commented 6 months ago

@brainelectronics I tested again this issue and I confirm that errors do not happen anymore with 2.3.5 (that shows 0.0.0) 🥳

Follow the tests used in the first thread of this issue:

Slave RTU (sync):

$ mpremote run rtu_client_example_with_callback.py 
Running ModBus version: 0.0.0
Custom callback, called on getting COILS at 125, currently: [1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1]
Custom callback, called on setting COILS at 125 to: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True]
Custom callback, called on getting COILS at 125, currently: [False]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, False, False]

Master RTU (sync):

$ mpremote 
Connected to MicroPython at /dev/ttyACM1
Use Ctrl-] to exit this shell
>>> 
>>> from umodbus.serial import Serial as ModbusRTUMaster
>>> rtu_pins = (17, 18)
>>> host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
>>> 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)
[False, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=2)
[False, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=1)
[False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
[False, True, True, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
[False, True, True, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=18)
[False, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True, False, False]
>>> 

Can you share the connection diagram please?

papercodeIN commented 6 months ago
ctrl_pin

Hi Friend, Can you share connection diagram please ?