I've got this little .NET 6.0 program that sends a simple text string to the Arduino, that then processes this string and displays something on a TFT screen.
This all works when sending the string from a Windows computer - text is processed and shown correctly on the screen.
However, when this program is compiled and executed on the Linux machine (Ubuntu), the Arduino seems to simply crash and reboot.
I've done some logging code that saves some debug messages on a SD card, and I can tell that the code crashes exactly when the bytes are being read from Serial (no other log messages directly after that).
Note that this issue persists, regardless of the baudrate - I've tried everything between 9600 and 500000
Any insights?
Here's my arduino code for receiving data:
#include <arduino.h>
#include <SPI.h> // f.k. for Arduino-1.5.2
#define USE_SDFAT
#include <SdFat.h> // Use the SdFat library
#include <MCUFRIEND_kbv.h>
#include "config.h"
#include "RowData.h"
#if SPI_DRIVER_SELECT != 2
#error edit SdFatConfig.h . READ THE SKETCH INSTRUCTIONS
#endif
SoftSpiDriver<12, 11, 13> softSpi; //Bit-Bang on the Shield pins SDFat.h v2
SdFat SD;
SdFile myFile;
#define SD_CS SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)
MCUFRIEND_kbv tft;
const int bufferSize = 512;
char buffer[bufferSize];
RowData* rowData = 0;
String* rowBuffer = 0;
void setup()
{
if (!SD.begin(SD_CS)) SD.initErrorHalt();
uint16_t ID;
Serial.begin(baudRate);
ID = tft.readID();
log("Found TFT with ID:0x" + String(ID, HEX));
if (ID == 0x0D3D3) ID = 0x9481;
tft.begin(ID);
tft.setRotation(displayRotation); // Default: 0 (portrait)
tft.setTextWrap(false); // Default: True
tft.setTextColor(fontColor);
tft.setTextSize(fontScale); // Default: 1
tft.fillScreen(background);
log("Setup complete.");
}
void loop()
{
log("Waiting for input...");
while (!Serial.available());
int bytesRead = Serial.readBytes(buffer, bufferSize);
buffer[bytesRead] = '\0';
log("Received " + String(bytesRead, DEC) + " bytes");
tft.fillScreen(background);
.........
}
I'm not sure I know what you mean here...
I'm passing the maximum buffer size to Serial.readBytes so it won't cause a buffer overflow.
Serial.readBytes will read all available data up to 512 bytes, because the buffer can't hold anymore data than that. It then returns the size of the data read.
It is impossible to pass on the size of data to receive into Serial.readBytes as it is unknown at this point...
At least that's how I'm understanding it?
Also, bytesRead is never 512 when I manage to run it on the Windows platform - instead it matches perfectly the size of data sent through the serial.
You could be accessing memory which is out of bounds, bytesRead may be equal to bufferSize which is 512, but buffer[512] is not within the bounds (0..511):
int bytesRead = Serial.readBytes(buffer, bufferSize - 1);
buffer[bytesRead] = '\0';
I totally see your point here....
If bytesRead is 512 and I'm trying to set buffer[512] to \0 that will of course cause an index out of range, since the last slot in buffer is 511...
And also have in mind that a line ending in windows is "\r\n" whereas it is "\n" in Linux as suggested by @Whandall. When parsing the content received from .readBytes(), simply ignore '\r' and use '\n' as line ending.
The ones running this particular code are Uno and Mega 2560 - I do have Nano33 IoT but they are sporting a different microcontroller (SAMD21) and are not fully compatible with the TFT libraries I need for the TFT screen.
I have been running a similar sketch on the Nano 33 IoT with a LCD instead, and that works perfectly fine on Linux as well as Windows - the data is sent perfectly fine and displayed on the LCD....
Character in the Serial output buffer don't always get sent when a sketch crashes. I suggest adding "Serial.flush();" just after Serial.println() in log().
You should not use the "String" class / data type on AVR based MCU's like the Uno and Nano since that alone may cause crashes. Are you sure that the arduino crashes and reboots? Have you tried to blink the internal LED upon boot to be sure?
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
for (uint8_t i = 0; i < 3; i++)
{
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
...
}
Will blink 3 times when booted.
Or comment out that Serial.println() since there is nothing that receives it in the other end. The serial connection is terminated after written to in C#, so the arduino is essentially writing to a closed connection.
yes I am absolutely positive it reboots, as per the log functionality it writes to the log file whenever setup() is done being executed.
I can see in my logs that the entry "Setup complete." shows up again and again
I will add the blink functionality to make it more physically visible when it reboots instead of having to confirm by checking SD logs, just for comfort - thanks for the advice
Here's log output:
Setup complete.
Waiting for input...
Setup complete.
Waiting for input...
Setup complete.
Setup complete.
Waiting for input...
Setup complete.
Waiting for input...
Setup complete.
Something just came to mind; Is the Arduino not being reset when a serial connection to it is opened? Maybe the serial connections on Windoze are persistent and on Linux they are not, that would explain the behavior..