emelianov / modbus-esp8266

Most complete Modbus library for Arduino. A library that allows your Arduino board to communicate via Modbus protocol, acting as a master, slave or both. Supports network transport (Modbus TCP) and Serial line/RS-485 (Modbus RTU). Supports Modbus TCP Security for ESP8266/ESP32.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problem with package drop on esp32

ihitsov opened this issue · comments

Dear all,

I am having a problem with what seems like a package drop problem with this library on ESP32 in RTU slave example. The hardware setup is:
Node red is modbus master, requests the read of IRegs via modbus TCP
There is a modbus TCP>RTU gateway from CDEbyte
ESP32 is connected to the RTU pins on the gateway
Now the problem is that it seems like its dropping some packets (20-30% at 9600 baudrate) and when this happens the gateway reconnects.

I can daisy chain a few of the CDEByte gateways and they work nicely without any packet loss

I tried 3 different ttl2modbus adapter boards, two without de/re pin and one with. The behavior is identical with all 3 boards.
I tried putting 120 ohm resistors between DataA and DataB on the gateway and the modbus adapter, no success. I think my code is nothing special, but even with the base example I still have problems. I would appreciate any help or directions with this! I am not sure if its a hardware or software issue, not sure how to debug this.

Best regards
Ivaylo

These are the 3 boards I tried:
image
image
image

Here is the modbus TCP/RTU gateway from CDEByte:
image

And here is the code.
`#include <ModbusRTU.h>
//#include <SoftwareSerial.h>

#define SLAVE_ID 3
#define INPUT_COUNT 4
ModbusRTU mb;

//SoftwareSerial swSer1(4, 13); // Define hardware connections

volatile unsigned long pulseCount[INPUT_COUNT] = {0};
unsigned long frequencies[INPUT_COUNT] = {0}; // Store frequencies here
unsigned long previousMicros = 0; // Changed from previousMillis to previousMicros
const long interval = 1000000; // Measurement interval in microseconds (1 second)
const int inputPins[INPUT_COUNT] = {19, 21, 22, 23}; // Note: Pins 21 and 22 are common I2C pins

// Flag to indicate that frequencies need to be updated
volatile bool updateRequired = false;

void IRAM_ATTR handleInterrupt0() { pulseCount[0]++; updateRequired = true; }
void IRAM_ATTR handleInterrupt1() { pulseCount[1]++; updateRequired = true; }
void IRAM_ATTR handleInterrupt2() { pulseCount[2]++; updateRequired = true; }
void IRAM_ATTR handleInterrupt3() { pulseCount[3]++; updateRequired = true; }

// Array of function pointers for ISRs
void (*handleInterrupts[INPUT_COUNT])() = {handleInterrupt0, handleInterrupt1, handleInterrupt2, handleInterrupt3};

void setupModbus() {
for (int i = 0; i < INPUT_COUNT; ++i) {
mb.addIreg(0x0000 + i);
}
Serial.println("Modbus configured.");
}

void setupPins() {
for (int i = 0; i < INPUT_COUNT; ++i) {
pinMode(inputPins[i], INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(inputPins[i]), handleInterrupts[i], RISING);
}
Serial.println("Pins configured for interrupts.");
}

void calculateAndResetFrequencies() {
noInterrupts(); // Disable interrupts to safely read and reset shared variables
for (int i = 0; i < INPUT_COUNT; ++i) {
// Adjusted calculation for microsecond interval
frequencies[i] = pulseCount[i] * 1000000 / interval; // Use 1000000 to convert from counts per microsecond to Hz
mb.Ireg(0x0000 + i, frequencies[i]);
pulseCount[i] = 0; // Reset pulse count after calculating frequency
}
interrupts(); // Re-enable interrupts
updateRequired = false; // Reset update flag
}

void setup() {
// swSer1.begin(9600, SWSERIAL_8N1);
Serial.begin(9600);
Serial2.begin(1200, SERIAL_8N1);
mb.begin(&Serial2); // Assuming pin 26 is DE/RE control pin
mb.slave(SLAVE_ID);

while (!Serial); // Wait for serial port to connect
setupModbus();
setupPins();

}

void loop() {

unsigned long currentMicros = micros(); // Changed from millis() to micros()
if (updateRequired || (currentMicros - previousMicros >= interval)) {
    previousMicros = currentMicros; // Update the timing variable
    calculateAndResetFrequencies(); // Calculate frequencies
    // Now print the frequencies in the main loop, outside of critical section
    for (int i = 0; i < INPUT_COUNT; ++i) {
        Serial.print("Pin ");
        Serial.print(inputPins[i]);
        Serial.print(" Frequency: ");
        Serial.print(frequencies[i]);
        Serial.println(" Hz");
    }
}

yield();
mb.task();
yield();}`

Does anyone have an idea what could cause this? I am running out of things to try. Any hints are welcome!

The code above uses a lot of interrupts, but it drops packages even with the most basic examples. Is this library working well with ESP32? I always use the hardware serial 2 of ESP32 which should work without any limitations. I tried software serial as well, this dropped packages too. Thanks in advance!

Best regards
Ivaylo

Try to replace yield with delay:

  mb.task();
  delay(50);
}

If it doesn't help could you provide some expat data to make me able to simulate the issue in my lab?