1

I've been having decoding errors on my Raspberry Pi 3B using pymodbus. Designed a board using MAX14854G as the RS-485 transceiver that is connected to the RPI3's UART pins (8 & 10). Currently testing it by using an RS-485 cable and a modbus simulator (Modbus Simulator --> RS485 cable --> RS-485 HAT board UART --> Raspberry Pi 3B).

Block Diagram:

enter image description here

Additional info: I'm using the full functionality of the UART (ttyAMA0) by swapping the ttyS0 and ttyAMA0 and by disabling the serial consoles and Bluetooth:

$ sudo systemctl disable serial-getty@ttyAMA0.service
$ sudo systemctl disable serial-getty@ttyS0.service
$ sudo systemctl disable serial-getty@serial0.service
$ sudo systemctl disable serial-getty@serial1.service

Here's my code + errors + log:

In [1]: import pymodbus
   ...: import serial
   ...: import serial.rs485
   ...: from pymodbus.pdu import ModbusRequest
   ...: from pymodbus.client.sync import ModbusSerialClient as ModbusClient
   ...: from pymodbus.transaction import ModbusRtuFramer
   ...: from pymodbus.register_read_message import ReadInputRegistersResponse
   ...: 
   ...: import logging
   ...: logging.basicConfig()
   ...: log = logging.getLogger()
   ...: log.setLevel(logging.DEBUG)

In [2]: msys = ModbusClient(method='rtu',port='/dev/ttyAMA0',stopbits=1,bytesize=8,parity='O',baudrate=9600,timeout=2)

In [3]: msys.inter_char_timeout = 0.05

In [4]: HR2 = msys.read_holding_registers(0,1,unit=1)
DEBUG:pymodbus.transaction:Current transaction state - IDLE
DEBUG:pymodbus.transaction:Running transaction 1
DEBUG:pymodbus.transaction:SEND: 0x1 0x3 0x0 0x0 0x0 0x1 0x84 0xa
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x1 0x3 0x0 0x0 0x0 0x1 0x84
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'

In [5]: HR2
Out[5]: 
pymodbus.exceptions.ModbusIOException('No Response received from the remote unit/Unable to decode response',
                                  3)

In [6]: print(HR2)
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response

In [7]: print(HR2.registers)
---------------------------------------------------------------------------
 AttributeError                            Traceback (most recent call last)
<ipython-input-7-02134bc1ab17> in <module>()
----> 1 print(HR2.registers)

AttributeError: 'ModbusIOException' object has no attribute 'registers'

Is this a decoding problem or is the Raspberry Pi 3B's UART not properly set? Before disabling the serial consoles, I couldn't even connect to the device. Based on the Modbus simulator, there's data traffic.

enter image description here

cknz
  • 21
  • 5

2 Answers2

1

The response is incorrect. For function 3 (which is read out words), the response should look like [SlaveNb] [FnNb] [NbBytes] [Data] [CRC16]. Your request is correct, you are asking for 1 word starting at address 0.

The response should be 01 03 02 XX XX YY YY where 02 is number of data bytes, XX XX is data, YY YY is CRC16. You should notice, your NbBytes field is 0 in response, but should be doubled number of words.

Btw, your response is looking like echo of request. Didn't you made a mistake in wiring? Probably you looped rx&tx?

grapes
  • 8,185
  • 1
  • 19
  • 31
  • Added an image, it's the data traffic from the modbus simulator. Is this similar to the error log? – cknz Dec 18 '18 at 07:46
  • Your screenshot looks nice. I see `002` for data length, it means response is correct (i didnt check the crc btw) – grapes Dec 18 '18 at 07:48
  • Added a block diagram. Tested the RS-485 part of the circuit and I can see the correct response. The correct data is not passing thru the Raspberry Pi. – cknz Dec 20 '18 at 13:01
0

I'm not sure I understand your setup but it seems to me you are trying to read from the RS485 bus with the drive enable signal from the Pi's side always high.

You need to toggle the drive enable low right after you finish sending your Modbus query for you to be able to read the response from the bus.

You need to implement either a hardware or software way to toggle it. Take a look here: background on RS485

EDIT: see this Q&As if you want to use libmodbus instead, including the GPIO line toggling you're missing from your code (it's not Python but you should be able to wrap it from the C library quite easily):

Solution with libmodbus

Marcos G.
  • 3,371
  • 2
  • 8
  • 16