Modbus giving crc errors

I am trying to get a simple modbus controller working, but it produces continuous crc errors. Looking at the log it seems like a lot of random data is read all the time.

Some things I have noticed and tried

  • The moment I disconnect the tx pin everything stops.
  • Also if I remove the modbus configuration from the yaml nothing is happening on the uart.
  • The moment I add only the modbus config, the noise starts again on the uart
  • If I load custom firmware on the same device it works perfectly so I know there is nothing wrong with the physical setup and wiring.

I am using an esp32 dev board with a max 485 module. I tried a different board with the same results and also working with custom firmware.

Here is my yaml


uart:
  id: uart_bus
  rx_pin: GPIO17 #GPIO20
  tx_pin: GPIO16 #GPIO21
  baud_rate: 9600
  debug:

modbus:
  flow_control_pin: GPIO32
  id: modbus1
  uart_id: uart_bus
  send_wait_time: 200ms

modbus_controller:
  - id: river_modbus
    address: 0x1   ## address of the Modbus slave device on the bus
    modbus_id: modbus1
    setup_priority: -10
    command_throttle: 100ms

Small snippet of my log files,

19:25:29][W][modbus:108]: Modbus CRC Check failed! 1030!=EA03
[19:25:29][W][modbus:108]: Modbus CRC Check failed! 47F4!=F4F4
[19:25:29][W][modbus:108]: Modbus CRC Check failed! 7577!=F4D0
[19:25:29][W][modbus:108]: Modbus CRC Check failed! 7577!=F0F4
[19:25:29][W][modbus:108]: Modbus CRC Check failed! AD76!=F4D4
[19:25:29][W][modbus:108]: Modbus CRC Check failed! B570!=F4FC
[19:25:29][D][uart_debug:114]: <<< 54:00:00:03:EA:F8:50:54:54:54:50:50:50:50:54:54:02:5A:FA:FE:FA:FA:FC:FC:FC:F0:FC:FE:FC:FC:FC:FC:FC:FC:FC:F4:C0:FC:FC:F4:F4:F4:F4:F0:D0:F4:FC:F4:F4:F4:F4:F4:F4:FC:F4:D4:D0:F4:F4:F4:F4:F4:F4:F4:D4:D4:F4:F4:F4:F0:F4:F4:F4:F4:F4:D4:FC:F4:F4:F4:F4:F4:F4:F4:F4:F4:D4:FC:F0:F4:F4:F4:F4:F4:F4:F4:F4:D0:F4:F4:F4:F4:F4:F0:F4:F4:D4:D4:F4:F4:FC:F4:FC:F4:50:54:54:54:54:55
[19:25:29][W][modbus:108]: Modbus CRC Check failed! F117!=F4F4
[19:25:29][W][modbus:108]: Modbus CRC Check failed! 7671!=F4F4
[19:25:29][W][modbus:108]: Modbus CRC Check failed! BC6E!=F4FC

Can you explain this better.

So instead of using ESPhome and HA. I have a small c program in PIO that uses SoftwareSerial to send the commands including crc, I load this onto the espboard and everything works as expected. I can switch the device(VFD) on and off. I can read registers. But when I load the Esphome firmware with the modbus config it goes crazy without having the mod_controller or any sensors/switches configured.

Here is some part of the code that I think might be of importance

#include <SoftwareSerial.h>

#include "Web.h"

// RS485 setup with ESp32

#define RE 19 // Connect RE terminal with 32 of ESP

#define DE 19 // Connect DE terminal with 33 of ESP

#define byte unsigned char

SoftwareSerial mod(20, 21); // RX=26 , TX =27

void setup()
{
 mod.begin(9600); // modbus configuration
}

Once the crc is appended to a buffer with the command, I set the DE,RE pins high(this use to be 2 different pins but since ESPhome only has one I just connected them together) and write it to mod serial. Set pins low and wait for the response.

Sounds correct. Did you control that you wired to your hardware serial2 pins on the actual board (16,17)?

The code above doesn’t include any modbus requests

Yes I use 16 and 17 on ESP32 and 20,21 on ESP-C3. The code has a webserver as well, I use that to make testing easier, you can enter a command in the browser that will send that over the serial and then display the return result.

But here is the writing and reading to the Serial

yte ModbusData(byte data[], int len, byte out[], bool &success, int &retryCnt)
{

  AddCheckSum(data, len);
  byte i;
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  int cnt = 0;
  if (mod.write(data, len+2) == len+2)
  {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);

    cnt = Read(&mod, out);
    
    Serial.printf("Received(%i) :", cnt);
    success = false; 
    if(cnt >2)
    {
      unsigned int chk = crc_chk_value(out, cnt-2);
      unsigned int* vl = (unsigned int*)&out[cnt-2]; // Suppose to work!!
      unsigned int chkR = out[cnt-1] << 8 |  out[cnt-2]; //Only solution, pointing an int to this buffer yield weird resutls
      success = (chk == chkR);
      Serial.printf("%i - Checksum Calculated: %u, Received: %u, Direct: %u\r\n", success, chk,chkR,*vl);
    }
   }
  if(!success && retryCnt>0)
  {
    Serial.println("Serail CRC failed Retrying...");// on retrycnt: %i. Retrying\r\n", retryCnt);
    retryCnt--;
    return ModbusData(data, len, out, success, retryCnt);
  }
  Serial.println("ModBusDone");
  return cnt;
}

Reading the return

