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.
Other
534 stars 190 forks source link

Problem with package drop on esp32 #341

Closed ihitsov closed 3 days ago

ihitsov commented 9 months ago

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 //#include

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();}`
ihitsov commented 8 months ago

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

emelianov commented 7 months ago

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?

ihitsov commented 6 months ago

Thank you very much for replying! I investigated this a lot and at the end it seems to be coming from my Node Red modbus library. Thanks again!