Logger - SD Card write speed - Corrupt files

Hi
I have improved upon my voltage logger
I have added an SD card hat
And added a 16bit ADC
SO.. the 16 bit (15 bits plus sign really) is much better than the 10 bit analog inputs on my uno board
The 16 bit ADC is great
But having issues with corrupt file on the SD card
It seems fine for a short log, but after a few hours *.CSV file its writing is corrupt and not readable on computer
I think I'm not writing to the card very efficiently
I have got it writing the time in millis so I can see how often its taking readings and its not only slow but it varies a LOT
I assume I need to store a selection of readings in a buffer or cache and write to file every 5 seconds?
I have looked and have no idea how to do that! many thanks for any help you can offer

I would like 50 readings a second - I seem to be getting that maybe thats a tall order?

I have read I could "delay" readings using millis instead of delay and store readings and write to card less often in blocks?

Alternatively it could be crashing/corrupting because of file size? the corrupt file was 7590kb maybe there is a file size limit?

Hardware - Arduino Uno - SD Card Sheild Sees Studio - ADS1115 ADC

As before I am measuring single ni-mh battery discharge and charge voltages

Thankyou for any help your able to offer

//16 bit volt meter
//Logs to sd card
//

#include <SD.h>
#include<ADS1115_WE.h>
#include<Wire.h>
#define I2C_ADDRESS 0x48
#define ECHO_TO_FILE 1
File logfile;
//int t, delay_t = 1000, dt = 5; //log every 5 seconds
const int chipSelect = 4;
ADS1115_WE adc(I2C_ADDRESS);
// ADS1115_WE adc = ADS1115_WE(); // Alternative: uses default address 0x48
unsigned long myTime;

void setup() {
  //Serial.begin(9600);
  pinMode (10, OUTPUT);
#if ECHO_TO_FILE
  //Serial.print ("Initializing SD Card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present"); return;
  }
  else {
    Serial.println("card initialized."); char filename[] = "MAHASD.csv";
    logfile = SD.open(filename, FILE_WRITE);
    if (!logfile) {
      Serial.println("Could not create file.");
      return;
    }
    else {
      Serial.print("logging to: ");
      Serial.println(filename);
    }
  }
#endif //ECHO_TO_FILE
  Wire.begin();
  if (!adc.init()) {
    //Serial.println("ADS1115 not connected!");
  }

  /* Set the voltage range of the ADC to adjust the gain
     Please note that you must not apply more than VDD + 0.3V to the input pins!

     ADS1115_RANGE_6144  ->  +/- 6144 mV
     ADS1115_RANGE_4096  ->  +/- 4096 mV
     ADS1115_RANGE_2048  ->  +/- 2048 mV (default)
     ADS1115_RANGE_1024  ->  +/- 1024 mV
     ADS1115_RANGE_0512  ->  +/- 512 mV
     ADS1115_RANGE_0256  ->  +/- 256 mV
  */
  adc.setVoltageRange_mV(ADS1115_RANGE_4096); //comment line/change parameter to change range

  /* Set the inputs to be compared

      ADS1115_COMP_0_1    ->  compares 0 with 1 (default)
      ADS1115_COMP_0_3    ->  compares 0 with 3
      ADS1115_COMP_1_3    ->  compares 1 with 3
      ADS1115_COMP_2_3    ->  compares 2 with 3
      ADS1115_COMP_0_GND  ->  compares 0 with GND
      ADS1115_COMP_1_GND  ->  compares 1 with GND
      ADS1115_COMP_2_GND  ->  compares 2 with GND
      ADS1115_COMP_3_GND  ->  compares 3 with GND
  */
  adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channel
  //adc.setCompareChannels(ADS1115_COMP_2_3); //comment line/change parameter to change channel

  /* Set number of conversions after which the alert pin will be active
     - or you can disable the alert

      ADS1115_ASSERT_AFTER_1  -> after 1 conversion
      ADS1115_ASSERT_AFTER_2  -> after 2 conversions
      ADS1115_ASSERT_AFTER_4  -> after 4 conversions
      ADS1115_DISABLE_ALERT   -> disable comparator / alert pin (default)
  */
  //adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default

  /* Set the conversion rate in SPS (samples per second)
     Options should be self-explaining:

      ADS1115_8_SPS
      ADS1115_16_SPS
      ADS1115_32_SPS
      ADS1115_64_SPS
      ADS1115_128_SPS (default)
      ADS1115_250_SPS
      ADS1115_475_SPS
      ADS1115_860_SPS
  */
  adc.setConvRate(ADS1115_128_SPS); //uncomment if you want to change the default

  /* Set continuous or single shot mode:

      ADS1115_CONTINUOUS  ->  continuous mode
      ADS1115_SINGLE     ->  single shot mode (default)
  */
  adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode

  /* Choose maximum limit or maximum and minimum alert limit (window)in Volt - alert pin will
     be active when measured values are beyond the maximum limit or outside the window
     Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
     In max limit mode the minimum value is the limit where the alert pin will be deactivated (if
     not latched)

     ADS1115_MAX_LIMIT
     ADS1115_WINDOW

  */
  //adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default

  /* Enable or disable latch. If latch is enabled the alarm pin will be active until the
     conversion register is read (getResult functions). If disabled the alarm pin will be
     deactivated with next value within limits.

      ADS1115_LATCH_DISABLED (default)
      ADS1115_LATCH_ENABLED
  */
  //adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default

  /* Sets the alert pin polarity if active:

     Enable or disable latch. If latch is enabled the alarm pin will be active until the
     conversion register is read (getResult functions). If disabled the alarm pin will be
     deactivated with next value within limits.

     ADS1115_ACT_LOW  ->  active low (default)
     ADS1115_ACT_HIGH ->  active high
  */
  //adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default

  /* With this function the alert pin will be active, when a conversion is ready.
     In order to deactivate, use the setAlertLimit_V function
  */
  //adc.setAlertPinToConversionReady(); //uncomment if you want to change the default

  //Serial.println("ADS1115 Example Sketch - Continuous Mode");
  //Serial.println();
}

void loop() {
  float voltage = 0.0;
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  //Serial.print("Channel 0 vs GND [V]: ");
  //Serial.print(voltage , 3);
  //Serial.print(",");
  //Serial.println();
#if ECHO_TO_FILE
  myTime = millis();
  logfile.print(myTime); logfile.print(","); logfile.print(voltage , 6); logfile.println(",");
  logfile.flush();
#endif //ECHO_TO_FILE

  //delay(0);
}

log CSV.txt (582 KB)

But having issues with corrupt file on the SD card

Not surprised seeing your code.

An SD card is a flash storage and as so it writes in complete blocks. A block is first erased, then written. It does that for every enforced write operation (flush) and every block write counts on the lifetime. Standard SD card's flash can be written about 10'000 times. The cards controller tries to spread these writes over the available cells as good as possible but if you write every few milliseconds, your card will die in a few days. Collect several readings in memory and write them down in block size (ideally) or at least in big chunks.