int Read(SoftwareSerial *ser, byte data[], int max = 200, int initTimeout = 100, int betweenTimeout= 100) 
 {
   int cnt = 0;
   unsigned long st = millis();
   unsigned long lr = 0;
   bool hasTimeout = false;
   int fc =-1;
   int lb = -1;
   int tt = -1; 
  
   while(!hasTimeout && cnt< max)
   {
      if(cnt == 0)
      {
        if(millis()-st > initTimeout) 
        {
          hasTimeout = true;
          //Serial.printf("init timeout:%i\r\n", (millis()-st));
        }
      }
      else
      {
        if(millis() - lr > betweenTimeout ) 
        {
          hasTimeout = true;
          //Serial.printf("Between timeout:%i\r\n", (millis()-lr));
        }
      }
      
      if(hasTimeout) break;

      if(ser->available()>0)
      {
        if(fc == -1 )
        {
           fc = millis()-st;
        }
        else
        {
          int tlr = millis() - lr;
          if(tlr> lb) lb = tlr;
        }
        lr = millis();
         
        data[cnt] = ser->read();
        cnt++;
      }
   }
   tt = millis()-st;
   //tt = cnt > 0? lr - st: millis()-st;
   //Serial.printf("cnt: %i, fc: %i, st: %lu, lr: %lu, now:%lu\r\n", cnt,fc,st,lr, millis());
   Serial.printf("Read: Bytes: %i, Initial: %i, Between: %i, Total: %i \r\n", cnt, fc, lb, tt);
         
  return cnt;
 }

Reading the data took me some time to figure out how long to wait, which is clear from above code that I measured almost everything.
But it works well, no libraries used.
Command I will send through in the data parameter will be something like

01 06 20 00 00 01 // Switch on the VFD
01 06 20 00 00 05 // Stop the VFD
01 03 10 00 00 14 // Read all the stats(About 24 registers)

Is this modbus rtu or… ?

If yes, I would read this: slave address 1, read holding regs, first register 10, number of registers 0

Yes it is rtu,
1st byte is slave, 1byte the function 03 to read, 2 bytes the address(0x1000) and 2 bytes the amount to read which is 0x0014

Correct.
My mistake.

did you ever try with esphome component request, lijke this:

sensor:

  • platform: modbus_controller
    modbus_controller_id: river_modbus
    name: “xxx”
    register_type: holding
    address: 0x1001 ## address of the register inside the Modbus slave device
    value_type: U_WORD

to confirm that problem is not in your code?

I added that, but the thing is it starts misbehaving the moment the below part is in the yaml. So whether I add the sensor or not, it goes crazy.

modbus:
  flow_control_pin: GPIO32
  id: modbus1
  uart_id: uart_bus
  send_wait_time: 200ms

I don’t know your code overall right now, but I suggest you to test with a simple test setup, bare minimum. Sorry, I don’t know how to insert code to post…

uart:
  id: uart_bus
  rx_pin: GPIO17 #GPIO20
  tx_pin: GPIO16 #GPIO21
  baud_rate: 9600
  debug:

modbus:
  flow_control_pin: GPIO32
  id: modbus1
  uart_id: uart_bus
  

modbus_controller:
  - id: river_modbus
    address: 0x1   ## address of the Modbus slave device on the bus
    modbus_id: modbus1
    update_interval: 5s

sensor:

  - platform: modbus_controller
    modbus_controller_id: river_modbus
    name: “xxx”
    register_type: holding
    address: 0x1001 ## address of the register inside the Modbus slave device
    value_type: U_WORD

edit: I managed to insert code :grinning:…

It is exactly what I did. I used the above code, it produce the same result. Constant RX from UART with crc errors. Then I removed the sensor with the same result, I then removed the modbus_controller and still the same. When I removed the modbus everything went quiet. So the problems start with the modbus config.
So what I am trying to say is that I even have issues with less setup as in you sample above. To be precise it is with the modbus config where the problems start.

Sorry to hear.
I have done several setups and never had any issues with modbus component.
By the way, I don’t have anything related to HA on my setup. You?
Control your wiring for RE DE bridge? Try another flow control pin?

Yes this can be so easy to accomplish if only it works, I even tried it with a different board and different pins(Both which works perfectly fine with non esphome firmware) and joining the DE RE connections to one pin. All my stuff hooks up to home assistant and esphome(Maybe one or two switches run on sonoff via HA)

My other alternative is to create a complete external component and have full control via coding. But that is no simple task, documentation seems scarce and the only thing I have a bit knowledge about is now deprecated which is a custom component.

What can I say… Mine are working rock solid,
Esphome 8/2023 without Home assistant
Wroom32 dev board
$1 Max485 module with re/de
short wiring

3 modbus devices…

How do you use esphome without HA? Just like a webserver?

It’s actually quite complete system even without HA. Webserver, automations, HTTP api, MQTT. I have few of them working together. I don’t miss anything.
Underappreciated solution.

How does that work, you have like a central rpi or something where you control everything from? Is there any documentation on this?

No separate central units, just few esphomes. I have shared different tasks between them and they communicate between each other. All automations coded in. Webserver as user interface, everything in local network. External communication same way than with HA, MQTT or HTTP api.
Only thing it’s missing, is numeric input in webserver.
Esphome documentation is little bit messy, but so far I have found everything.

1 Like

After some painful struggling, I finally got an external component going. It really took some shouting between myself and chat GPT and a whole lot of patience.

Exactly the same problem. I manage to send a command to the VFD, but a lot of garbage comes back on the UART. The command I send does work, so I can switch on the VFD but the response is endless bytes of do not know what.
Then I replaced esphome’s UART with SoftwareSerail and all works as expected.

So I am not sure why UART works differently from something like SoftwareSerial but that is at the moment the problem with my comms.