Go Down

Topic: SD Card - Read available space? (Read 3561 times) previous topic - next topic

DerekErb

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!

johnwasser

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.
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

DerekErb

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...

johnwasser

You could add something like this to the SdVolume object:
Code: [Select]

// 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;
}
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

fat16lib

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:

Code: [Select]

#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:
Quote

Free space KB: 1949504
Free space KB: 7733952

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

DerekErb

Quote

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!

DerekErb

Quote

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!

PaulS

Quote
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.

DerekErb

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:

http://arduino.cc/en/Tutorial/CardInfo

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

fat16lib

My sketch calculates the free space in KB.  I added this note since several people have tried to calculate the free space in bytes.
Quote
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.
Quote
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 http://code.google.com/p/sdfatlib/downloads/list.

DerekErb

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!

fat16lib

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:
Code: [Select]

#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:
Quote

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..

DerekErb

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)

Code: [Select]

#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!

Go Up