ArduinoModbus only prints fail messages (using MKR1010 board and MKR485 shield)

Greetings my fellow comrades,

This is my first ever post on any sort of forum / stack overflow style thing, so please let me know if I can update anything to be easier to read or understand.

Anyways: Working on a project with an Arduino MKR1010 and MKR CAN and MKR 485 shields to be the controller and communicate with some sensors and such. So far, the Modbus on the MKR 485 shield is providing to be more of a challenge--it's essentially a black box that doesn't work for me.

I followed the entire guide on the Getting Started for the Arduino MKR 485 shields. The guide works great for 485 (although, I had to lower the baud rate to 4800 like in this post), but when I then try to load the ArduinoModbus example files (Specifically: Examples → AdruinoModbus → RTU → ModbusRTUClientToggle & ModbusRTUServerLED) included below for convenience:
ModbusRTUServerLED:

/*
  Modbus RTU Server LED

  This sketch creates a Modbus RTU Server with a simulated coil.
  The value of the simulated coil is set on the LED

  Circuit:
   - MKR board
   - MKR 485 shield
     - ISO GND connected to GND of the Modbus RTU server
     - Y connected to A/Y of the Modbus RTU client
     - Z connected to B/Z of the Modbus RTU client
     - Jumper positions
       - FULL set to OFF
       - Z \/\/ Y set to OFF

  created 16 July 2018
  by Sandeep Mistry
*/

#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>

#define MOD_BAUD_RATE 4800

const int ledPin = LED_BUILTIN;

void setup() {
  Serial.begin(9600);

  Serial.println("Modbus RTU Server LED");

  // start the Modbus RTU server, with (slave) id 1
  if (!ModbusRTUServer.begin(1, MOD_BAUD_RATE)) {
    Serial.println("Failed to start Modbus RTU Server!");
    while (1);
  }

  // configure the LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // configure a single coil at address 0x00
  ModbusRTUServer.configureCoils(0x00, 1);
}

void loop() {
  // poll for Modbus RTU requests
  int packetReceived = ModbusRTUServer.poll();

  if(packetReceived) {
    // read the current value of the coil
    int coilValue = ModbusRTUServer.coilRead(0x00);
  
    if (coilValue) {
      // coil value set, turn LED on
      digitalWrite(ledPin, HIGH);
    } else {
      // coil value clear, turn LED off
      digitalWrite(ledPin, LOW);
    }
  }
}

ModbusRTUClientToggle:

/*
  Modbus RTU Client Toggle

  This sketch toggles the coil of a Modbus RTU server connected via RS485
  on and off every second.

  Circuit:
   - MKR board
   - MKR 485 shield
     - ISO GND connected to GND of the Modbus RTU server
     - Y connected to A/Y of the Modbus RTU server
     - Z connected to B/Z of the Modbus RTU server
     - Jumper positions
       - FULL set to OFF
       - Z \/\/ Y set to ON

  created 16 July 2018
  by Sandeep Mistry
*/

#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>

#define MOD_BAUD_RATE 4800

void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.println("Modbus RTU Client Toggle");

  // start the Modbus RTU client
  if (!ModbusRTUClient.begin(MOD_BAUD_RATE)) {
    Serial.println("Failed to start Modbus RTU Client!");
    while (1);
  }
}

void loop() {
  // for (slave) id 1: write the value of 0x01, to the coil at address 0x00 
  if (!ModbusRTUClient.coilWrite(1, 0x00, 0x01)) {
    Serial.print("Failed to write coil! ");
    Serial.println(ModbusRTUClient.lastError());
  }

  // wait for 1 second
  delay(1000);

  // for (slave) id 1: write the value of 0x00, to the coil at address 0x00 
  if (!ModbusRTUClient.coilWrite(1, 0x00, 0x00)) {
    Serial.print("Failed to write coil! ");
    Serial.println(ModbusRTUClient.lastError());
  }

  // wait for 1 second
  delay(1000);
}

However, I get the following errors:

Failed to write coil! Response not from requested slave
Failed to write coil! Invalid data
Failed to write coil! Invalid CRC
Failed to write coil! Connection timed out
Failed to write coil! Response not from requested slave
Failed to write coil! Invalid data
Failed to write coil! Invalid CRC
Failed to write coil! Connection timed out
Failed to write coil! Response not from requested slave

