Troubleshooting Cayenne + SD on Arduino

Hello folks,
I’ve been working on an Arduino Mega project with Ethernet Shield, an RTC, a little buzzer, a graphic LCD and a configurable number of sensors that measures temperature, pressure, humidity etc.
I publish the data on Cayenne’s Dashboard and also store the measurements on SD as backup.
During the refinement of the code, I started having errors on writing the data to SD. This was driving me nuts as I could not figure out where the problem was.
SD writing worked fine on setup{} but on loop{} it didn’t.
Making the story short, I finally found that if I comment //Cayenne.run() within loop{} the logging on SD works fine. If I enable the line, SD writing gives me writing error then stops or sometimes during debugging, it doesn’t stops or give errors, but logging does not happen. Again, when disabling Cayenne.run line, logging works.

The code is getting big but at compile, I still have 3879 bytes for local storage.
I thought that I might not have enough memory but using freemem I had at least 2K on critical points of the code so I believe I have ram.

My loop looks like this:
void loop() {
tm = now();
if ((tm - tmPreviousTimeText) > 1) {
updateTimeText(); // gets current time and stores it in decreasing CSV text from year to second like “2017/04/10,22:14:46”
tmPreviousTimeText = tm;
}
if ((tm - tmPreviousLCD) > 1 ) {
prindSnsrsLCD(); // prints sensors result to LCD.
tmPreviousLCD = tm;
}
if ((tm - tmPreviousTakeReading) > smplFreq) {
takeReading(); // gets data from sensors
writeResultsToSD(); // writes data do SD usinf sdFAT.h library
tmPreviousTakeReading = tm;
}
if ((tm - tmPreviousOscilateLED) > 1) {
iAmAlive = !iAmAlive;
digitalWrite(ledPin, iAmAlive) ; just a led blink to indicate the system is working.
tmPreviousOscilateLED = tm;
}
Cayenne.run();
}

I disabled each of the possible routines above simplifying and reducing the code except of course writeResultsToSD() and Cayenne.run() to see if they work together but they don’t like each other :slight_smile:

with Cayenne enabled, data is properly sent to Dashboard but SD doesn’t work
with Cayenne disabled, SD writing works.
All measurements are sent to Cayenne using Virtual ports.

