-
Notifications
You must be signed in to change notification settings - Fork 4
Description
I wrote a sketch for my Opta that reads periodically from the register of a device connected via Modbus, then writes the value in a text file stored on a USB device. Unfortunately, I noticed that when using this library I am no longer able to read from the device using the Modbus channel, as ModbusRTUClient.read()
returns -1
which corresponds to an error.
I suspect this happens because on the Opta the Arduino_UnifiedStorage
library uses serial RS485
for debug purposes. I set debuggingModeEnabled
to false in my code, but nothing changed.
The only workaround I was able to find is to move the RS485
and Modbus initialization at the end of my setup()
code, however it is error prone and I find it odd that the Arduino_UnifiedStorage
would change my serial configuration when debugging is disabled. Furthermore, I could not find any documentation on this.
I managed to reproduce the issue multiple times, so I will attach the setup()
code below so you can see how moving the serial and Modbus init code changes the behavior of the ModbusRTUClient.read()
:
void setup()
{
// Here read fails.
// Output is: "Read value is: 4294967295", which is 0xFFFFFFFF error from ModbusRTUClient.read()
// modbusInit(38400, SERIAL_8N1);
// Disable debugging of storage operations.
Arduino_UnifiedStorage::debuggingModeEnabled = false;
// Init USBStorage object.
usbStorage = USBStorage();
// Here read fails.
// Output is: "Read value is: 4294967295", which is 0xFFFFFFFF error from ModbusRTUClient.read()
// modbusInit(38400, SERIAL_8N1);
// Register connect and disconnect callback.
usbStorage.onConnect(connectionCallback);
usbStorage.onDisconnect(disconnectionCallback);
// Here read works.
// Output is: "Read value is: 17968", which is expected
modbusInit(38400, SERIAL_8N1);
delay(5000);
}
For completeness, I will also attach the full code of the sketch so you can take a look and try to reproduce the issue if you want:
Click to expand
#include <ArduinoModbus.h>
#include <ArduinoRS485.h>
#include <Arduino_UnifiedStorage.h>
USBStorage usbStorage;
volatile bool usbAvailable = false;
int address = 20;
int reg = 9;
int numBytes = 1;
int readDelay = 5000;
void setup()
{
// Here read fails.
// Output is: "Read value is: 4294967295", which is 0xFFFFFFFF error from ModbusRTUClient.read()
// modbusInit(38400, SERIAL_8N1);
// Disable debugging of storage operations.
Arduino_UnifiedStorage::debuggingModeEnabled = false;
// Init USBStorage object.
usbStorage = USBStorage();
// Here read fails.
// Output is: "Read value is: 4294967295", which is 0xFFFFFFFF error from ModbusRTUClient.read()
// modbusInit(38400, SERIAL_8N1);
// Register connect and disconnect callback.
usbStorage.onConnect(connectionCallback);
usbStorage.onDisconnect(disconnectionCallback);
// Here read works.
// Output is: "Read value is: 17968", which is expected
modbusInit(38400, SERIAL_8N1);
delay(5000);
}
void loop()
{
if (usbAvailable)
{
digitalWrite(LED_USER, HIGH);
ModbusRTUClient.requestFrom(address, INPUT_REGISTERS, reg, numBytes);
uint32_t data = ModbusRTUClient.read();
String out = "Read value is: " + String(data) + "\n";
writeToFile(out);
digitalWrite(LED_D0, LOW);
digitalWrite(LED_D1, LOW);
digitalWrite(LED_D2, LOW);
digitalWrite(LED_D3, LOW);
digitalWrite(LED_USER, LOW);
}
unsigned long start = millis();
while (millis() < start + readDelay)
{
digitalWrite(LED_D0, LOW);
digitalWrite(LED_D1, LOW);
digitalWrite(LED_D2, LOW);
digitalWrite(LED_D3, LOW);
delay(500);
digitalWrite(LED_D0, HIGH);
digitalWrite(LED_D1, HIGH);
digitalWrite(LED_D2, HIGH);
digitalWrite(LED_D3, HIGH);
delay(500);
}
}
// Modbus operations.
void modbusInit(int baudrate, int serialConfig)
{
uint32_t preDelay, postDelay, timeout;
float bitDuration = 1.f / baudrate;
if (baudrate <= 19200)
{
preDelay = postDelay = bitDuration * 9.6f * 3.5f * 1e6;
timeout = 200;
}
else
{
preDelay = postDelay = 1750;
timeout = 1000;
}
RS485.setDelays(preDelay, postDelay);
ModbusRTUClient.setTimeout(timeout);
if (ModbusRTUClient.begin(baudrate, serialConfig) != 1)
{
while (1)
{
}
}
}
// Write operations.
void writeToFile(String data)
{
if (!usbStorage.isMounted())
{
digitalWrite(LED_D0, HIGH);
usbStorage.begin();
}
Folder rootDir = usbStorage.getRootFolder();
UFile outFile = rootDir.createFile("output.txt", FileMode::APPEND);
outFile.write(data);
digitalWrite(LED_D1, HIGH);
outFile.close();
digitalWrite(LED_D2, HIGH);
usbStorage.unmount();
digitalWrite(LED_D3, HIGH);
}
// // Callbacks.
void connectionCallback()
{
usbAvailable = true;
usbStorage.removeOnConnectCallback();
}
void disconnectionCallback()
{
usbAvailable = false;
usbStorage.onConnect(connectionCallback);
}
For the record, I tried patching the library by changing Boards.h
at line 24 like this:
#if defined(ARDUINO_OPTA)
#define HAS_USB
#define HAS_QSPI
#define USES_MBED_CORE
#define QSPI_STORAGE_SIZE 16384
// #define HAS_RS485
#endif
but the library would still change my serial configuration. If I can provide further details or assistance just let me know!