I am working on a logging device for paragliding, using a Teensy 3.1, a MS5637 pressure sensor and an SD card. The code I am using is as follows:
#include <SdFat.h> // SD card library
#include <math.h>
#include <Wire.h>
const int chipSelect = 10;
#define ADDRESS 0x76 //define adress of MS5637 Barometer, infos from datasheet
// Create file system object
SdFat sd;
// Define text file for logging
ofstream logfile;
uint32_t D1 = 0;
uint32_t D2 = 0;
int64_t dT = 0;
int64_t TEMP = 0;
int64_t OFF = 0;
int64_t SENS = 0;
int64_t P = 0;
int64_t T2 = 0;
int64_t OFF2 = 0;
int64_t SENS2 = 0;
uint16_t C[7];
float temperature;
float pressure;
float altBaro;
const float sea_press = 1013.3;
String bufferString = "";
String SDbufferString = "";
uint64_t time = 0;
uint64_t timeOld = 0;
void setup() {
Wire.begin();
Serial.begin(115200);
I2C0_F = 0x1A; //set the I2C speed to 400KHz for Teensy 3.1
delay(100);
initBaro(ADDRESS);
// initialize the SD card at SPI_FULL_SPEED
if (!sd.begin(chipSelect, SPI_FULL_SPEED )) sd.initErrorHalt();
// Create a new file in the current working directory
// and generate a new name if the file already exists
char fileName[13] = "LOGGER00.CSV";
for (uint8_t i = 0; i < 150; i++)
{
fileName[6] = i/10 + '0';
fileName[7] = i%10 + '0';
if (sd.exists(fileName)) continue;
logfile.open(fileName);
break;
}
logfile << ("Time,Temperature,Pressure,AltitudeRaw") << flush; //Write header to logfile
timeOld = millis();
}
void loop() {
time = millis();
int dt = time - timeOld;
timeOld = time;
requestPressure(); // Request pressure conversion raw
delay(20); // OSR=8192, minimal delay ro read result is 17ms
// Instead of delay(20) something useful can be done during this time, like reading an IMU
readPressure(); // Read raw pressure
requestTemperature(); // Request pressure conversion raw
delay(20); // OSR=8192, minimal delay ro read result is 17ms
// Instead of delay(20) something useful can be done during this time, like reading an IMU
readTemperature(); // Read raw pressure
calculatePressureTemperature();
altBaro = 44330 * (1.0 - pow(pressure /sea_press,0.1903));
// make a string for assembling the data to log:
String dataString = "";
dataString += String("Time,");
dataString += String(int(time));
dataString += String(",");
dataString += String("Temperature,");
dataString += String(temperature);
dataString += String(",");
dataString += String("Pressure,");
dataString += String(pressure);
dataString += String(",");
dataString += String("AltitudeBaro,");
dataString += String(altBaro);
dataString += String("\n"); //Create a new line on the SD card
bufferString += dataString;
int length = bufferString.length();
if (length > 512)
{
SDbufferString = bufferString.substring(0,511); //Create a string with 512 bytes for writing on the SD card.
bufferString = bufferString.substring(511,length); //Remove the 512 bytes for the SD card from the main string.
char charBuf[512];
SDbufferString.toCharArray(charBuf,512);
logfile << charBuf << flush; //Write to SD Card
}
Serial.print(int(dt));
Serial.println();
}
void requestPressure()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x4A); //OSR=8192, minimal delay ro read result is 17ms
Wire.endTransmission();
//delay(20);
}
void readPressure()
{
Wire.beginTransmission(ADDRESS);
Wire.write((byte) 0x00);
Wire.endTransmission();
Wire.beginTransmission(ADDRESS);
Wire.requestFrom(ADDRESS, (int)3);
if (Wire.available() >= 3)
{
D1 = Wire.read() * (unsigned long)65536 + Wire.read() * (unsigned long)256 + Wire.read();
}
Wire.endTransmission();
}
void requestTemperature()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x5A); //OSR=8192, minimal delay ro read result is 17ms
Wire.endTransmission();
//delay(20);
}
void readTemperature()
{
Wire.beginTransmission(ADDRESS);
Wire.write((byte) 0x00);
Wire.endTransmission();
Wire.beginTransmission(ADDRESS);
Wire.requestFrom(ADDRESS, (int)3);
if (Wire.available() >= 3)
{
D2 = Wire.read() * (unsigned long)65536 + Wire.read() * (unsigned long)256 + Wire.read();
}
Wire.endTransmission();
}
void calculatePressureTemperature()
{
OFF2 = 0;
SENS2 = 0;
dT=D2-C[5]*pow(2,8);
TEMP=2000+(dT*C[6])/pow(2,23);
OFF=C[2]*pow(2,17)+dT*C[4]/pow(2,6);
SENS=C[1]*pow(2,16)+dT*C[3]/pow(2,7);
if (TEMP < 2000) // if temperature lower than 20 Celsius
{
OFF2 = 61*pow((TEMP-2000),2)/pow(2,4);
SENS2 = 29*pow((TEMP-2000),2)/pow(2,4);
}
TEMP=TEMP-T2;
OFF=OFF-OFF2;
SENS=SENS-SENS2;
P=(((D1*SENS)/pow(2,21)-OFF)/pow(2,15));
temperature=(float)TEMP/100;
pressure=(float)P/100;
}
void initBaro(uint8_t address)
{
Serial.println("Reading Calibration Data");
Wire.beginTransmission(address);
Wire.write(0x1E); // reset
Wire.endTransmission();
delay(10);
for (int i = 0; i < 6 ; i++) {
Wire.beginTransmission(address);
Wire.write(0xA2 + (i * 2));
Wire.endTransmission();
Wire.beginTransmission(address);
Wire.requestFrom(address, (uint8_t) 6);
delay(1);
if (Wire.available())
{
C[i + 1] = Wire.read() << 8 | Wire.read();
}
else {
Serial.println("Error Reading Calibration Data"); // error reading the PROM or communicating with the device
}
Serial.print("C");
Serial.print(i + 1);
Serial.print(" ");
Serial.println(C[i + 1]);
}
Serial.println();
}
The issue is now that it takes too long (and the dt time is not constant, varies between 41ms to 300ms) to write the data to the SD card, and that the code does nothing useful when the SD card is busy writing the data. The idea is to have a code that always needs the same time for the loop, and that there would no useful processor time wasted waiting for the SD card to write the data.
Ideally it would be great if the writing of the data to the SD card could be split into several actions:
Buffer the data that have to be written to the SD card in strings of 512 bytes.
Check if the SD card is ready to accept data. If not, continue directly with the main loop. But if it's possible to write data then this data should be sent to the SD card, without waiting that the SD card actually writes the data. Continue immediately after the write command with the main loop.
Check later on if the data has been written to the SD card in the loop. If the SD card is still busy writing data continue immediately with the main loop. Otherwise write another 512 bytes from the buffer.
Like this the loop would always take almost the same time to execute, but the data would only be sent to the SD card if that makes sense. The intervals where the data are written to the SD card would then be somewhat written randomly, but the code would not be slowed down due to the fact that data gets written to the SD card.
It doesn't matter if it takes time to write to the card, but it would be very useful if the Arduino or Teensy could do something else while the card is writing the data, instead of waiting for the SD card until the write process has finished. If such an approach is feasible then it might take much less processor time to write the data. And if the data is written not in constant time steps this doesen't matter, it's important that the correct data is written to the SD card, not when that data is written.
A non-blocking SD library or SDFAT library would solve that problem.
I am quite new to programming, so help to solve that problem would greatly be appreciated.