100Hz Data Logging

Hi everyone.

I have been working through some code utilizing examples and online support to try and develop some code which will record data from the SparkFun Micro 6DoF IMU - ISM330DHCX sensor at 100Hz onto an SD card via the SparkFun ESP32 RedBoard.

I also have a SparkFun RV1805 RTC in the circuit to help sync everything at 100Hz.

So far I am not able to get a solid and reliable 100Hz logging. This may be a hardware limitation of the sensor, I'm not 100% sure.

I have included a copy of the code I've been working on. Any help would be greatly appreciated.

Thanks everyone.

#include <Wire.h>
#include <SD.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ISM330DHCX.h>
#include <SparkFun_RV1805.h>

#define CS_PIN 5

RV1805 rtc; // Create an RV-1805 RTC object
Adafruit_ISM330DHCX imu; // Create an ISM330DHCX object

const unsigned long SAMPLE_INTERVAL = 10; // Sampling interval in milliseconds (100Hz)
const unsigned long RECORDING_DURATION = 60000; // Recording duration in milliseconds (60 seconds)
const char* FILENAME = "/sensor_data.csv"; // File name to save data

File dataFile;
unsigned long recordingStartTime = 0;
unsigned long lastSampleTime = 0;
unsigned long startTimeMillis = 0;

void setup() {
  Wire.begin();
  Serial.begin(115200);

  if (!SD.begin(CS_PIN)) {
    Serial.println("Error initializing SD card.");
    while (true);
  }

  if (!imu.begin_I2C(0x6B)) {
    Serial.println("Couldn't find ISM330DHCX sensor.");
    while (true);
  }

  if (!rtc.begin()) {
    Serial.println("Couldn't find RV1805 RTC.");
    while (true);
  }

  recordingStartTime = millis();
  lastSampleTime = recordingStartTime;
  startTimeMillis = rtc.getEpoch(); // Get the RTC start time in seconds

  dataFile = SD.open(FILENAME, FILE_WRITE);

  if (dataFile) {
    // Print headers to the data file
    dataFile.println("Timestamp (ms),Acceleration X (mg),Acceleration Y (mg),Acceleration Z (mg),Gyro X (dps),Gyro Y (dps),Gyro Z (dps)");
    dataFile.close();
  } else {
    Serial.println("Error opening data file.");
  }
}

void loop() {
  unsigned long currentTime = millis();

  if (currentTime - recordingStartTime >= RECORDING_DURATION) {
    dataFile.close();
    Serial.println("Recording complete.");
    while (true);
  }

  if (currentTime - lastSampleTime >= SAMPLE_INTERVAL) {
    recordSensorData(currentTime);
    lastSampleTime = currentTime;
  }
}

void recordSensorData(unsigned long currentTime) {
  dataFile = SD.open(FILENAME, FILE_APPEND);

  if (dataFile) {
    sensors_event_t accel;
    sensors_event_t gyro;
    sensors_event_t temp;
    imu.getEvent(&accel, &gyro, &temp);

    // Convert acceleration and gyro values to millig's and degrees per second
    float accelX_mg = accel.acceleration.x * 1000.0;
    float accelY_mg = accel.acceleration.y * 1000.0;
    float accelZ_mg = accel.acceleration.z * 1000.0;
    float gyroX_dps = gyro.gyro.x;
    float gyroY_dps = gyro.gyro.y;
    float gyroZ_dps = gyro.gyro.z;
    float temp_deg = temp.temperature;

    // Get the current time from the RTC and calculate the timestamp in milliseconds
    unsigned long currentTimeRTC = rtc.getEpoch();
    unsigned long timestamp_ms = (currentTimeRTC - startTimeMillis) * 1000 + (currentTime % 1000);

    // Print data to the data file with the timestamp
    dataFile.print(timestamp_ms);
    dataFile.print(",");
    dataFile.print(accelX_mg);
    dataFile.print(",");
    dataFile.print(accelY_mg);
    dataFile.print(",");
    dataFile.print(accelZ_mg);
    dataFile.print(",");
    dataFile.print(gyroX_dps);
    dataFile.print(",");
    dataFile.print(gyroY_dps);
    dataFile.print(",");
    dataFile.print(gyroZ_dps);
    dataFile.print(",");
    dataFile.println(temp_deg);

    dataFile.close();
  } else {
    Serial.println("Error opening data file.");
  }
}

Opening the SD file, writing one line of data and closing it again is the major problem, and is a common beginner mistake. Every time you open the file, an entire 512 byte block of data must be read in to memory, then is written back out each time you close it.

Open the file once in setup() and close it only when you are all done collecting data.

  dataFile = SD.open(FILENAME, FILE_WRITE);

  if (dataFile) {
    // Print headers to the data file
    dataFile.println("Timestamp (ms),Acceleration X (mg),Acceleration Y (mg),Acceleration Z (mg),Gyro X (dps),Gyro Y (dps),Gyro Z (dps)");
    dataFile.close();

Oh wow, that's perfect now! Thank you so much. The data is beautiful!

Richard