SD card writing causes timing issues.

I’m currently working with underwater sensors and a relay. I tried to add a function that would write the data I get from the sensors to an SD card. The problem is the sensors and relay I use depend a lot on timing and when you open a file on the SD card it takes a few milliseconds. Additionally I’m now having a problem where the SD card has a hard time initializing. Any help would be greatly appreciated! Here’s my code:

#include <Wire.h>
#include <SparkFun_Qwiic_Relay.h>
#include <U8glib.h>
#include "SparkFun_Qwiic_Relay.h"
#include "U8glib.h"
#include <SoftwareSerial.h>
#include "TSYS01.h"
#include "MS5837.h"
#define rx 2
#define tx 3
#define RELAY_ADDR 0x18
#include <SPI.h>
#include <SD.h>

File myFile;

TSYS01 sensor1;

MS5837 sensor;

Qwiic_Relay relay(RELAY_ADDR);

SoftwareSerial myserial(rx, tx);

String inputstring = "";
String sensorstring = "";
boolean input_string_complete = false;
boolean sensor_string_complete = false;
int timing = 0;
int time0 = 0;
int time1 = 0;

void setup() {

  Serial.begin(9600);
  myserial.begin(9600);
  inputstring.reserve(10);
  sensorstring.reserve(30);

  Serial.println("Starting");
  
  Wire.begin();
  
  sensor1.init();
  while (!sensor.init()) {
    Serial.println("Init failed!");
    Serial.println("Are SDA/SCL connected correctly?");
    Serial.println("Blue Robotics Bar30: White=SDA, Green=SCL");
    Serial.println("\n\n\n");
    delay(5000);
  }

  if (!SD.begin(4)) {
    Serial.println("SD initialization failed!");
    while (1);
  }
  Serial.println("SD initialization done.");
  myFile = SD.open("Output.txt", FILE_WRITE);

  if (myFile) {
    Serial.print("Testing Connection");
    myFile.println("Success");
    myFile.close();
    Serial.println("Success");
  } else {
    Serial.println("Error opening Output.txt");
  }

  sensor.setModel(MS5837::MS5837_30BA);
  sensor.setFluidDensity(997); // kg/m^3 (freshwater, 1029 for seawater)
}

void serialEvent() {
  inputstring = Serial.readStringUntil(13);
  input_string_complete = true;
}

void loop() {

if (time0 >= 0) {

  relay.turnRelayOn();

  delay(100);

  relay.turnRelayOff();

  delay(100);

  relay.turnRelayOn();

  delay(100);

  relay.turnRelayOff();

  time0 = -720000;

  } else { 
  myFile = SD.open("Output.txt", FILE_WRITE);
  if (timing == 170) {
    sensor.read();
    sensor1.read();

    Serial.print("Pressure: ");
    Serial.print(sensor.pressure());
    Serial.println(" mbar");

    myFile.print("Pressure: ");
    myFile.print(sensor.pressure());
    myFile.println(" mbar");

    Serial.print("Temperature: ");
    Serial.print(sensor1.temperature());
    Serial.println(" deg C");

    myFile.print("Temperature: ");
    myFile.print(sensor1.temperature());
    myFile.println(" deg C");

    Serial.print("Depth: ");
    Serial.print(sensor.depth());
    Serial.println(" m");

    myFile.print("Depth: ");
    myFile.print(sensor.depth());
    myFile.println(" m");

    Serial.print("Altitude: ");
    Serial.print(sensor.altitude());
    Serial.println(" m above mean sea level");
    Serial.println("");
    Serial.println("--------------");

    myFile.print("Altitude: ");
    myFile.print(sensor.altitude());
    myFile.println(" m above mean sea level");
    myFile.println("");
    myFile.println("--------------");
    timing = 0;
  }

  if (input_string_complete == true) {
    myserial.print(inputstring);
    myserial.print('\r');
    inputstring = "";
    input_string_complete = false;
  }

  if (myserial.available() > 0) {
    char inchar = (char)myserial.read();
    sensorstring += inchar;
    if (inchar == '\r') {
      sensor_string_complete = true;
    }
  }

  //pH Print
  if (sensor_string_complete == true) {
    Serial.print("pH: ");
    Serial.println(sensorstring);
    myFile.print("pH: ");
    myFile.println(sensorstring);
    sensorstring = "";
    sensor_string_complete = false;
  }

  delay(1);
  timing = timing + 1;
  time0 = time0 + 1;
  myFile.close();
  }
}

Also, here’s the weird error with initializing:

please help us.PNG

There are a couple other current threads here related to SD card delays. I think the bottom line is there's nothing much you can do about the delays other than maybe try to find a card that operates faster. But if you're already at a few ms delay, that's actually pretty fast.

On the error, I'm having trouble figuring out how your code generates that serial stream. But specifically, does this even work:

  if (!SD.begin(4)) {
    Serial.println("SD initialization failed!");
    while (1);
  }

I'm not really a C++ programmer, and don't understand how the while works here. Why not do it the way you did the sensor init just above that? I understand that one. :slight_smile:

Have you considered FRAM (Feroresemot Random Access Memory) It's similar to Static random-access memory, only with a ferroelectric layer instead of a dielectric layer. This gives it stable handling (the bytes you write are non-volatile) with dynamic responsiveness (you can write them very fast!). Some of the advantages I see in FRAM are high speed reading and writing, non-volatile storage (it remembers its contents without needing power or battery backup), virtually unlimited read / write cycles - you can't wear it out unlike some other types of non-volatile memory. To get started try this link: Adafruit SPI Non-Volatile FRAM Breakout - 64Kbit / 8KByte : ID 1897 : $5.95 : Adafruit Industries, Unique & fun DIY electronics and kits
Good Luck & Have Fun!
Gil

ShermanP:

  if (!SD.begin(4)) {

Serial.println("SD initialization failed!");
    while (1);
  }




I'm not really a C++ programmer, and don't understand how the while works here. Why not do it the way you did the sensor init just above that? I understand that one. :-)

This is pretty common code, copied into millions of examples and tutorials. It tries to initiate the card with card-select on pin 4. (This should be a named constant but it's only going to be used in this one place in the code, so not too important to waste time creating a name, right up until you try to put something else on pin 4.) If that fails (returns false) then print that it failed and stop.

while(true){/*Do nothing forever*/} might be a better way to write that last line. In most simple Arduino data loggers, if there's no SD card then the Arduino cannot do anything useful until the power is switched off and a card inserted.

Part of this construction is due to the original SD library having no close-and-restart method, so once you called begin() and there wasn't a card available, you couldn't later plug in a card and have it start working. The failed attempt at beginning was still open and could not be closed.

Oh I misunderstood what he was trying to do. I thought he wanted to go back and try again, and didn't see how that could work. But as you say, it's just an endless loop, so the code makes sense.

But I still don't understand how his code generates the stream that's shown in the serial monitor.

ShermanP:
But I still don't understand how his code generates the stream that's shown in the serial monitor.

For what I can see, "SD initializatioStarting" is a clear sign of self-resetting, but "SD initializatio[garbage]" appears to be either noise or oscillator issues.

Due to self-resetting makes me think about supply voltage instability (brown-out detector kicking in), which may also explain the oscillator's instability as well...