From my research, I haven't really found anything helpful and honestly just similar posts (like this one without an answer from a year ago).

I'm not really sure where to go from here. I tried switching to half-duplex instead of full-duplex, but that didn't really help the Modbus. I have been poking a lot into the ArduinoModbus library GitHub and the issues and PRs etc. They just give me something else to look into without much luck on actual answers.

Any answers or tips on where to look or how to debug would be much appreciated! (I have soldered on header pins and been trying to us a J-Link to debug as well as a cheaper logic analyzer (with Saleae Logic software) and an oscilloscope to dig deeper, but maybe I'm in too much over my head?)

Modbus is a pretty simple comms protocol so it shouldn't be too difficult to figure out what the issue is.

Can you post a diagram of how you have connected the 2 Modbus setups together.

When working with Modbus, a really useful tool to have is an RS485-USB dongle. They are really cheap and can allow your PC to listen to the RS485 bus and display the messages.

Is the MKR-CAN plugged in at the same time as the MKR-485? There may be conflicts between these 2 boards that stop one or both from working correctly.

Hi @mori4732stthomas ,

Welcome to the forum..

curious, having to lower the baud usually indicates bad connections or line termination..
but the really curious thing, why crank the baud back up when trying modbus, if anything lower it, try 2400 or 1200..
easiest way to debug this is using a usb 485 adapter for your pc..

did some modbus work a while back..

those errors are typically produced when data received is corrupted..

good luck.. ~q

Thanks, @qubits-us!

Whoops, you're right! I did have the baud rate at 4800, but it didn't save I guess when I opened the file to copy it into the forums. I'll fix that in the OP (Original Post).

I haven't tried setting the baud rate to anything lower than 4800. Just tried 2400 and 1200, but the result was still the same unfortunately.

I did just get a USB-485 adapter, but couldn't really find any free software to use with it. I tried some free trial software, but that wasn't too helpful either. Do you have any recommendations for that?

if you're running on windoze then you can give my test app a try..
it's in my git i linked too already..

~q

That's what I've read and been told, so that's why I feel like I must be missing something either super simple or just expecting something of the ArduinoModbus library that it doesn't allow it to use two Arduinos as a complete master/slave system.

Originally, I had everything wired up as shown in the official Arduino 485 tutorial like this:

However, I tried simplifying things by converting to half-duplex using page 9 of the datasheet of the chip on the MKR 485 shield. Here's a picture of that:


(DIP switch positions on both boards: A-B Termination Resistor is off, Full duplex is off, Y-Z Termination Resistor is on. ISOGND from one board to the GND of the second board. Y of one board connected to Y of second board via blue wire. Z of one board connected to Z of second board via yellow wire.)

No, not currently, but I have looked at the schematics of the MKR 485 shield and the MKR CAN shield to verify that before using the parts, but here's the wiring diagram I made for when I stack all three together:

But since I am just trying to start stuff up, I'm limiting the possible affecting factors and am not using the CAN shield at the same time as the as 485 shield (but the CAN shield seems to work just fine from the limited testing I've done).

I did just get a waveform USB-485 converter. What software would you recommend to use?

Ah, I will try that and get back to you. Thanks, @qubits-us!

ok, heads up, baud rate is hardcoded to 9600..
try it, if it doesn't fly, i'll add ability to change baud..
~q

If you are using half duplex on both the MKR485, then the connections are Y-Y and Z-Z.

You can also simplify during testing by ignoring Modbus altogether. Simply control RE & DE (pins A5 and A6) yourself to put the module into transmit mode. Then print a simple text message to the serial port. Your receiving board should leave the module in receive mode and just listen for any characters on the serial port.

Any serial port monitoring software that can display hexadecimal values will do. There are free Modbus programs out there for Windows PCs - sorry their names escape me for now.

Yep, that's what I have!

Gotcha. I'll try that here in a bit. However, I just tried doing the RS485 example code again and was able to get the baud rate at 9600 and 115200. Weird. But I'll take it!


Yes, that's what the RS485 library does that the ArduinoModbus library is dependent on.

Now that I think about it, I wonder if the slave Arduino sends a received message? I know the master has been sending the messages, but maybe the slave Arduino just doesn't respond? I'm going to look into that.

First weird thing that I found:


