Problem with SD.open() ?

Hi all,
I am new to Arduino, but I plan to make a datalogger from it.
But I have encountered a problem while testing the SD card …

#include <SPI.h>
#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4;
int x=0;
File myFile1;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("\nInitializing SD card...");
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    while (1);
  } else {
    Serial.println("Wiring is correct and a card is present.");
  }
  Serial.println();
  Serial.print("Card type:         ");
  switch (card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    while (1);
  }
  Serial.print("Clusters:          ");
  Serial.println(volume.clusterCount());
  Serial.print("Blocks x Cluster:  ");
  Serial.println(volume.blocksPerCluster());
  Serial.print("Total Blocks:      ");
  Serial.println(volume.blocksPerCluster() * volume.clusterCount());
  Serial.println();
  uint32_t volumesize;
  Serial.print("Volume type is:    FAT");
  Serial.println(volume.fatType(), DEC);
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize /= 2;                           // SD card blocks are always 512 bytes (2 blocks are 1KB)
  Serial.print("Volume size (Kb):  ");
  Serial.println(volumesize);
  Serial.print("Volume size (Mb):  ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Gb):  ");
  Serial.println((float)volumesize / 1024.0);
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
  root.ls(LS_R | LS_DATE | LS_SIZE);
  SD.begin(chipSelect);
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}

void loop() {
  x++;
  myFile1=SD.open("example.txt", FILE_WRITE);
  if (myFile1) {
    Serial.println(x);
  }
}

The setup part is the card info from the Arduino library, but during the loop() myFile1 was true only for the first few loops (see below for the serial monitor prints) … what might be a problem…?

Initializing SD card…Wiring is correct and a card is present.

Card type: SDHC
Clusters: 244192
Blocks x Cluster: 64
Total Blocks: 15628288

Volume type is: FAT32
Volume size (Kb): 7814144
Volume size (Mb): 7631
Volume size (Gb): 7.45

Files found on the card (name, date and size in bytes):
EXAMPLE.TXT 2000-01-01 01:00:00 0
initialization done.
1
2
3
4
5
6
7

myFile1 was no longer true after x>7 … why? Appreciate any help!!!

Possibly because you fail to close the file before reopening it? Only one file open at a time according to the SD library. Not sure why it iterates to 7 before failing. I would have expected it to fail on the second loop.

Possibly because you fail to close the file before reopening it? Only one file open at a time according to the SD library. Not sure why it iterates to 7 before failing. I would have expected it to fail on the second loop.

As of version 1.0, the library does support opening multiple files. The problem is that each time a file is opened a 512 byte buffer is created. You are running out of memory in your test sketch and crashing the program.

cattledog: time a file is opened a 512 byte buffer is created.

Wrong. A File object takes around 30 bytes, it does not create any buffer other than its name. The only 512-byte buffer (which is actually a cache) resides in the "volume and filesystem manager" part of the library (which lies inside the SD object), and it's shared to all File instances.

If that were true, you could at most have opened 3 files at once before running out of memory (if the MCU has 2 KB of RAM).

cattledog: You are running out of memory in your test sketch and crashing the program.

However, I agree with you here. Once I've wrote a quick file lister that prints, to the serial port, all the names of all the files contained in a specific folder; but it stopped working exactly at the 11th file. After some headaches and asking to this forum, I've realized that for some reason I thought openNextFile() created auto-closable File objects; and thus forgetting to manually close the file at the end of the loop.

Apparently, unclosed stray File objects do cause "memory leaks"; because after adding the close() function in my sketch, it began to work fine. Taking a look at the source code, I know why; but in a nutshell it's for two reasons:

  • It lacks of a destructor function.
  • In one of its constructors, it allocates memory (malloc()) that gets deallocated only when close() is called at least once. If an object allocates memory with malloc(), it won't be implicitly deallocated when that object is discarded; the solution would be to actually implement a destructor that does it explicitly (i.e. calls free()).

I don't know if calling that an oversight or an annoying bug, but in any case ALWAYS CLOSE A FILE AS SOON AS IS NO LONGER NEEDED!

Hello,

I would like to line up with the SD open...

First of all I am laic and I am making small steps with the Arduino and ESP base on my free time possibilities. I can not read the lib (but I am trying).

I am using the ESP32 DevKit and SD library from Arduino and Sparkfun (I tried all well known SD libs and this seems to me as the easiest one to use). Unfortunatelly, the behavior is strange to me. I am trying to log some datas to the file, unfortunatelly it overwrites the first line everytime (there is always the latest value).

I didn't find any open or related topic except this one: link to related topic Proposed solution has been tried, no improvement so far.

I tried to replace the parameter "FILE_WRITE" to some "O_READ l O_WRITE l...", but this would mean from my point of view to transfer the string to char, and this is for me very complicated, frankly said, I do not know, if this is the only point.

The libraries are included in another "tab" also the variable declaration.

Can you please tell me, what am I doinf wrong or advice how to debug this issue?

Thank you in advance for your time and patience.

Code:

[code]
void setup_SD() {
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(5)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  Serial.println(SD.exists("/logs"));
  if(SD.exists("/logs")==0)
  {
    SD.mkdir("/logs");
  }
      filename=("/logs/logAirTemp" + myTZ.dateTime("my") + ".txt");
    logAirTemp = SD.open(FILE_WRITE);
    logAirTemp.close();
    filename=("/logs/logWaterTemp" + myTZ.dateTime("my") + ".txt");
    logWaterTemp = SD.open(filename, FILE_WRITE);
    logWaterTemp.close();
    filename=("/logs/logCoreTemp" + myTZ.dateTime("my") + ".txt");
    logCoreTemp = SD.open(filename, FILE_WRITE);
    logCoreTemp.close();
    filename=("/logs/logReboot" + myTZ.dateTime("my") + ".txt");
    logReboot = SD.open(filename, FILE_WRITE);
    logReboot.close();
}

void log_coreTemp()
{
    filename=("/logs/logCoreTemp" + dateTime("my") + ".txt");
    logCoreTemp = SD.open(filename, FILE_WRITE);
    logCoreTemp.println(myTZ.dateTime("y.n.Y") + ", " + myTZ.dateTime("G:i:s") + ", " + temperatureRead());
    //logCoreTemp.write(myTZ.dateTime("y.n.Y") + ", " + myTZ.dateTime("G:i:s") + ", " + temperatureRead() + "/n");
    Serial.println(myTZ.dateTime("y.n.Y") + ", " + myTZ.dateTime("G:i:s") + ", " + temperatureRead());
    logCoreTemp.close(); 
}

[/code]