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?
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.
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!
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.
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?
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.
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...
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.
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();
}
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);
}