Increase Write Speed to MicroSD card

Hello everyone,
I am currently working on a project to monitor vibrations up to 1kHZ. For that, I need to take at least 2k samples a second. I am using an Arduino Nano 33 BLE with an Adafruit LIS3DH accelerometer (Overview | Adafruit LIS3DH Triple-Axis Accelerometer Breakout | Adafruit Learning System) and an Adafruit MicroSD card board (MicroSD card breakout board+ : ID 254 : $7.50 : Adafruit Industries, Unique & fun DIY electronics and kits). Both are wired to the Arduino via SPI. I am currently only getting around 600 samples per second written on the microSD card. How can I increase the write speed?

Code:

/*Running the LIS3DH accelerometer and writing the data to a microSD card
 * by willish32
 * Created 6/29/20
 */

#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>

//ACCELEROMETER SPI SETUP
// Used for hardware & software SPI
#define LIS3DH_CS 10
// hardware SPI
Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS);

//SD CARD SETUP
File myFile; //file name on SD
unsigned long timer; //timer var to track the datapoints per second... Plan on adding an RTC module later on to keep track of time
#define SIZE 100 //size of array 400 gets 2000 samples/sec ... sadly not anymore
double samples[SIZE][4]; //declare variable for sample storage

//FUNCTIONS

//Retrieve the data from the sensor
void getData() {
  //Collect data from the sensor
  for(int i=0; i<SIZE; i++){
  lis.read();      // get X Y and Z data at once
  // Then print out the raw data
  /*Serial.print("X:  "); Serial.print(lis.x);
  Serial.print("  \tY:  "); Serial.print(lis.y);
  Serial.print("  \tZ:  "); Serial.print(lis.z);
  */
  /* Or....get a new sensor event, normalized */
  sensors_event_t event;
  lis.getEvent(&event);

  /* Display the results (acceleration is measured in m/s^2) */
  /*Serial.print("\t\tX: "); Serial.print(event.acceleration.x);
  Serial.print(" \tY: "); Serial.print(event.acceleration.y);
  Serial.print(" \tZ: "); Serial.print(event.acceleration.z);
  Serial.println(" m/s^2 ");

  Serial.println();
  */
  //collect the data in blocks
      samples[i][0] = timer;
      samples[i][1] = event.acceleration.x;
      samples[i][2] = event.acceleration.y;
      samples[i][3] = event.acceleration.z;
  }
}

//Write the data to the MicroSD card
void writeData() {
  //write data to the MicroSD
  myFile = SD.open("test.txt", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    for(int i=0; i<SIZE; i++) {
      myFile.print(samples[i][0]);
      myFile.print(" ms \t X: ");
      myFile.print(samples[i][1]);
      myFile.print("\t Y: ");
      myFile.print(samples[i][2]);
      myFile.print("\t Z: ");
      myFile.print(samples[i][3]);
      myFile.print("\n");
    }
  // close the file:
  myFile.close();
  } else {
  // if the file didn't open, print an error:
  Serial.println("error opening test.txt");
  }
}


void setup() {
//setup the MicroSD card
  Serial.begin(115200); 
  while (!Serial) {
    ; //wait for the serial port to connect before proceding
  }
  Serial.print("Initializing SD card...");
  pinMode(9, OUTPUT); //set pin 9 as the output
  if (!SD.begin(9)) {
  Serial.println("initialization failed!");
  return;
}
Serial.println("initialization done.");

//setup the sensor
  Serial.println("LIS3DH test!");

  if (! lis.begin(0x18)) {   // change this to 0x19 for alternative i2c address
    Serial.println("Couldnt start");
    while (1) yield();
  }
  Serial.println("LIS3DH found!");

  // lis.setRange(LIS3DH_RANGE_4_G);   // 2, 4, 8 or 16 G!

  Serial.print("Range = "); Serial.print(2 << lis.getRange());
  Serial.println("G");

  lis.setDataRate(LIS3DH_DATARATE_LOWPOWER_5KHZ);
  Serial.print("Data rate set to: ");
  switch (lis.getDataRate()) {
    case LIS3DH_DATARATE_1_HZ: Serial.println("1 Hz"); break;
    case LIS3DH_DATARATE_10_HZ: Serial.println("10 Hz"); break;
    case LIS3DH_DATARATE_25_HZ: Serial.println("25 Hz"); break;
    case LIS3DH_DATARATE_50_HZ: Serial.println("50 Hz"); break;
    case LIS3DH_DATARATE_100_HZ: Serial.println("100 Hz"); break;
    case LIS3DH_DATARATE_200_HZ: Serial.println("200 Hz"); break;
    case LIS3DH_DATARATE_400_HZ: Serial.println("400 Hz"); break;

    case LIS3DH_DATARATE_POWERDOWN: Serial.println("Powered Down"); break;
    case LIS3DH_DATARATE_LOWPOWER_5KHZ: Serial.println("5 Khz Low Power"); break;
    case LIS3DH_DATARATE_LOWPOWER_1K6HZ: Serial.println("16 Khz Low Power"); break;
  }
}

void loop() {
  //start the timer
  timer = millis();
  getData();
  writeData();

  //test for shutdown command
  int incomingByte = 0;
  if(Serial.available() >= 0){
    incomingByte=Serial.read();
  }
  //shutdown
  if(incomingByte == '0'){
    myFile.close();
    Serial.print("The process has ended");
  }

}

willish32:
I need to take at least 2k samples a second.

The vital thing you don't talk about is for how long.

Micro SDs are not famous for speed and you may be already getting all you are going to get, although I bet opening and closing the file every time in that subroutine is a timewaster.

You might look at storing the data in RAM over the event and then send to SD at leisure.

You look to be opening and closing the file on the SD card everytime you want to add some more data that causes additional I/O as it has to update other files when it closes. Try keeping the file open from thestat unti you need add no more data.