SD.h library

Hi,

Just starting to use the SD.h library to access an SD card. I tried the example printDirectory code that gives a directory listing but it does not work. There is no way for it to leave the while(true) loop. I added a break clause when it reaches the last file, and the function works now, sort of.

If you try calling the function repeatedly it only works once. It’s as if there is some persistent data that is corrupting something when it is called a second time. I tried adding rewindDirectory() to the start of the function to make sure it starts from the beginning each time it is called but this doesn’t help. I also notice that the function opens another instance of the File object while the initial File object is still open. The printDirectory code seems to be logical so is there a problem with the library?

Here is the code, you can see that the printDirectory() function is called 3 times.

#include <SD.h>

File root;

void setup()
{
  Serial.begin(9600);
  pinMode(10, OUTPUT);

  SD.begin(4);

  root = SD.open("/");

  printDirectory(root, 0);
  root.rewindDirectory();
  printDirectory(root, 0);
  root.rewindDirectory();
  printDirectory(root, 0);
  root.rewindDirectory();
  
  Serial.println("done!");
}

void loop()
{
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
   while(true) {

     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       Serial.println("**nomorefiles**");
       entry.rewindDirectory();
       entry.close();
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');
     }
     Serial.print(entry.name());
     if (entry.isDirectory()) {
       Serial.println("/");
       printDirectory(entry, numTabs+1);
     } else {
       // files have sizes, directories do not
       Serial.print("\t\t");
       Serial.println(entry.size(), DEC);
     }
   }
}

My SD card has nine files on it and one subdirectory with the same nine files in that. The output of the code is :

001.TXT		33
002.TXT		15
003.TXT		15
004.TXT		13
005.TXT		15
006.TXT		15
007.TXT		15
008.TXT		15
009.TXT		185
NEWFOL~2/
	006.TXT		15
	007.TXT		15
	008.TXT		15
	009.TXT		185
	001.TXT		33
	002.TXT		15
	003.TXT		15
	004.TXT		13
	005.TXT		15
**nomorefiles**
**nomorefiles**
001.TXT		33
002.TXT		15
003.TXT		15
**nomorefiles**
**nomorefiles**
done!

You can see that the first time the function is called the files in the root are listed correctly. The second time it is called it prints nothing, the third time it prints only the first 3 files …

Any suggestions?

How does the SDfat library compare to this that ships with arduino?

Thanks.

SD.h is old and buggy. It is a wrapper for an old version of SdFat that I wrote in 2009.

You added a bug to the example that caused a memory leak so it is now really broken.

       Serial.println(entry.size(), DEC);
     }
     entry.close();  <-------- Don't remove this, it frees memory.
   }

The example stopped listing files when free memory was exhausted.

You don’t need these but they won’t hurt.

       // no more files
       Serial.println("**nomorefiles**");
       entry.rewindDirectory();  <--------------- Not needed
       entry.close();  <-------------------------  Not needed, the file didn't open so there is no memory.
       break;

This is what was listed on the first call. Files are not sorted so it is correct.

001.TXT 33
002.TXT 15
003.TXT 15
004.TXT 13
005.TXT 15
006.TXT 15
007.TXT 15
008.TXT 15
009.TXT 185
NEWFOL~2/
006.TXT 15
007.TXT 15
008.TXT 15
009.TXT 185
001.TXT 33
002.TXT 15
003.TXT 15
004.TXT 13
005.TXT 15
nomorefiles
nomorefiles

Here is where you ran out of memory on the second call.

001.TXT 33
002.TXT 15
003.TXT 15
nomorefiles <------------------ Memory gone

Here is the third call, no memory so no list.

nomorefiles

SdFat does not use dynamic memory. This happen due to poor design of the SD.h wrapper which allocates memory when you open a file and frees it when you close a file.

I just posted a new version of SdFat http://forum.arduino.cc/index.php?topic=259317.0. It has an ls() function so you don’t need to write a list files function. Download it and look at the examples. It’s far more complex than SD.h, that’s why the Arduino company wrote the SD.h wrapper to reduce the number of API functions.

Hmm, the example given didn't include that entry.close() line, I didn't remove it. I've put it in and it works now.

I think I'll forget about the wrapper and just use your library. Thanks for the hard work.