A sample code for a Virtual port is:
CAYENNE_OUT(V1) {
byte i = 0;
optional call method
if (sensorUnit[i] == F(" C “)) {
Cayenne.virtualWrite(V1, sensorMeasureVal[i], TEMPERATURE, CELSIUS);
} else if (sensorUnit[i] == F(” % “)) {
Cayenne.virtualWrite(V1, sensorMeasureVal[i], HUMIDITY, PERCENT);
} else if (sensorUnit[i] == F(” hPa")) {
Cayenne.hectoPascalWrite(V1, sensorMeasureVal[i]);
}
}

I’d love to hear suggestions, hints, tips of where a bug could be?
If I get this solved, I will certainly share.

Thanks
Carlos.

It’s an interesting problem, I’m curious what the solution will be. What is in writeResultsToSD();?

Hi Adam,
writeResults() is the routine that stores the collected data from last sensors read to the SD.
It uses sdFat.h library.

It’s a quite short routine that builds the name of the file with the date and the sensor number and stores the result as csv to each sensor’s file.
It calls appendLog( fileName, logString); passing the file name and the csv data.
I am posting both below.

//**************************************
//*** Write last results to SD ***
//*** for all enabled sensosr ***
//**************************************
void writeResultsToSD() {
Serial.println(F(“\n → SD”));
String fileName;
for (byte i = 0; i < numSensors; i++) {
if (sensorEnabled[i]) {
switch (sensor[i][0]) {
case 1:
fileName = ‘s’;
break;
case 2:
fileName = ‘i’;
break;
}
fileName += String(sensor[i][1]) + String(sensor[i][2] + 1) + dateDash.substring(1, dateDash.length()) + F(“.log”);
logString = timeText + F(“,”);
logString += sensorMeasureVal[i];
char fileNameChar[14];
fileName.toCharArray(fileNameChar, 13);
appendLog( fileNameChar, logString);
}
}
// Serial.println(F(“.”));
}

//************************************************************
//*** Write log file ***
//*** pass the log file name and the log line to be stored ***
//************************************************************
void appendLog(char logFile[14], String text ) {
// set date time callback function
SdFile::dateTimeCallback(dateTime);
tm = now();
// sprintf(timestamp, “%02d:%02d:%02d %2d/%2d/%2d \n”, hour™, minute™, second™, month™, day™, year™ - 2000);
DEBUG_PRINTS(“'”); DEBUG_PRINT(text);
DEBUG_PRINTS(“’ ----> “);
// dataFile = sdAppend.open(logFile, FILE_WRITE);
if (!sdAppend.open(logFile, FILE_WRITE)) {
// if (!sdAppend.open(logFile, O_RDWR | O_CREAT | O_AT_END)){
// if (!sdAppend.open(logFile, O_CREAT | O_WRITE | O_AT_END | O_APPEND)) {
auxLcdLine = “err wrt “; auxLcdLine += logFile;
DEBUG_PRINTLN(auxLcdLine);
logLcdMessages(auxLcdLine);
showLcdMessages();
beep(2);
char errmsg[60]; auxLcdLine.toCharArray(errmsg, 60);
sd.errorHalt(errmsg);
}
sdAppend.println(text);
sdAppend.flush();
sdAppend.close();
DEBUG_PRINTS(”'”); DEBUG_PRINT(logFile); DEBUG_PRINTS(”'\n”);
// delay( 100 ); // ← wait a little
}

Update:

I know it’s brute force but what matters is that the SD write error went away.
I just added a initSD(); as the first line of appendLog and the write errors disappeared.
So the first few lines now look like this:

void appendLog(char logFile[14], String text ) {
initSD(); // <-----------Just added this. It was supposed to be used once on setup but…
// set date time callback function
SdFile::dateTimeCallback(dateTime);
tm = now();

Now another problem just appeared. Cayenne breaks after a few minutes (sometimes seconds) and arduino locks.
I isolated the problem to calls to:
Cayenne.virtualWrite(V1, sensorMeasureVal[i], TEMPERATURE, CELSIUS);

It is called and never returns. I have no idea on how to go deeper into this.

A sample of my code that sends data back to Cayenne looks like this:

CAYENNE_OUT(V1) {
Serial.print(F(“1”)); //freeMem();
byte i = 0;
// printV(i);// prints sensor information being sent to Cayenne
//if (sensorUnit[i] == F(" C “)) { Cayenne.celsiusWrite (V4, sensorMeasureVal[i]);} // optional call method
if (sensorUnit[i] == F(” C “)) {
Cayenne.virtualWrite(V1, sensorMeasureVal[i], TEMPERATURE, CELSIUS);
Serial.print(F(“a”)); //freeMem();
} else if (sensorUnit[i] == F(” % “)) {
Cayenne.virtualWrite(V1, sensorMeasureVal[i], HUMIDITY, PERCENT);
Serial.print(F(“b”)); //freeMem();
} else if (sensorUnit[i] == F(” hPa")) {
Cayenne.hectoPascalWrite(V1, sensorMeasureVal[i]);
Serial.print(F(“c”)); //freeMem();
}
Serial.print(F(“.”)); //freeMem();
}

I replaced the Ethernet Shield w/o success and my network is working as I have other arduino connected and working with Cayenne at the same time on the same hub.

Any suggestions on how to go further?

Thanks in advance.

Adam, I am talking about this problem on another post below where kreigg was also helping.

Please take a look to it as I tried MANY things to find the problem but despite all, it still remains there and I have no other ideas to debug. It really looks like a problem with Cayenne, I guess.
Thank you.
Carlos.

I would isolate this to using only the standard Cayenne barebones sketch including this call.

I am not convinced it is a Cayenne bug, but doing this test will prove if this call hangs, and the dev team has a reproducable bug.

Cheers,

Craig