SD Card - Read available space?

I have the WiFi Shield with a 2 GB micro SD card in it. I am very pleased with writing to and reading from the SD card.

However I would like to be able to read how much space is available on the SD card before writing to it or to display / send that information elsewhere.

I went through the library functions and couldn't find anything that does this.

How can I read the amount of available space on the SD card?

Thanks!

You can use the Cardinfo example to see how to determine the total card size. Look in SD/utility/SDvolume::allocContiguous to see how it searches for available clusters to allocate. I don't think it keeps a count of free or allocated clusters so you will have to go through every cluster and count the free ones.

Thank you for your quick reply.

I should have mentioned that I had already successfully tested the card size functionality. I was hoping there was a simple library function call to get the amount of free space on the card...

Another, very kludgy workaround, would be to take the total card size and loop through all of the stored files subtracting their current size from the total size. That would give an indication of how much size is left. That's definitely NOT what I am looking for... especially, as I think of it, as it would have to recurse through folders and subfolders as well!

Thanks...

You could add something like this to the SdVolume object:

// Count the number of free clusters
uint8_t SdVolume::freeSpace() {
  uint32_t freeCount = 0;

  // search the FAT for free clusters
  for (uint32_t cluster = 2;  cluster < clusterCount_; cluster++) {
    uint32_t f;
    if (!fatGet(endCluster, &f)) 
        return 0;

    if (f == 0) 
        freeCount++;
    }

  return freeCount;
}

SD.h is a wrapper for an old version of SdFat and does not have a free space function.

Newer versions of SdFat have a free clusters function which gives free space. Here is an example sketch:

#include <SdFat.h>
SdFat sd;
const uint8_t csPin = SS;
void setup() {
  Serial.begin(9600);
  if (!sd.begin(csPin)) sd.initErrorHalt();
  uint32_t freeKB = sd.vol()->freeClusterCount();
  freeKB *= sd.vol()->blocksPerCluster()/2;
  Serial.print("Free space KB: ");
  Serial.println(freeKB);
}
void loop() {}

Here is what it prints for 2GB and 8GB cards where KB is 1024 bytes:

Free space KB: 1949504
Free space KB: 7733952

Note that uint32_t is too small for free byte count for cards larger than 4GB.

Note that uint32_t is too small for free byte count for cards larger than 4GB.

I just went through the Arduino data types. The two biggest highest max values I found are unsigned int and unsigned long which both have a max value of approximately 4 GB.

What data type does one use for calculations requiring values greater than 4 GB?

I have 8 GB, 16 GB and 32 GB SD cards and I assume I am not alone.

Thanks!

You could add something like this to the SdVolume object:

Where would I find the SdVolume object to work with?

I am on day 4 or 5 with my first Arduino so still finding out all about the various programming structures...

I naïvely thought I might be able to at least use the SdFile.ls() function, as it recurses through all files and folders on the card, and deduct each file size from the total size to give a file-based free size amount. Then I realised I have no idea where any of these undocumented classes from the SD.H library (Sd2Card, SdVolume and SdFile) are...

I assume this, relatively basic, free / available space functionality will be added to an upgraded version of the sd.h library?

Thanks for all the info and assistance!

Then I realised I have no idea where any of these undocumented classes from the SD.H library (Sd2Card, SdVolume and SdFile) are...

You missed the point where fat16lib told you that you needed to download and install a different library, apparently. Those classes are not part of SD.

Paul,

From what I understand, which is obviously less than I think, all of the classes I mentioned (Sd2Card, SdVolume and SdFile) must be part of the SD.H library. They are used in the classic tutorial example of getting card info:

That sketch doesn't seem to include any library other than SD.H...

My sketch calculates the free space in KB. I added this note since several people have tried to calculate the free space in bytes.

Note that uint32_t is too small for free byte count for cards larger than 4GB.

If you multiply the free space in KB by 1024 a uint32_t will give the wrong answer in bytes if the free space is larger than 4 GB.

Notice that I calculated the free space for an 8GB card in KB.

Free space KB: 7733952

The standard SD.h library will not work with the example sketch. SD.h uses a very old version of SdFat.

You need to use a newer version of SdFat located here Google Code Archive - Long-term storage for Google Code Project Hosting..

I have finally gotten back to this...

I have installed the SdFat library and have been having fun seeing what I can do with it.

I got a FreeSpace function up and running very quickly. I then found a TimeStamp function in the library examples and that was something I was really looking for so I played around with that, for way too long, and can now set file creation, modification and accessed datetime stamps.

I went back to my file I/O operations and played with opening, writing to and closing my files with the new library. That works fine.

However all of this leads me to 2 questions:

How can I read/display the size of my file?
With the SD library I would probably use the ls object with a LS_SIZE call. But how do I do this for my individual file object?

How do I recalculate the FreeSpace as I get the feeling it's showing me cached info or something.

In my loop() I read the free space, write a line to my file wait 10 seconds and do it all again. The amount of free space never changes although I can see, afterwards, that my lines are being properly appended to my file and its size is getting bigger and bigger.

