SD card does not open file

Hello,

I am trying to create a datalogger of sorts using the BMP180 and ADXL345 pressure sensor and accelerometer breakout boards from Adafruit. Of course, to store large amounts of data, one must use an SD card. I am using an Ethernet SD card shield at the moment.

Running the ReadWrite or DataLogger examples from the SD library work perfectly, however, I cannot get the file to open properly when I try to implement it in my own code.

Right now I am just trying to read the accelerometer data (all th parts pertaining to capturing data from the BMP180 are commented out.

Here is my entire code:

#include <SD.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_ADXL345_U.h>
#include <SPI.h>

/*Sensors*/
//Accelerometer and altimeter on I2C
Adafruit_ADXL345_Unified Accelerometer = Adafruit_ADXL345_Unified(12345);
Adafruit_BMP085_Unified Altimeter = Adafruit_BMP085_Unified(10085);
//Temperature sensor - LM35
#define TempPin A0

//The file that we will write to - SD on SPI
//File Data;
//chip select pin for SPI for the SD card
const int CS = 4;

//Current build of the code - Major.Minor.Revision
const String CodeVersion = "0.0.3";
//Current hardware version - Major.Minor
const String HardVersion = "0.1";

//Variables to store the elapsed time for stopping the recording
unsigned long previousMillis = 0;
long interval = 10000; //ten seconds

void setup()
{
  Serial.begin(9600);
  Serial.println(F("-------------------------"));
  Serial.println(F("Datalogger"));
  Serial.print(F("Hardware version: "));Serial.println(HardVersion);
  Serial.print(F("Software version: "));Serial.println(CodeVersion);
  Serial.println(F("-------------------------"));
  Serial.println(F(""));
  delay(1000);

  //Set up the peripheral devices
  SetupPeripherals();

  //Output sensor information to verify that they are working properly
  DisplaySensorDetails();
  Serial.println("");
  delay(1000);
}

void loop()
{

	

	Serial.println(F("Beginning logging data..."));
	int timesThrough =0;
	while (timesThrough<10)
	{
		Serial.print(F("Logging data: "));Serial.println(timesThrough);
		//The string to write to the file

		//Read the BMP's information
		/*sensors_event_t altEvent;
		Altimeter.getEvent(&altEvent);

		if (altEvent.pressure)
		{
			Data.print("Pressure:    ");
			Data.print(altEvent.pressure);
			Data.println(" hPa");

			float temperature;
			Altimeter.getTemperature(&temperature);
			Data.print("Temperature: ");
			Data.print(temperature);
			Data.println(" C");

			float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
			Data.print("Altitude:    "); 
			Data.print(Altimeter.pressureToAltitude(seaLevelPressure,
				altEvent.pressure,
				temperature)); 
			Serial.println(" m");
			Serial.println("");
		}
		else
		{
			Data.println("Sensor error");
		}*/

		//Read and log the accelerometer's information
		sensors_event_t accelEvent; 
		Accelerometer.getEvent(&accelEvent);

		
		File dataFile = SD.open("datalog.txt", FILE_WRITE);
		String dataString = "";

		if (dataFile)
		{
			char * s;
			dataString += ("X: "); dataString += dtostrf(accelEvent.acceleration.x,2,2,s); dataString +=("  ");
			dataString +=("Y: "); dataString +=dtostrf(accelEvent.acceleration.y,2,2,s); dataString +=("  ");
			dataString +=("Z: "); dataString +=dtostrf(accelEvent.acceleration.z,2,2,s); dataString +=("  ");dataString +=("m/s^2 ");

			dataFile.println(dataString);
			/*dataFile.print(("X: ")); dataFile.print(accelEvent.acceleration.x); dataFile.print(("  "));
			dataFile.print(("Y: ")); dataFile.print(accelEvent.acceleration.y); dataFile.print(("  "));
			dataFile.print(("Z: ")); dataFile.print(accelEvent.acceleration.z); dataFile.print(("  "));dataFile.println(("m/s^2 "));
			dataFile.close();*/
		}else
		{
			Serial.println("Error opening file");
		}
		Serial.print(F("X: ")); Serial.print(accelEvent.acceleration.x); Serial.print(F("  "));
		Serial.print(F("Y: ")); Serial.print(accelEvent.acceleration.y); Serial.print(F("  "));
		Serial.print(F("Z: ")); Serial.print(accelEvent.acceleration.z); Serial.print(F("  "));Serial.println(F("m/s^2 "));
		delay(1000); 
		timesThrough++;
	}
	Serial.println(F("Finished logging data."));
	delay(1000);
	exit(0);
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////                                          OTHER METHODS                                 ////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////

//Display details about teh sensors
void DisplaySensorDetails()
{
  sensor_t accelSensor;
  Accelerometer.getSensor(&accelSensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:        "); Serial.println(accelSensor.name);
  Serial.print  ("Driver Ver:    "); Serial.println(accelSensor.version);
  Serial.print  ("Unique ID:     "); Serial.println(accelSensor.sensor_id);
  Serial.print  ("Max Value:     "); Serial.print(accelSensor.max_value); Serial.println(" m/s^2");
  Serial.print  ("Min Value:     "); Serial.print(accelSensor.min_value); Serial.println(" m/s^2");
  Serial.print  ("Resolution:    "); Serial.print(accelSensor.resolution); Serial.println(" m/s^2");  
  Serial.print  ("Data Rate:     "); Serial.print(GetAccelDataRate()); Serial.println(" Hz");
  Serial.print  ("Data Range:    +/-"); Serial.print(GetAccelDataRange()); Serial.println("g");
  Serial.println("------------------------------------");
  Serial.println("");
  
  sensor_t bmpSensor;
  Altimeter.getSensor(&bmpSensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(bmpSensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(bmpSensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(bmpSensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(bmpSensor.max_value); Serial.println(" hPa");
  Serial.print  ("Min Value:    "); Serial.print(bmpSensor.min_value); Serial.println(" hPa");
  Serial.print  ("Resolution:   "); Serial.print(bmpSensor.resolution); Serial.println(" hPa");  
  Serial.println("------------------------------------");
  Serial.println("");
  
}

//Set up the sensors and teh SD card
void SetupPeripherals()
{
  //Initialize SD card
  Serial.println(F("Initializing data storage..."));
  pinMode(CS, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(10,HIGH);
  if(!SD.begin(CS))
  {
	  Serial.println(F("Problem initializing SD card - check that a card is inserted and that the wiring is correct!"));
	  while(1);
  }
  Serial.println(F("MicroSD storage initialized!"));
  //Set up the sensors
  Serial.println("Initializing sensors...");
  //Altimeter
  if(!Altimeter.begin())
  {
	  Serial.println("Problem initializing BMP180 Pressure Sensor - Check wiring or I2C Address!");
	  while(1);
  }
  Serial.println("BMP180 initialized!");
  //Accelerometer
  if(!Accelerometer.begin())
  {
	  Serial.println("Problem initializing ADXL345 Accelerometer - Check wiring or I2C address!");
	  while(1);
  }
  
  //Set accelerometer range to +/- 16g - should be sufficient for these purposes
  Accelerometer.setRange(ADXL345_RANGE_16_G);
  Accelerometer.setDataRate(ADXL345_DATARATE_3200_HZ);
  Serial.println("ADXL345 initialized!");

}

//returns the data rate of the accelerometer
int GetAccelDataRate()
{
	switch(Accelerometer.getDataRate())
  {
    case ADXL345_DATARATE_3200_HZ:
      return  3200; 
    case ADXL345_DATARATE_1600_HZ:
      return   1600; 
    case ADXL345_DATARATE_800_HZ:
      return   800; 
    case ADXL345_DATARATE_400_HZ:
      return   400; 
    case ADXL345_DATARATE_200_HZ:
      return   200; 
    case ADXL345_DATARATE_100_HZ:
      return   100; 
    case ADXL345_DATARATE_50_HZ:
      return   50; 
    case ADXL345_DATARATE_25_HZ:
      return   25; 
    case ADXL345_DATARATE_12_5_HZ:
      return   12.5; 
    case ADXL345_DATARATE_6_25HZ:
      return   6.25;
    case ADXL345_DATARATE_3_13_HZ:
      return   3.13;
    case ADXL345_DATARATE_1_56_HZ:
      return   1.56; 
    case ADXL345_DATARATE_0_78_HZ:
      return  0.78; 
    case ADXL345_DATARATE_0_39_HZ:
      return   0.39; 
    case ADXL345_DATARATE_0_20_HZ:
      return   0.20; 
    case ADXL345_DATARATE_0_10_HZ:
      return   0.10; 
    default:
      return   0; 
  }  
}

//Returns the range of the accelerometer
int GetAccelDataRange()
{
 switch(Accelerometer.getRange())
  {
    case ADXL345_RANGE_16_G:
      return  16 ; 
    case ADXL345_RANGE_8_G:
      return  8;
    case ADXL345_RANGE_4_G:
      return  4; 
    case ADXL345_RANGE_2_G:
      return  2; 
    default:
      return  0; 
  }  
}

The file is created properly, but nothing is written to it. I appreciate any insight this wonderful forum can give!

Thank you!

const String CodeVersion = "0.0.3";

Why do you need to wrap a string in a class? This pisses away memory uselessly.

		String dataString = "";

More useless wasting of precious memory. The data written to an SD card if buffered. Collecting all the data in a String or string or bucket makes no sense. Write the data when you have it, one piece at a time. When the buffer, managed by the SD class, gets full it will be committed to the file, and emptied.

I have noticed that it takes up a lot of memory; thank you for calling my intention to that.

But that is not my main question.

But that is not my main question.

If you nearly sever your arm in a chainsaw accident, and then go to the emergency room complaining about a hangnail, they are going to laugh at you. You post code that wastes resources to the extent that there may not be enough memory for the program to run without crashing, and we ARE going to expect you to deal with that FIRST. You may choose not to. And, that's fine. We may choose to no longer help you. And, that needs to be fine with you.

I have noticed that it takes up a lot of memory; thank you for calling my intention to that.

But that is not my main question.

It may not be your question but memory is your problem. I happen to have your sensors and tried your program.

Open fails since there is not enough memory. I added the following before open.

		Serial.println(FreeRam());
		File dataFile = SD.open("datalog.txt", FILE_WRITE);

It printed 248 so you have very little memory at this point.

SD.h uses dynamic memory in open to create the "File" which it returns. I added this print and find that malloc() will not allocate memory.

File::File(SdFile f, const char *n) {
  // oh man you are kidding me, new() doesnt exist? Ok we do it by hand!
  _file = (SdFile *)malloc(sizeof(SdFile)); 
  Serial.print('f');Serial.println((int)_file);

It prints "f0".

Beginning logging data...
Logging data: 0
248
f0
Error opening file

PaulS, I wish I had your persistence to campaign against use of String. I also wish dynamic memory had not been used in the SD.h wrapper for SdFat.

Sorry it has taken so long to reply; I've gotten busy.

Thanks for explaining how my abysmal usage of memory was affecting the SD card. I have removed all the references to String, however, I feel that I am still having some large issues with memory. Here is my current revised code:

#include <SD.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_ADXL345_U.h>
#include <SPI.h>

/*Sensors*/
//Accelerometer and altimeter on I2C
Adafruit_ADXL345_Unified Accelerometer = Adafruit_ADXL345_Unified(12345);
Adafruit_BMP085_Unified Altimeter = Adafruit_BMP085_Unified(10085);
//Temperature sensor - LM35
#define TempPin A0

//The file that we will write to - SD on SPI
//File Data;
//chip select pin for SPI for the SD card
const int CS = 4;


//Variables to store the elapsed time for stopping the recording
unsigned long previousMillis = 0;
long interval = 10000; //ten seconds

void setup()
{
  Serial.begin(9600);
  Serial.println(F("-------------------------"));
  Serial.println(F("Datalogger"));
  Serial.println(F("Hardware version: 0.0.4"));
  Serial.println(F("Software version: 0.1"));
  Serial.println(F("-------------------------"));
  Serial.println((""));
  delay(1000);

  //Set up the peripheral devices
  SetupPeripherals();

  //Output sensor information to verify that they are working properly
  DisplaySensorDetails();
  Serial.println("");
  delay(1000);
}

void loop()
{

	

	Serial.println(F("Beginning logging data..."));
	int timesThrough =0;
	while (timesThrough<10)
	{
		Serial.print(F("Logging data: "));Serial.println(timesThrough);
		
		//Open the file
		File dataFile = SD.open("datalog.txt", FILE_WRITE);

		if (dataFile)
		{

			//Read the BMP's information
			/*sensors_event_t altEvent;
			Altimeter.getEvent(&altEvent);

			if (altEvent.pressure)
			{
				dataFile.print("Pressure:    ");
				dataFile.print(altEvent.pressure);
				dataFile.println(" hPa");

				float temperature;
				Altimeter.getTemperature(&temperature);
				dataFile.print("Temperature: ");
				dataFile.print(temperature);
				dataFile.println(" C");

				float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
				dataFile.print("Altitude:    "); 
				dataFile.print(Altimeter.pressureToAltitude(seaLevelPressure,
					altEvent.pressure,
					temperature)); 
				dataFile.println(" m");
				dataFile.println("");
			}
			else
			{
				Serial.println("Sensor error");
			}*/

			//Read and print the accelerometer's information
			sensors_event_t accelEvent; 
			Accelerometer.getEvent(&accelEvent);

		

			dataFile.print(("X: ")); dataFile.print(accelEvent.acceleration.x); dataFile.print(("  "));
			dataFile.print(("Y: ")); dataFile.print(accelEvent.acceleration.y); dataFile.print(("  "));
			dataFile.print(("Z: ")); dataFile.print(accelEvent.acceleration.z); dataFile.print(("  "));dataFile.println(("m/s^2 "));
			dataFile.close();
		}else
		{
			Serial.println("Error opening file");
		}
		
		delay(1000); 
		timesThrough++;
	}
	Serial.println(F("Finished logging data."));
	delay(1000);
	exit(0);
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////                                          OTHER METHODS                                 ////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////

//Display details about teh sensors
void DisplaySensorDetails()
{
  sensor_t accelSensor;
  Accelerometer.getSensor(&accelSensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:        "); Serial.println(accelSensor.name);
  Serial.print  ("Driver Ver:    "); Serial.println(accelSensor.version);
  Serial.print  ("Unique ID:     "); Serial.println(accelSensor.sensor_id);
  Serial.print  ("Max Value:     "); Serial.print(accelSensor.max_value); Serial.println(" m/s^2");
  Serial.print  ("Min Value:     "); Serial.print(accelSensor.min_value); Serial.println(" m/s^2");
  Serial.print  ("Resolution:    "); Serial.print(accelSensor.resolution); Serial.println(" m/s^2");  
  Serial.print  ("Data Rate:     "); Serial.print(GetAccelDataRate()); Serial.println(" Hz");
  Serial.print  ("Data Range:    +/-"); Serial.print(GetAccelDataRange()); Serial.println("g");
  Serial.println("------------------------------------");
  Serial.println("");
  
  sensor_t bmpSensor;
  Altimeter.getSensor(&bmpSensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(bmpSensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(bmpSensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(bmpSensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(bmpSensor.max_value); Serial.println(" hPa");
  Serial.print  ("Min Value:    "); Serial.print(bmpSensor.min_value); Serial.println(" hPa");
  Serial.print  ("Resolution:   "); Serial.print(bmpSensor.resolution); Serial.println(" hPa");  
  Serial.println("------------------------------------");
  Serial.println("");
  
}

//Set up the sensors and teh SD card
void SetupPeripherals()
{
  //Initialize SD card
  Serial.println(F("Initializing data storage..."));
  pinMode(CS, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(10,HIGH);
  if(!SD.begin(CS))
  {
	  Serial.println(F("Problem initializing SD card - check that a card is inserted and that the wiring is correct!"));
	  while(1);
  }
  Serial.println(F("MicroSD storage initialized!"));
  //Set up the sensors
  Serial.println("Initializing sensors...");
  //Altimeter
  if(!Altimeter.begin())
  {
	  Serial.println("Problem initializing BMP180 Pressure Sensor - Check wiring or I2C Address!");
	  while(1);
  }
  Serial.println("BMP180 initialized!");
  //Accelerometer
  if(!Accelerometer.begin())
  {
	  Serial.println("Problem initializing ADXL345 Accelerometer - Check wiring or I2C address!");
	  while(1);
  }
  
  //Set accelerometer range to +/- 16g - should be sufficient for these purposes
  Accelerometer.setRange(ADXL345_RANGE_16_G);
  Accelerometer.setDataRate(ADXL345_DATARATE_3200_HZ);
  Serial.println("ADXL345 initialized!");

}

//returns the data rate of the accelerometer
int GetAccelDataRate()
{
	switch(Accelerometer.getDataRate())
  {
    case ADXL345_DATARATE_3200_HZ:
      return  3200; 
    case ADXL345_DATARATE_1600_HZ:
      return   1600; 
    case ADXL345_DATARATE_800_HZ:
      return   800; 
    case ADXL345_DATARATE_400_HZ:
      return   400; 
    case ADXL345_DATARATE_200_HZ:
      return   200; 
    case ADXL345_DATARATE_100_HZ:
      return   100; 
    case ADXL345_DATARATE_50_HZ:
      return   50; 
    case ADXL345_DATARATE_25_HZ:
      return   25; 
    case ADXL345_DATARATE_12_5_HZ:
      return   12.5; 
    case ADXL345_DATARATE_6_25HZ:
      return   6.25;
    case ADXL345_DATARATE_3_13_HZ:
      return   3.13;
    case ADXL345_DATARATE_1_56_HZ:
      return   1.56; 
    case ADXL345_DATARATE_0_78_HZ:
      return  0.78; 
    case ADXL345_DATARATE_0_39_HZ:
      return   0.39; 
    case ADXL345_DATARATE_0_20_HZ:
      return   0.20; 
    case ADXL345_DATARATE_0_10_HZ:
      return   0.10; 
    default:
      return   0; 
  }  
}

//Returns the range of the accelerometer
int GetAccelDataRange()
{
 switch(Accelerometer.getRange())
  {
    case ADXL345_RANGE_16_G:
      return  16 ; 
    case ADXL345_RANGE_8_G:
      return  8;
    case ADXL345_RANGE_4_G:
      return  4; 
    case ADXL345_RANGE_2_G:
      return  2; 
    default:
      return  0; 
  }  
}

If I uncomment the part in loop() that logs the BMP's sensor value, the program crashes again, looping through bits of the program almost at random. I've researched this issue a little bit and it seems to still be a memory issue - I was told to use the F() macro on all of my print statements and as you can see, I have, but that hasn't helped measurably.

You need to use the F() macro around every quoted string in print/println calls. like these:

 Serial.println("------------------------------------");
  Serial.print  ("Sensor:        "); Serial.println(accelSensor.name);
  Serial.print  ("Driver Ver:    "); Serial.println(accelSensor.version);
  Serial.print  ("Unique ID:     "); Serial.println(accelSensor.sensor_id);
  Serial.print  ("Max Value:     "); Serial.print(accelSensor.max_value); Serial.println(" m/s^2");
  Serial.print  ("Min Value:     "); Serial.print(accelSensor.min_value); Serial.println(" m/s^2");
  Serial.print  ("Resolution:    "); Serial.print(accelSensor.resolution); Serial.println(" m/s^2");  
  Serial.print  ("Data Rate:     "); Serial.print(GetAccelDataRate()); Serial.println(" Hz");
  Serial.print  ("Data Range:    +/-"); Serial.print(GetAccelDataRange()); Serial.println("g");
  Serial.println("------------------------------------");
  Serial.println("");
   ...
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(bmpSensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(bmpSensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(bmpSensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(bmpSensor.max_value); Serial.println(" hPa");
  Serial.print  ("Min Value:    "); Serial.print(bmpSensor.min_value); Serial.println(" hPa");
  Serial.print  ("Resolution:   "); Serial.print(bmpSensor.resolution); Serial.println(" hPa");  
  Serial.println("------------------------------------");
  Serial.println("");

Then add the FreeRam line here.

		//Open the file
		File dataFile = SD.open("datalog.txt", FILE_WRITE);
                Serial.print(F("FreeRam: "));Serial.println(FreeRam());

You need at least 300-400 bytes free at this point.

Great, thanks. I F() macroed almost every line in quotes, even the print statements to the file, and it works now with 728 bytes free, which is good, because I plan to expand it extensively. Thank you!

fat16lib:
It may not be your question but memory is your problem. I happen to have your sensors and tried your program.

Open fails since there is not enough memory. I added the following before open.

		Serial.println(FreeRam());
	File dataFile = SD.open("datalog.txt", FILE_WRITE);


It printed 248 so you have very little memory at this point.

SD.h uses dynamic memory in open to create the "File" which it returns. I added this print and find that malloc() will not allocate memory.



File::File(SdFile f, const char *n) {
  // oh man you are kidding me, new() doesnt exist? Ok we do it by hand!
  _file = (SdFile *)malloc(sizeof(SdFile));
  Serial.print('f');Serial.println((int)_file);




It prints "f0".
PaulS, I wish I had your persistence to campaign against use of String. I also wish dynamic memory had not been used in the SD.h wrapper for SdFat.

yes you are correct. I am also facing same issue. I checked with Serial.println(FreeRam()); and it is showing 293. So wht should I do to fix this problem? Please help...

Kumkum23:
yes you are correct. I am also facing same issue. I checked with Serial.println(FreeRam()); and it is showing 293. So wht should I do to fix this problem? Please help...

Posting your code would be a start. Telling us which board you're using could also be of help.