arduino-libraries / ArduinoModbus

244 stars 116 forks source link

RP2040: RX works, but always times out #111

Open pomplesiegel opened 1 year ago

pomplesiegel commented 1 year ago

Hello! Great library. I'm trying to get up and running on a RP2040 (raspberry pi pico) to make a very low cost solution using this library and RS485.

For hardware I am using:

I am able to successfully send commands from a host to the RP2040, but they always time out, even though the value is received by the node. This is the same whether we're talking about a holding register, coil, etc...

To simplify the debug process, below is MVP code to replicate the issue using this hardware:

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

RS485Class _RS485(Serial1, 0, 6, 1); //middle value (DE) is driver enable - need custom pinout

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

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

  // configure 1 coil at address 1
  ModbusRTUServer.configureCoils(1,1);
}

void loop() 
{
  // poll for Modbus RTU requests
  if (ModbusRTUServer.poll() )
  {
    Serial.println("Received request!"); 
    Serial.println( "Coil value: " + String(ModbusRTUServer.coilRead(1)) );
  }
}

When calling from a host (whether python or a GUI-based program like ModbusMechanic) the result is the same. My node can see the command from the host, but the response is never seen by the host. It always times out.

See resulting serial output from node below, when I send a 0, followed by a 1 for the coil value from a host to the node:

Received request!
Coil value: 0
Received request!
Coil value: 1

NOTE: to get the code to compile I had to change a couple default pin values within RS485.h, just because the RP2040 doesn't have an A5 or A6:

#ifndef RS485_DEFAULT_DE_PIN
#define RS485_DEFAULT_DE_PIN 6
#define RS485_DEFAULT_RE_PIN 1
#endif

I'm wondering if this could be an issue with the software serial on the RP2040's compatibility with the library? Looking forward to others' thoughts!

Thank you! Michael

pomplesiegel commented 1 year ago

In the meantime, what are supported chipsets to use the library with? I can compare the behavior between this and the RP2040.

Thank you!

pomplesiegel commented 1 year ago

Confirmed working on an Adafruit Grand Central M4 Express (SAMD51). This appears to be a RP2040 (raspberry pi pico) issue. Any ideas how to get it working on that particular platform, as it's quite common now?

pomplesiegel commented 1 year ago

Hi @facchinm and @aentinger, hope you're doing well! From your perspective, any idea on how much work it would take to get the library running correctly on the RP2040? Thank you very much!

aentinger commented 1 year ago

Mostly well, thank you :bow: I don't have any RS485 slave available, but I'll try and take a look into this, mkay?

pomplesiegel commented 1 year ago

@aentinger great, thank you very much!

martinez20m commented 1 year ago

Hi! I've started to use this library on raspberry pi pico with my custom board. There is half duplex rs485 and de pin and re pin is the same (gp18). In file pins_arduino.h I've defined another serial (Serial2) with my pins (gp16 and gp17) The problem I've encountered was "Checksum incorrect". I've looked on osciloscope that de/re pin change before serial transmit all data out. So far I've added 5ms delay after flush fcn in RS485.cpp in endTransmission() and it works well ;) Hope it helps

Edit: In RS485.h there is acctually appriopiate define for delay: RS485_DEFAULT_POST_DELAY and now I've change it to 5000 for 19200 baudrate

pomplesiegel commented 1 year ago

@martinez20m, very cool!! Thank you for the post. Would you mind sharing a gist or inline code of your actual changes?

aentinger commented 1 year ago

We'd also be taking a PR with both PIN definitions and other related changes :grin: :bow: .

pomplesiegel commented 1 year ago

@martinez20m, hope you're doing well! Would you mind sharing some code, since you have this working on a RP2040? No worries if it's just informal snippets.

Thank you!

martinez20m commented 1 year ago

Hi @pomplesiegel, thanks, quite good;) Here are my changes: https://gist.github.com/martinez20m/2597dd791224aa96e883bbdbef6921ef

aentinger commented 1 year ago

Hi @pomplesiegel ☕ 👋

Did those files help you with your problem? If you've got any changes to extend this libraries support for RP2040, please feel free to contribute a PR 🙇 .

pomplesiegel commented 1 year ago

Hi @martinez20m and @aentinger, thank you so much for your help! Indeed, these changes worked well. I found that the only changes I actually needed to make were within RS485.h. I'm not sure what would be the best approach to keep to the existing style here. The two changes which need to occur in order to have this running correctly on a Feather RP2040 or Raspi Pico are for

Thankfully the only changes necessary are within RS485.h! However, this is a library dependency, so I'm not sure what the best approach is here...

To address this:

  1. When using Serial2 the default pins on my RP2040 feather are TX = 0, RX = 1, and since it is nearby DE = 6. How should we best define this in RS485.h for compatibility and auto-detection? I'm currently just hard-coding the values in this file.
  2. I am currently using the settings below for pre-post delay and it's working well on my RP2040! I imagine this should be platform-dependent as well? Not sure why we require the extra delay on this platform, but it is indeed necessary.
    #define RS485_DEFAULT_PRE_DELAY 100
    #define RS485_DEFAULT_POST_DELAY 1000

Looking forward to your collective thoughts. Thank you again for finding the fix!! Thank you!