The default value for the Modbus config parameter is a 1 start, 8 data, no parity, and 1 stop bits for a total of 10 bits. However, according to the Modbus RTU specifications on page 12 of this Modbus manual, there should always be 11 bits per character. I'll probably add a pull request or issue or something to make a note of that in the ArduinoModbus repo.

So, hooking up my logic analyzer to just the TX and RX pins on the master MKR board, I'm getting a clean signal here:


What I don't get is that seems to be perfectly normal signal to me that shouldn't cause any errors. Yet, the terminal is still printing out errors:
image
According to my understanding, if there was an error in Modbus, the MSB would be set in the function code, so for a 0x05 function code, the error function code would be 0x85 instead.

I guess now I get to dig even deeper into the library code and maybe double-check that the UART buffers are sending and receiving the correct bytes too...

With errors like that, I would be looking at the RE & DE signals with your LA to see if there is an issue with when they switch the transceiver from RX to TX and back again. Just so I could be confident that the comms were not being corrupted by early or late switching of the transceiver.

scope looks valid..
seems like your client is not getting its data properly..
try this client, should print out each byte in response formatted to hex..

#include <ArduinoRS485.h>

const uint32_t TIMEOUT = 500UL;

const byte data[] = {0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x8C, 0x3A};

byte buf[80];

void setup() {
  Serial.begin(115200);
  RS485.begin(9600);
// Enable data reception
  RS485.receive();  
}

void loop() {
  sendTest();
  delay(10000);
}

void sendTest() {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  memset(buf,0,sizeof(buf));
  RS485.beginTransmission();
  delay(10);
  RS485.write(data, sizeof(data));
  RS485.flush();
  RS485.endTransmission();
  startTime = millis();
  while (millis() - startTime <= TIMEOUT) {
    if (RS485.available() && byteCount < sizeof(buf)) {
      buf[byteCount++] = RS485.read();
      Serial.print(buf[byteCount - 1],HEX);
      Serial.print(" ");
    }
  }
  Serial.println();
}

let's see what the client is getting..

good luck.. ~q

I hooked my logic analyzer to pins A5 and A6 on my MKR board per the MKR 485 schematic, and this is the scope with the just the sample code. It doesn't look quite right to me, but I am going to double-check the datasheet on that MAX chip...

Here's the scope for @qubits-us's code (FYI, I did change RS485.begin(9600); to RS485.begin(9600, SERIAL_8E1);):

With @qubits-us's custom client, the RX and TX pins seem to be getting the same signal initially before the response comes back from the slave Arduino...

Thanks again for the lightning fast replies, comrades! =D

received response twice, interesting..
what if we stop receiving as we transmit..
like this maybe..

void sendTest() {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  memset(buf,0,sizeof(buf));
  RS485.noReceive();    
  RS485.beginTransmission();
  delay(10);
  RS485.write(data, sizeof(data));
  RS485.flush();
  RS485.endTransmission();
  RS485.receive();  
  startTime = millis();
  while (millis() - startTime <= TIMEOUT) {
    if (RS485.available() && byteCount < sizeof(buf)) {
      buf[byteCount++] = RS485.read();
      Serial.print(buf[byteCount - 1],HEX);
      Serial.print(" ");
    }
  }
  Serial.println();
}

still twice??

~q

Yeah, I just looked into that and that's exactly what I did to fix it. Although, it doesn't look as pretty as the other scope.

Here is the new output now...
image

(This is how the ArduinoModbus library sends data, I think...)

same as us now, you're not getting it all..
wonder if it's a switch setting..
~q

Fixed this with:

void sendTest() {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  memset(buf,0,sizeof(buf));
  delay(10);
  RS485.noReceive();
  RS485.beginTransmission();
  RS485.write(data, sizeof(data));
  RS485.endTransmission();
  RS485.receive();
  RS485.flush();
  startTime = millis();
  while (millis() - startTime <= TIMEOUT) {
    if (RS485.available() && byteCount < sizeof(buf)) {
      buf[byteCount++] = RS485.read();
      Serial.print(buf[byteCount - 1],HEX);
      Serial.print(" ");
    }
  }
  Serial.println();
}

New Scope and Output:



(It randomly does and doesn't seem to get the bytes correct?...)

Are you referring to the dip switches on the MKR 485 board?

yep, you can see it now..
a valid response is just an echo..
now i'm thinking bad connection/cable..

~q