SD Problems - Low Memory?

Hello, I am making a flight computer with several sensors that logs data on a micro-SD card. I can get each of the sensors to work individually, and the SD card to work on its own, but when I combine it all, my file won't open to save the data. Is the SD error due to the low memory available? If so, what's a good way to save on storage? Thanks!

This is the message I get when I run it:

Sketch uses 23264 bytes (75%) of program storage space. Maximum is 30720 bytes.
Global variables use 1712 bytes (83%) of dynamic memory, leaving 336 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_MPL3115A2.h>
#include "MPU9250.h"

File dataFile;
MPU9250 IMU(Wire,0x68);
Adafruit_MPL3115A2 baro = Adafruit_MPL3115A2();

int status;
const int chipSelect = 4;

void setup() {
  Serial.begin(9600);
  status = IMU.begin();
  pinMode(2, OUTPUT);
  pinMode(8, OUTPUT);
  while (!Serial){
    Serial.print("Serial not connected!");
    digitalWrite(8,true); //indicator LED
    }
  while (status < 0){
    Serial.print("IMU not connected!");
    digitalWrite(8,true);
  }
  while (!SD.begin(chipSelect)) {
    Serial.println("SD initialization failed!");
    digitalWrite(8,true);
    }
  while (! baro.begin()) {
  Serial.println("Barometer Failed!");
  digitalWrite(8,true);
  }
  
   
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile){ //creates column titles
    dataFile.println("Pressure(inches Hg), Altitude(m), Temp(*F), AccX(m/s), AccY(m/s), AccZ(m/s), GyroX(rad/s), GyroY(rad/s), GyroZ(rad/s)");
    dataFile.close();
    Serial.println("Pressure(inches Hg), Altitude(m), Temp(*F), AccX(m/s), AccY(m/s), AccZ(m/s), GyroX(rad/s), GyroY(rad/s), GyroZ(rad/s)");
    }
  digitalWrite(8,false);
} //end setup

void loop() {
  IMU.readSensor();
 
  String dataString = "";
  float pascals = baro.getPressure(); //barometer data
  float alt     = baro.getAltitude();
  float tempC   = baro.getTemperature();
  
  float accelX  = IMU.getAccelX_mss(); //IMU data
  float accelY  = IMU.getAccelY_mss();
  float accelZ  = IMU.getAccelZ_mss();
  float gyroX   = IMU.getGyroX_rads();
  float gyroY   = IMU.getGyroY_rads();
  float gyroZ   = IMU.getGyroZ_rads();

  
  dataString += String(pascals/3377); dataString += ",";
  dataString += String(alt); dataString += ",";
  dataString += String(tempC * 9 / 5 + 32); dataString += ",";
  dataString += String(accelX); dataString += ",";
  dataString += String(accelY); dataString += ",";
  dataString += String(accelZ); dataString += ",";
  dataString += String(gyroX); dataString += ",";
  dataString += String(gyroY); dataString += ",";
  dataString += String(gyroZ);
  //Serial.print(dataString);
  
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if(!dataFile){
    Serial.println(" Can't open dataFile");
    digitalWrite(2,true); //indicator LEDs
    digitalWrite(8,true);
    while(1){} //stop if file doesn't open
  }
  if (dataFile){
    dataFile.println(dataString);
    dataFile.close();
   Serial.println("Data Uploaded!");
  }
  
  delay(250); 
}

You need to free some RAM used by all those string literals - try using the F() macro and report back.

Thanks for the tip. I added a #define F up top and added the F() macro to many of the strings but nothing changed. I'm definitely doing it wrong but I'm not sure as to why.

code is below:

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_MPL3115A2.h>
#include "MPU9250.h"
#define F
File dataFile;
MPU9250 IMU(Wire,0x68);
Adafruit_MPL3115A2 baro = Adafruit_MPL3115A2();

int status;
const int chipSelect = 4;

void setup() {
  Serial.begin(9600);
  status = IMU.begin();
  while (!Serial){
    Serial.print("Serial not connected!");
    digitalWrite(8,true); //indicator LED
    }
  while (status < 0){
    Serial.print("IMU not connected!");
    digitalWrite(8,true);
  }
  while (!SD.begin(chipSelect)) {
    Serial.println("SD initialization failed!");
    digitalWrite(8,true);
    }
  while (! baro.begin()) {
  Serial.println("Barometer Failed!");
  digitalWrite(8,true);
  }
  
  pinMode(2, OUTPUT);
  pinMode(8, OUTPUT);
  
   
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile){ //creates column titles
    dataFile.println("Pressure(inches Hg), Altitude(m), Temp(*F), AccX(m/s), AccY(m/s), AccZ(m/s), GyroX(rad/s), GyroY(rad/s), GyroZ(rad/s)");
    dataFile.close();
    Serial.println(F("Pressure(inches Hg), Altitude(m), Temp(*F), AccX(m/s), AccY(m/s), AccZ(m/s), GyroX(rad/s), GyroY(rad/s), GyroZ(rad/s)"));
    }
  digitalWrite(8,false);
} //end setup

