Skip to main content

SD Card

In this example, we will check if a file exists on the SD Card, create a new file if not and read and write from that file. First, to use the SDCard, we need to include the SdFat.h header and the instantiate the sd class and, then run sd.begin() to initialize the sd card. Additionally, we will use the now() time function, so we will include the TimeLib.h header file as well:

#include "TimeLib.h"
#include "SdFat.h"

SdFs sd;

void setup() {
sd.begin();
}

But to make this program more robust, we should check if the sd.begin() function was successful and only proceed if it was.

#include "TimeLib.h"
#include "SdFat.h"
SdFs sd;

void setup() {
while (sd.begin() == false) {
//Sd card failed, wait and try again
delay(1000); //wait 1000ms or 1 sec
Serial.println("Unable to connect to SD Card, was it inserted?");
}
Serial.println("Successfully connected to SD card.");
}

That this point, we can use various sd functions such as:

  • open(filename)
  • exists(filename)
  • remove(filename)
  • mkdir(dirname)
  • chdir(dirname)
  • rmdir(dirname)
  • ls()

The next step is to write some functions to use the SD card. Here's a function to see if a file exists, and if so print the filesize:

char filename[] = "Data.dat";
void readFile(void) {
if (sd.exists(filename)) {
FsFile file = sd.open(filename,O_RDONLY); //open the file read-only
Serial.printf("File %s exists with size %u\n",filename,file.fileSize());
file.close();
} else {
Serial.printf("File %s is missing!\n",filename);
}
}

When using the open function, there are a few flags to set how the file will be opened:

  • O_RDONLY    // Open file read-only. This is the default and does not need to be used
  • O_WRONLY   // Open file for writing only
  • O_RDWF    // Open file for reading and writing
  • O_APPEND   // Append to file (otherwise writes start at start of file)
  • O_CREAT   // Create new file (if it does not already exist)

If we want to read the data in a file and print out its contents, we can use this expanded readFile() function:

char filename[] = "Data.dat";
void readFile(void) {
char filedata[2000]; //temporary place to store contents of the file
if (sd.exists(filename)) {
FsFile file = sd.open(filename,O_RDONLY); //open the file read only
uint64_t fileSize = file.fileSize(); //get the file size
Serial.printf("File %s exists with size %u\n",filename,fileSize);
uint64_t openSize = min(fileSize-1,sizeof(filedata)); //prevent overflow if file larger than buffer to store it
file.read(filedata,openSize); //read the entire file into filedata array
Serial.println(" ** Data Contents Start **");
filedata[openSize] = '\0'; //Terminate data so we can print as string
Serial.print(filedata);
Serial.println("\n ** Data Contents End **");
file.close();
} else {
Serial.printf("File %s is missing!\n",filename);
}
}

To write to a file and append data to it, we have:

void writeFile(void) {
char message[500];
FsFile file;
static uint count = 1;
file = sd.open(filename,O_RDWR | O_CREAT | O_APPEND);
if (file) {
uint nowTime = (uint) now();
uint charsWritten = sprintf(message,"%u Write number %u\n",nowTime,count); //Prepare string to write to file
count++; //keep track of how many times we have written to the file
file.write(message,charsWritten); //write to file
file.close(); // close file now that write is done
} else {
Serial.println("Error opening Data.txt file.");
sd.errorPrint(&Serial);
return;
}
}

And finally, if we want to erase the file, we have:

void eraseFile(void) {
if (sd.exists(filename)) {
sd.remove(filename);
}
}

Putting this together, if we put into our setup function:

void setup() {
while (sd.begin() == false) {
//Sd card failed, wait and try again
delay(1000); //wait 1000ms or 1 sec
Serial.println("Unable to connect to SD Card, was it inserted?");
}
Serial.println("Successfully connected to SD card.");
eraseFile(); //erase file
readFile(); //try to read when no file exists
writeFile(); //write to file for first time
readFile(); //read file
delay(2000); //wait 2 seconds
writeFile(); // write to file a second time
readFile(); //read file
delay(2000); //wait 2 seconds
writeFile(); //write to file a third time
readFile(); //read file
}

Running this will return:

Unable to connect to SD Card, is it inserted?
Successfully connected to SD card.
File Data.txt is missing!
File Data.txt exists with size 26
** Data Contents Start **
1653512729 Write number 1
** Data Contents End **
File Data.txt exists with size 52
** Data Contents Start **
1653512729 Write number 1
1653512731 Write number 2
** Data Contents End **
File Data.txt exists with size 78
** Data Contents Start **
1653512729 Write number 1
1653512731 Write number 2
1653512733 Write number 3
** Data Contents End **

When the SD Card is first inserted, the Data.dat file is deleted and readFile() reports the file is missing. Then writeFile() writes the first line and readFile() reports 26 bytes written. When writeFile() is called a second time, it appends another 26 bytes to the file, adding a new line with a new timestamp. When readFile() is subsequently called, it sees 52 bytes and two lines.

The full file is available in Examples, Examples for Quarto, SD, BasicReadWriteDelete or below:

#include "TimeLib.h"
#include "SdFat.h"

SdFs sd;
char filename[] = "Data.dat";

void setup() {
while (sd.begin() == false) {
//Sd card failed, wait and try again
delay(1000); //wait 1000ms or 1 sec
Serial.println("Unable to connect to SD Card, was it inserted?");
}

Serial.println("Successfully connected to SD card.");
eraseFile(); //erase file
readFile(); //try to read when no file exists
writeFile(); //write to file for first time
readFile(); //read file
delay(2000); //wait 2 seconds
writeFile(); // write to file a second time
readFile(); //read file
delay(2000); //wait 2 seconds
writeFile(); //write to file a third time
readFile(); //read file

}

void readFile(void) {
char filedata[2000]; //temporary place to store contents of the file
if (sd.exists(filename)) {
FsFile file = sd.open(filename,O_RDONLY); //open the file read only
uint64_t fileSize = file.fileSize(); //get the file size
Serial.printf("File %s exists with size %u\n",filename,fileSize);
uint64_t openSize = min(fileSize-1,sizeof(filedata)); //prevent overflow if file larger than buffer to store it
file.read(filedata,openSize); //read the entire file into filedata array
Serial.println(" ** Data Contents Start **");
filedata[openSize] = '\0'; //Terminate data so we can print as string
Serial.print(filedata);
Serial.println("\n ** Data Contents End **");
file.close();
} else {
Serial.printf("File %s is missing!\n",filename);
}
}

void writeFile(void) {
char message[500];
FsFile file;
static uint count = 1;
file = sd.open(filename,O_RDWR | O_CREAT | O_APPEND);
if (file) {
uint nowTime = (uint) now();
uint charsWritten = sprintf(message,"%u Write number %u\n",nowTime,count); //Prepare string to write to file
count++; //keep track of how many times we have written to the file
file.write(message,charsWritten); //write to file
file.close(); // close file now that write is done
} else {
Serial.println("Error opening Data.txt file.");
sd.errorPrint(&Serial);
return;
}
}

void eraseFile(void) {
if (sd.exists(filename)) {
sd.remove(filename);
}
}

void loop() {
static unsigned long lastrun = 0;
if (millis() > lastrun) { //Run once every 1000ms
lastrun = millis() + 1000;
toggleLEDBlue();
}
}