What I would like to do is:

loop{
ShowFreeSpace();
WriteLineToFile();
ShowFileSize();
delay(10000);
}

That ShowFreeSpace() function currently returns the same value each time.
WriteLineToFile() works fine
ShowFileSize() I don't know how to do

Once I can learn these 2 points my next step will be getting date and time from an NTP server and using that to datetime stamp my files.

Thanks!

You are not going to see free space on the SD change unless a new cluster is allocated to a file. That's why Sdfat has the function freeClusterCount(), which returns how many allocation units are available on the SD.

This example:

#include <SdFat.h>
SdFat sd;
SdFile file;
const uint8_t csPin = SS;
void setup() {
  Serial.begin(9600);
  if (!sd.begin(csPin) || !file.open("TEST.TXT", O_WRITE | O_CREAT | O_TRUNC)) {
    Serial.println("SD problem");
  }
  Serial.print("Cluster Size: ");
  Serial.println(512L*sd.vol()->blocksPerCluster());
}
void loop() {
  Serial.print("FreeClusters: ");
  Serial.print(sd.vol()->freeClusterCount());
  Serial.print(", File size: ");
  Serial.println(file.fileSize());
  file.println("A line to add bytes to the file");
  // force write of data to SD
  file.sync();
}

Prints this:

Cluster Size: 32768
FreeClusters: 242242, File size: 0
FreeClusters: 242241, File size: 33
FreeClusters: 242241, File size: 66
FreeClusters: 242241, File size: 99
FreeClusters: 242241, File size: 132
FreeClusters: 242241, File size: 165
FreeClusters: 242241, File size: 198
FreeClusters: 242241, File size: 231

Notice that the free cluster count decreased by one after the first write and then didn't change. This is because one cluster of 32768 bytes was allocated to the file on the first write. The cluster count won't decrease until the file is larger than 32768 bytes an then another cluster will be allocated..

Wow! Thank you for your prompt and oh so helpful reply. The most important info I needed was the fact that I wasn't going to see a change in the free space until another cluster was allocated to the file. My code was therefore actually already working from that point of view...

The simple fileSize() call was also the simple answer to what I needed. I had tried without the uppercase S...

I have removed the timestamp stuff from my code, for brevity here, it does just what I want it to...

[I got bored waiting for that new cluster to appear so I made it write 100 lines at a time and reduced the delay to 10 seconds)

#include <SdFat.h>

// Arduino Ethernet Shield = pin 4
const int iSDPin = 4;

// Global card and file variables
SdFat sd;
SdFile file;
char strFname[] = "WRITETST.TXT";  // File name

int i = 1;  // Global counter

//
// Display space available on SD card
//

void ShowFreeSpace() {
  // Calculate free space (volume free clusters * blocks per clusters / 2)
  long lFreeKB = sd.vol()->freeClusterCount();
  lFreeKB *= sd.vol()->blocksPerCluster()/2;

  // Display free space
  Serial.print("Free space: ");
  Serial.print(lFreeKB);
  Serial.println(" KB");
}

void setup(void) {
  // Setup serial monitor
  Serial.begin(9600);
  // Wait 3 seconds
  delay(3000);
  // Some declaring text
  Serial.println("\nSD Card - SD Fat Library - File date-time stamp testing");
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!sd.begin(iSDPin, SPI_HALF_SPEED))
    sd.initErrorHalt();

  // remove files if they exist
  sd.remove(strFname);
}

void loop(void){
  
  Serial.println("\nReading free space...");
  ShowFreeSpace();

  // Open file for writing (appending)
  if (!file.open(strFname, O_CREAT | O_WRITE | O_AT_END)) {
    Serial.print("ERROR : open ");
    Serial.print(strFname);
    Serial.print(" failed");
  }
  // Write to file ... 100 lines
  Serial.print("\nWriting to the file...\tLine : ");
  Serial.println(i+=100);
  for (int j = 0; j < 100; j++) {
    file.print("\"FILE WRITE TEST\",1234");
    file.print(i);
    file.println(",\"LINE WRITTEN\",\"ARDUINO FILE TIMESTAMP TESTING\"");
  }
  file.close();
  Serial.print("File Size :\t");
  Serial.print(file.fileSize());
  Serial.println(" b");
  
  // Wait 10 seconds  
  Serial.println("Waiting 10 seconds...");
  delay(10000);
}

Thank You for all of your help!

johnwasser:
You could add something like this to the SdVolume object:

// Count the number of free clusters

uint8_t SdVolume::freeSpace() {
 uint32_t freeCount = 0;

// search the FAT for free clusters
 for (uint32_t cluster = 2;  cluster < clusterCount_; cluster++) {
   uint32_t f;
   if (!fatGet(endCluster, &f))
       return 0;

if (f == 0)
       freeCount++;
   }

return freeCount;
}

Oh, really old topic, just saw it now! :smiley:

But, please, tell me, where I need to put that part of the code?