Hi All,
I am working on a project that receives data over serial to a particle and writes it to an sd card. I found several libraries, mostly by @rickkas7, that were hugely helpful in getting started and things seem to be working pretty well until the data rate increases and then I start to see problems with the data being received/recorded correctly.
Based on a couple quick calcs, I believe my max data rate coming in to the Argon over serial is about 15,000 bytes/s which I believe is doable from the reading I’ve done but please correct me if I am incorrect. I assume it is a problem with the buffer but am not sure where to go from there.
My hardware includes the adafruit RTC sd card logger, adafruit display board with a couple buttons and an Argon.
See code below:
#include "oled-wing-adafruit.h"
#include "SdFat.h"
#include "Particle.h"
#include "SerialBufferRK.h"
#include "Adafruit_RTClib_RK.h"
#include "AdafruitDataLoggerRK.h"
#include <string>
SYSTEM_THREAD(ENABLED);
const int SD_CHIP_SELECT = D5;
SdFat sd;
File myFile;
SerialLogHandler serialLogHandler;
OledWingAdafruit display;
RTC_PCF8523 rtc;
RTCSynchronizer rtcSync;
DateTime now;
// Allocate a serial buffer of 256 bytes attached to Serial1
// call serBuf.read() instead of Serial1.read()
SerialBuffer<4096> serBuf(Serial1);
int timestamp = millis();
bool cardReady = false;
bool startupLoop = true;
bool logging = false;
char fileName[] = "LOGGER00.txt";
void setup()
{
rtcSync.setup();
// setup the oled display and clear
display.setup();
display.clearDisplay();
display.display();
//turn on serial connection
Serial.begin();
Serial1.begin(230400);
// You must call serBuf.setup() from setup!
serBuf.setup();
// get dateTime from real time clock
now = rtc.now();
timestamp = millis();
// Initialize the library
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED))
{
updateDisplayString("ERROR: SD Init", true);
return;
}
else
{
updateDisplayString("SD init succesful", true);
delay(500);
}
getFilename();
// Open with fileName
if (!myFile.open(fileName, O_CREAT | O_WRITE | O_AT_END))
{
updateDisplayString("ERROR: Open SD", true);
return;
}
else
{
updateDisplayString("SD open succesful", true);
cardReady = true;
delay(500);
}
}
void loop()
{
if (cardReady == true) //check that there isn't a problem with the card
{
if (logging == false)
{
updateDisplayString("Press button A\nto start logging", false);
if (display.pressedA())
{
logging = true;
updateDisplayString("Logging In Progress,\nHold Button B to Stop", false);
}
}
else
{
if (display.pressedB())
{
updateDisplayString("Logging Stopped", true);
int starttime = millis();
while (millis() - starttime <= (3000))
{
String dataRow = serBuf.readStringUntil('^');
if (dataRow.length() != 0)
{
String writeToSDCard = (String)millis() + "," + dataRow; //ToDo switch away from micros(), we expect 800hz data so micros is probably not enough resolution for timestamp
writeToSD(writeToSDCard);
Log.info(dataRow);
}
}
writeToSD("END OF FILE");
myFile.close(); //close the file now that nothing else is coming. //ToDo change the setup of the loop so you can start new files without restering device
//ToDo add in the file upload to web
return;
}
// ToDo - it seems like this is taking too loing, data overflows expected format in high data rate events (impact)
String dataRow = serBuf.readStringUntil('^');
if (dataRow.length() != 0)
{
String writeToSDCard = (String)millis() + "," + dataRow; //ToDo switch away from micros(), we expect 800hz data so micros is probably not enough resolution for timestamp
writeToSD(writeToSDCard);
Log.info(dataRow);
}
}
}
else
{
updateDisplayString("ERROR: No SD Card", true);
return;
}
display.loop();
rtcSync.loop();
}
void updateDisplayString(String inputString, bool serialLog)
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println(inputString);
if (serialLog == true)
{
Log.info(inputString); //also log to serial monitor
}
display.display();
}
void writeToSD(String dataRow)
{
myFile.println(dataRow);
myFile.flush();
}
void getFilename()
{
// ToDo better way to make filenames. This can only do 100.
for (byte i = 1; i <= 99; i++)
{
Log.info("loop num: %i", i);
// check before modifying target filename.
if (sd.exists(fileName))
{
// the filename exists so increment the 2 digit filename index.
fileName[6] = i / 10 + '0';
fileName[7] = i % 10 + '0';
Log.info("filename already in use, adding to name: %s", fileName);
}
else
{
updateDisplayString((String)fileName, true);
delay(2000);
myFile.open(fileName, O_CREAT | O_WRITE | O_AT_END);
printDate(now);
myFile.write("Time,aX(mG),aY(mG),aZ(mG),|Vector|,vR(r/s),aR(r/s/s)");
myFile.close();
delay(2000);
return;
}
}
}
void printDate(const DateTime &now)
{
myFile.print(' ');
myFile.print(now.year(), DEC);
myFile.print('/');
myFile.print(now.month(), DEC);
myFile.print('/');
myFile.print(now.day(), DEC);
myFile.print(' ');
myFile.print(now.hour(), DEC);
myFile.print(':');
myFile.print(now.minute(), DEC);
myFile.print(':');
myFile.print(now.second(), DEC);
myFile.println();
}