arduino-libraries / ArduinoModbus

258 stars 123 forks source link

Larger reads sometimes time out at slower baud rates on RP2040 #125

Open pomplesiegel opened 1 year ago

pomplesiegel commented 1 year ago

Hello! I am successfully using this library to implement a sensor device with 24 holding registers which can be read. This all works beautifully at higher baud rates. However, at 9600 baud it times out quite often (about 1/4 of requests).

To be clear, this sometimes times out when reading 24 registers in a single request. However it functions fine at higher baud rates such as 115200.

Device: Adafruit RP2040 Feather Baud: 9600

MVP device code to replicate issue:

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

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

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

  // configure 24 registers, starting at address 1
  ModbusRTUServer.configureHoldingRegisters(1,24); 
}

void loop() 
{
  // poll for Modbus RTU requests
  if (ModbusRTUServer.poll() )
  {
    Serial.println("Received request!"); 
  }
}

RS485.h timing mod for things to work on RP2040:

#define RS485_DEFAULT_PRE_DELAY 100
#define RS485_DEFAULT_POST_DELAY 5000

BTW: I can replicate the issue when reading fewer registers at once, but it is much easier to replicate when performing larger requests (reading multiple registers).

Looking forward to your thoughts! Thank you, Michael

pomplesiegel commented 1 year ago

Hi @facchinm and @aentinger, I hope you're both doing well! Have either of you seen this in your usage with the library at slower baud rates?

aentinger commented 1 year ago

Unfortunately not using this library at all. Sounds like a timeout?

pomplesiegel commented 1 year ago

Hi @aentinger, thanks for the message! Yes, indeed it's a timeout, but it's not clear why this is happening about 1/4 of the time. The device is available and just sitting there, but there is some issue preventing it from seeing all of the modbus requests when running at certain baud rates.

Any ideas? Thank you!

aentinger commented 1 year ago

Nope, sorry, no ideas. I've looked for obvious timeouts in the code myself, but didn't see any. If you find a bug, please consider sending a PR to fix it 🙏 .

pomplesiegel commented 1 year ago

OK, I'll keep looking into it! Is anyone else able to quickly test / replicate the MVP code above? I think that may help clarify what is going on causing this issue. Thank you!

pomplesiegel commented 1 year ago

Anyone else experiencing timeouts on at these lower baud rates on other hardware? RP2040 it is definitely happening.

pomplesiegel commented 12 months ago

Just checked and with the latest release this (MVP example code above) is still easily replicable with baud rates 9600 and 19200. Anyone else seeing this on RP2040 or other hardware?

@martinez20m your assistance as so helpful on the last issue! Would you be open to testing this on your device to see if you replicate this as well?

pomplesiegel commented 11 months ago

Just tested and I'm seeing many other time-out issues at various baud rates on boards such as the ATSAMD21G18 (Adafruit Metro Express). Anyone else seeing this too?

pomplesiegel commented 11 months ago

@per1234, would you be open to testing this on your side? I have found it is quite easy to replicate on the two sets of hardware I have here, and this would represent a large issue for many people using the library.

pomplesiegel commented 11 months ago

OK! I have found a solution which allows stable operation on the RP2040:

I exposed the libmodbus's flush command via https://github.com/arduino-libraries/ArduinoModbus/pull/133 and call this after each poll, so loop() now looks like:

void loop() 
{
  // poll for Modbus RTU requests
  if (ModbusRTUServer.poll() )
  {
    Serial.println("Received request!"); 
    ModbusRTUServer.flush(); //necessary at lower baud rates
  }
}

Finally, the RS485.h timing needs to be

#define RS485_DEFAULT_PRE_DELAY 100
#define RS485_DEFAULT_POST_DELAY 10000

Both of these changes are necessary for stable operation with large reads. On my side things are now running stable between 9600 and 115200 baud, even with reads as large as 100 bytes.

I'm not sure what the end goal should be here in terms of integrated platform support, but FYI between my PR and the timing changes above this is finally working for me.