void loop() {
  IMU.readSensor();
 
  String(F(dataString)) = "";
  float pascals = baro.getPressure(); //barometer data
  float alt     = baro.getAltitude();
  float tempC   = baro.getTemperature();
  
  float accelX  = IMU.getAccelX_mss(); //IMU data
  float accelY  = IMU.getAccelY_mss();
  float accelZ  = IMU.getAccelZ_mss();
  float gyroX   = IMU.getGyroX_rads();
  float gyroY   = IMU.getGyroY_rads();
  float gyroZ   = IMU.getGyroZ_rads();

  
  dataString += String(F(pascals/3377)); dataString += ",";
  dataString += String(F(alt)); dataString += ",";
  dataString += String(F(tempC * 9 / 5 + 32)); dataString += ",";
  dataString += String(F(accelX)); dataString += ",";
  dataString += String(F(accelY)); dataString += ",";
  dataString += String(F(accelZ)); dataString += ",";
  dataString += String(F(gyroX)); dataString += ",";
  dataString += String(F(gyroY)); dataString += ",";
  dataString += String(F(gyroZ));
  Serial.print(F(dataString));
  
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if(!dataFile){
    Serial.println(" Can't open dataFile");
    digitalWrite(2,true); //indicator LEDs
    digitalWrite(8,true);
    while(1){} //stop if file doesn't open
  }
  if (dataFile){
    dataFile.println(F(dataString));
    dataFile.close();
   Serial.println("Data Uploaded!");
  }
  
  delay(250); 
}

lumaz:
I added a #define F up top

Why?

I read online but I was confused as to whether I should do it or not. I'll remove that and format the code accordingly. Thank you!

Check the reference page for Serial.print to see how to use F()

You use String variables to create a huge String a piece at a time just to write to SD.

I'm not going to type out an explanation of why to NOT use String variables in small memory, you can search if you want details. Long story short, String is not your friend on Arduinos.

But besides that, you don't need or want to assemble a line of text to put the text on SD. What you write to SD first writes to a 512 byte buffer in your RAM and only writes to SD when full. When printing to serial, it has its own buffer so again you don't need to pre-assemble a long text string (lower-case s string is not String) to print the whole.

  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if(!dataFile){
    Serial.println(" Can't open dataFile");
    digitalWrite(2,true); //indicator LEDs
    digitalWrite(8,true);
    while(1){} //stop if file doesn't open
  }
  if (dataFile)
  {
//    dataFile.println(F(dataString));  <<<=== the F() macro is ONLY for constant strings stored in flash memory.

  dataFile.write(pascals/3377);              dataFile.write( ',' );
  dataFile.write(alt);                               dataFile.write( ',' );
  dataFile.write(tempC * 9 / 5 + 32);      dataFile.write( ',' );
  dataFile.write(accelX);                        dataFile.write( ',' );
  dataFile.write(accelY);                        dataFile.write( ',' );
  dataFile.write(accelZ);                        dataFile.write( ',' );
  dataFile.write(gyroX);                         dataFile.write( ',' );
  dataFile.write(gyroY);                         dataFile.write( ',' );
  dataFile.write(gyroZ);                         dataFile.write( '\n' );

  Serial.write(pascals/3377);              Serial.write( ',' );
  Serial.write(alt);                               Serial.write( ',' );
  Serial.write(tempC * 9 / 5 + 32);      Serial.write( ',' );
  Serial.write(accelX);                        Serial.write( ',' );
  Serial.write(accelY);                        Serial.write( ',' );
  Serial.write(accelZ);                        Serial.write( ',' );
  Serial.write(gyroX);                         Serial.write( ',' );
  Serial.write(gyroY);                         Serial.write( ',' );
  Serial.write(gyroZ);                         Serial.write( '\n' );

   dataFile.close();
   Serial.println("Data Uploaded!");
  }

Little secret, the Arduino is so much faster than Serial that before one character transmits you can print just one char at a time more chars than there is buffer (64). At 9600 baud it takes over a ms to send just one char.

Tip to save some RAM; don't use int to store small values, they take 2 bytes each. The Arduino byte variable takes 1 byte and can hold 0 to 255, perfect for pin numbers.