Sd-card data buffered until close()?

Hello, got a engine datalogger writing stuff to csv and due to fire the arduino stopped with nothing on the card except the initial creation of the file, I was wondering how writing to sd goes since I really assumed every line was written until I close(), if not I have to recode and if yes it means the arduino stopped at the first line and not because of the fire.

void createFile(){
  sprintf(folder, "20%02d/%02d-%02d", yy, dd, mo);
  sprintf(file, "20%02d/%02d-%02d/%02d-%02d.CSV", yy, dd, mo, hh, mi);
  SD.mkdir(folder);
  myFile=SD.open(file, FILE_WRITE);
  myFile.println("timestamp,egt1,egt2,egt3,egt4,egt5,egt6,engine-temp,iat,exhaust-pressure,boost,H2O-pressure,oil-pressure,fuel-pressure,volt,RPM,wheelspeed");
  myFile.close();
}

void writeData() {
  if ((writeSD == 1) && (logBit == 0)) {
    logBit = 1;
    createFile();
    startTime = millis();
    myFile=SD.open(file, O_CREAT | O_WRITE | O_APPEND);
  }
  if ((writeSD == 1) && (logBit == 1)) {
    sprintf(time, "%02d:%02d:%02d.", hh, mi, ss);
    String writedata = "";
    writedata += time;
    writedata += (millis() - startTime);
    writedata += ',';
    writedata += egt1;
    writedata += ',';
    writedata += egt2;
    writedata += ','; 
    writedata += egt3;
    writedata += ',';
    writedata += egt4;
    writedata += ',';
    writedata += egt5;
    writedata += ',';
    writedata += egt6;
    writedata += ',';
    writedata += clt;
    writedata += ',';
    writedata += iat;
    writedata += ',';
    writedata += pressure1;
    writedata += ',';
    writedata += pressure2;
    writedata += ',';
    writedata += pressure3;
    writedata += ',';
    writedata += pressure4;
    writedata += ',';
    writedata += pressure5;
    writedata += ',';
    writedata += volt;
    writedata += ',';
    writedata += rpm1;
    writedata += ',';
    writedata += rpm2;
    myFile.println(writedata);
  }
  if ((writeSD == 0) && (logBit == 1)) {
    logBit = 0;
    myFile.close();
  }
}

void setup() {
  SD.begin(SD_CS);
}

void loop() {
  while (true)
  {
    if (myTouch.dataAvailable()) // check for touch screen events
    {
      myTouch.read();
      x=myTouch.getX();
      y=myTouch.getY();

      if ((y>=315) && (y<=390) && (x>=575) && (x<=790)) // START (575, 315, 790, 390)
      {
        drawFrame(575, 315, 790, 390);
        myGLCD.setColor(LCD_white);
        myGLCD.setBackColor (LCD_black);
        myGLCD.print("STOP", 650, 425);
        myGLCD.setColor(LCD_red);
        myGLCD.print("START", 650, 340);
        myGLCD.setBackColor (LCD_blue);
        writeSD = 1;
      }
      if ((y>=400) && (y<=475) && (x>=575) && (x<=790)) // STOP (575, 400, 790, 475)
      {
        drawFrame(575, 400, 790, 475);
        myGLCD.setColor(LCD_red);
        myGLCD.setBackColor (LCD_black);
        myGLCD.print("STOP", 650, 425);
        myGLCD.setColor(LCD_white);
        myGLCD.print("START", 650, 340);
        myGLCD.setBackColor (LCD_blue);
        writeSD = 0;
      }
    }
    time_now = millis();
      readSensors(); // 2632μs
      grabTime(); // 1068μs
      writeData(); // 6x1732μs + 1x4584μs = 14992μs / 7 = 2142μs average
      updateDisplay();
      printLEDbar();
      printRPM(1); // 38300μs
      printEGT(1); // 19320μs
      printEGT(2); // 19320μs
    while(millis() < time_now + period){
    }
  }
}

There is a 512 bytes buffer that is being used for all the bytes you send (write, print, println) to the SD card.

When the 512 byte buffer is full then the data is actually written on the SD card to clear out space in the buffer and caching starts again.

You can also force writing the cache to the SD if you close() the file or call flush()


side note : there is no reason to build the intermediary String buffer to write a full line since there is the 512 byte buffer anyway in front of the SD. Just print into that buffer and save memory !

if ((writeSD == 1) && (logBit == 1)) {
    snprintf(time, sizeof time, "%02d:%02d:%02d.", hh, mi, ss); // ensure you don't overflow...
    myFile.print(time);
    myFile.write(',');
    myFile.print(millis() - startTime);
    myFile.write(',');
    myFile.print(egt1);
    myFile.write(',');
    myFile.print(egt2);
    myFile.write(',');
    myFile.print(egt3);
    myFile.write(',');
    myFile.print(egt4);
    myFile.write(',');
    myFile.print(egt5);
    myFile.write(',');
    myFile.print(egt6);
    myFile.write(',');
    myFile.print(clt);
    myFile.write(',');
    myFile.print(iat);
    myFile.write(',');
    myFile.print(pressure1);
    myFile.write(',');
    myFile.print(pressure2);
    myFile.write(',');
    myFile.print(pressure3);
    myFile.write(',');
    myFile.print(pressure4);
    myFile.write(',');
    myFile.print(pressure5);
    myFile.write(',');
    myFile.print(volt);
    myFile.write(',');
    myFile.print(rpm1);
    myFile.write(',');
    myFile.println(rpm2);
}

thanks for pointing out!

Think that my code isn't really good anyway since it probably keeps the spi bus open until I press STOP so mayby print to the buffer and close() for every line

why do you say so ? the file can be open but it does not lock you SPI bus.
closing the file after every write is a way to ensure your SD card is in a clean state "most of the time"

I was looking into using multiple MAX6675 with SPI and for each device a SS, the sdcard is also using SPI so I have to finish writing stuff, select another device read data and then select the sd again and append to file, switching done by making SS pins high for not used and low for the one being read or written.

off topic but that's the "why do you say so"

You have not mentioned which arduino or SD card module you are using, be aware that a very common SD card adapter used to interface 5V logic to the 3.3V SD card has a flaw where the MISO line is not properly released. This prevents using any other SPI device along with that particular SD card adapter.

1 Like

right if you manually drive other SPI devices, you need to ensure SS is managed properly

1 Like