SD Card Tutorial for Arduino, ESP8266 and ESP32

In this tutorial you learn how to use the SD card module in combination with your Arduino, ESP8266 and ESP32 microcontroller board.

We create a temperature logger where we store the time from a real-time clock module, the temperature and humidity to a micro SD card.

SD Card Tutorial Thumbnail

Table of Contents

In my projects I like to transfer data wireless via MQTT to a central database, that is normally on a Raspberry Pi. But what if there is no WiFi available like in the garden? In this case we have to save the data to the SD card, because the internal memory of the microcontroller is only some megabyte. Moreover the internal memory of the microcontroller is harder to access and can be lost during a power reset.

Different SD Card Modules and Shields for Microcontroller

There are different SD card modules and also an SD card shield developed by AZDelivery, called Data Logger Module. The SD card shield fits with all pins on an Arduino Uno. The following picture shows a SD card module for micro SD cards and the Arduino Uno shield.

SD Card Module and Arduino Uno Shield

If we take a look at the SD card module, we see that there are two electrical components on the board.

  • Voltage regulator: the SD card module has a build in voltage regulator, because SD cards work with a 3.3V logic. If you want to connect an Arduino microcontroller with an operation voltage of 5V, you need this voltage regulator to reduce the voltage from 5V to 3.3V.
  • Logic-level shifter: The voltage regulator reduces only the supply voltage but for the SPI communication, we need the level shifter to translate the signals between 5V and 3.3V. The SD card module uses the 74LVC125A as logic-level shifter.

More components are not needed because the SD card itself has a build in SPI interface. Therefore the SD card module does not have to supply this interface.

It is important that the SD card that you use is formatted as FAT16 or FAT32. Depending on the SD card module there is a limit of 32GB for the SD card. You find any limitations on the datasheet of your SD card module.

Wiring between SD Card Module and Microcontroller

The SD card modules are connected via SPI to the Arduino, ESP8266 or ESP32 microcontroller. Instead of the default Slave Select (SS) pin for each microcontroller, you can define another digital pin, but if the default pin is not used, the GPIO must be left empty as output for the SD library. The SPI communication ensures that the data is transferred as fast as possible. The Microcontroller Datasheet eBook gives you an overview of the SPI pins for all used Arduino, ESP8266 and ESP32 microcontroller boards in this article.

The following sub-chapter show how to wire the module to different Arduino, ESP8266 and ESP32 microcontroller boards. If your favorite board is missing, use the comment section below and I will add your board to this article.

Wiring between SD Card Module and Arduino Boards

With the inbuilt voltage regulator and logic-level shifter of the SD card module, we can use the 5V supply voltage of the Arduino microcontroller. The following table shows the Arduino pins that we use for the SPI communication and the power consumption of the SD card modue.

SD Card PinArduino NanoArduino Pro MiniArduino UnoArduino Mega
GNDGNDGNDGNDGND
VCC5V5V5V5V
MISO121212MISO
MOSI111111MOSI
SCK131313SCK
CS101010SS

The Arduino Nano, Pro Mini and Uno share the same pins for the SPI connection. But for the Arduino Mega we use the standard SPI pins that are named like the description of the SD card module.

The following pictures show the wiring between the SD card module and different Arduino boards.

Wiring between SD Card Module and ESP8266 Boards

The ESP8266 has an operation voltage of 3.3V that matches the needed operation voltage of the SD card module. Because the SD card module has an internal voltage regulator and logic-level shifter you could also use the VIN pin of the ESP8266 NodeMCU or the 5V pin of the ESP8266 WeMos D1 Mini to operate the SD card module, when the microcontroller board is powered via Micro-USB. In this case, each pin has an output voltage slightly under 5V.

The following table shows the wiring between the different ESP8266 boards and the SD card module.

SD Card PinESP8266 NodeMCUESP8266 WeMos D1 Mini
GNDGNDGND
VCC3V3 or VIN3V3 or 5V
MISOD6D6
MOSID7D7
SCKD5D5
CSD8D8

Generally speaking, the ESP8266 has two SPI interfaces:

  • SPI (ID: 0): SPI
  • SPI (ID: 1): HSPI

Because the SPI interface with ID 0 is used for the communication of the flash chip, when you upload a program from your PC to the connected ESP8266 board via USB, I always use the HSPI interface.

The following pictures show the wiring like presented in the previous table. From the picture of the ESP8266 NodeMCU, you see that I do not use the SPI interface 0 on the right side of the board labeled SK, SD, SC, S1.

Wiring between SD Card Module and ESP32 Boards

The ESP32 microcontroller and the SD card module have the same operation voltage of 3.3V. If you power the ESP32 board via Micro-USB you can also use the v5 pin that provides a power supply of 5V for the SD card. The internal voltage regulator and logic-level shifter reduce the supply voltage down to 3.3V and also translate the SPI communication to the desired voltage level.

The following table shows the connection between the SD card module and the ESP microcontroller.

SD Card PinEPS32 (VSPI interface)EPS32 (HSPI interface)
GNDGNDGND
VCCV5 or 3V3V5 or 3V3
MISO1912
MOSI2313
SCK1814
CS515

From the table, you see that we can use the VSPI connection pins or the HSPI interface out of the 4 SPI interfaces that the ESP32 provides. The following fritzing picture shows the connection between the SD card module and the ESP32 microcontroller board using the VSPI interface.

The following table gives you an overview of all components and parts that I used for this tutorial. I get commissions for purchases made through links in this table.

ComponentAmazon LinkAliExpress Link
Arduino Nano AmazonAliExpress
Arduino Pro Mini AmazonAliExpress
Arduino Uno AmazonAliExpress
Arduino Mega AmazonAliExpress
ESP32 ESP-WROOM-32AmazonAliExpress
ESP8266 NodeMCU AmazonAliExpress
ESP8266 WeMos D1 Mini AmazonAliExpress
Micro SD Card Module (in Sensor Kit) AmazonAliExpress
Micro SD Card AmazonAliExpress
Real-Time Clock (in Sensor Kit) AmazonAliExpress
DHT22 Module AmazonAliExpress

Arduino and ESP8266 Temperature Logger with RTC and SD Card

In the following example we want to build a temperature logger that reads the temperature and humidity from an DHT22 sensor and gets the current time from a real-time clock (RTC) module. The whole dataset is then written to a micro SD card.

The following picture shows the wiring for Arduino and ESP8266 microcontroller. You can klick on each image to enlarge it.

Temperaturelogger RTC Arduino Nano
Temperaturelogger RTC Arduino Nano
Temperaturelogger RTC Arduino Pro Mini
Temperaturelogger RTC Arduino Pro Mini
Temperaturelogger RTC Arduino Uno
Temperaturelogger RTC Arduino Uno
Temperaturelogger RTC Arduino Mega
Temperaturelogger RTC Arduino Mega
Temperaturelogger RTC ESP8266 NodeMCU
Temperaturelogger RTC ESP8266 NodeMCU
Temperaturelogger RTC ESP8266 WeMos D1 Mini
Temperaturelogger RTC ESP8266 WeMos D1 Mini

For this project we need quite some libraries. The only library, that is not installed by default, is the RTClib library that we need to get the time from the RTC. The library can be installed via the Arduino IDE and if you do not know how to install a library, you can visit my library installation guide.

The following lines show the program code for Arduino and ESP8266 based microcontroller.

Microcontroller Datasheet eBook

The 35 pages Microcontroller Datasheet Playbook contains the most useful information of 14 Arduino, ESP8266 and ESP32 microcontroller boards.

#include "SPI.h"
#include "SD.h"
#include "DHT.h"
#include "RTClib.h"

#define DHTPIN 7    // used for Arduino
//#define DHTPIN D4   // used for ESP8266

#define DHTYPE DHT22

const int chipSelect = 10;  // used for Arduino
//const int chipSelect = D8;  // used for ESP8266

DHT dht(DHTPIN, DHTYPE);
RTC_DS1307 rtc;

void setup() {
  Serial.begin(9600);
  
  while (!Serial) {
  }

   if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  if (!SD.begin(chipSelect)) {
    Serial.println("Initialization failed!");
    while (1);
  }

  dht.begin();
}

void loop() {
  
  String dataString = "";

  float h = dht.readHumidity();
  float t = dht.readTemperature();

  DateTime now = rtc.now();

  dataString += String(now.unixtime());
  dataString += ",";
  dataString += String(h);
  dataString += ",";
  dataString += String(t);
  
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    Serial.println(dataString);
  }
  
  else {
    Serial.println("error opening datalog.txt");
  }

  delay(2000);
}

At the beginning of the script we include the following libraries:

  • SPI: used for the communication to the SD card
  • SD: read and write to the SD card
  • DHT: used for the DHT temperature and humidity sensor
  • RTClib: interface for the RTC

For Arduino microcontroller we read the DHT22 sensor values from digital pin 7 and for ESP8266 microcontroller from pin D4 like you see in the fritzing sketches. You only have to comment out the line for the microcontroller that you do not use.

Because I use the DHT22 temperature and humidity sensor, I have to define the DHT type as DHT22. If you use the DHT11, you only have to change the type in this line to DHT11.

In the next two lines we define the chip select pin to identify the SD card module on the SPI communication line. In my case I use the default chip select pins. If you use another digital pin for the CS line, remember that you do not connected the pin to other components, because the SD card library will use the default pin. The Arduino uses pin 10 and the ESP8266 pin D8 for the default SPI chip select connection.

Before we enter the setup function we create an DHT object with the previous defined DHT pin and type. Also we create an object for the RTC.

In the setup function we set the baud rate to 9600 that have to match the baud rate of the serial monitor. Now we wait until the serial communication channel is established. With the following three if statements we initialize the real-time clock and the SD card module. The real-time clock is set to the date and time when the sketch is compiled. If something failed during the initialization, we get an error message in the serial monitor.

In the last line of the setup function we initialize the DHT object.

After the setup function the RTC, the DHT sensor and the SD card module are ready to operate. The loop function start with the creation of an empty string.

Now the humidity and temperature is read from the DHT sensor and also the current time in unix datetime format from the RTC. After we have all values that we want to save to the SD card we create one string that will be one line in the text file that we create on the SD card. Therefore we connect all measurements and separate them with a comma.

The next step is to write the complete string to the SD card. Therefore we open the text file with the open function of the SD library and set the path to the text file and use the argument FILE_WRITE to open the file with writing permission.

If the file is available we write the dataString to the opened text file and close the file. To see the string in the serial monitor of the Arduino IDE, we write the same string to the serial USB connection.

If we can not open the file, we write an error message and at the end of the script we wait for 2 seconds.

The following two pictures show the serial monitor and also the opened text file on the PC.

Serial Monitor

Text File from SD Card

ESP32 Temperature Logger with RTC and SD Card

For the ESP32 we want to create the same temperature logger that reads the temperature and humidity from an DHT22 sensor and gets the current time from a real-time-clock (RTC) module, like for the Arduino and ESP8266. But because the program script is different, I create a separate section in this tutorial.

The following picture shows the wiring of the ESP32 NodeMCU, SD card module, RTC module and DHT22.

Temperaturelogger RTC ESP32 NodeMCU

For the program script we can use most of the parts in the previous example but we will use two functions to write on the SD card. The following lines show the Arduino script for the ESP32 temperature logger.

#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "RTClib.h"
#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 rtc;

void writeFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Writing file: %s\n", path);

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    if(file.print(message)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
    file.close();
}

void setup(){
  Serial.begin(9600);
  dht.begin();
  
  if(!SD.begin()){
      Serial.println("Card Mount Failed");
      return;
      }

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
    }

  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  
  writeFile(SD, "/datalog_ESP32.txt", "Time, Humidity, Temperature \r\n");
}

void loop(){

  String dataString = "";

  float h = dht.readHumidity();
  float t = dht.readTemperature();

  DateTime now = rtc.now();

  dataString += String(now.unixtime());
  dataString += ",";
  dataString += String(h);
  dataString += ",";
  dataString += String(t);
  dataString += "\r\n";

  Serial.println(dataString);
  appendFile(SD, "/datalog_ESP32.txt", dataString.c_str());
    
  delay(2000);
}

Because most of the script is already described in the Arduino and ESP8266 example, I want to focus on the differences.

The first difference is that we not only need the SD card library but also need the FS (file system) library. Also the DHT22 sensor is connected to digital pin 2.

In the setup function we use the writeFile function that is only executed once and that has three arguments:

  1. The memory address of the file system from the SD card (global namespace)
  2. The path to the text file
  3. The string that should be the headline of the text file

Like in the previous example we first open the text file or if it does not exist, we create the file. Then we write the string that was defined by the function argument to the file but at the end we add “\r\n” for a carriage return and start in a new line for the next message payload. When the string was written successfully to the file, we close the text file.

In the loop function we use the appendFile function that is the same as the writeFile function but now the string in the argument is the timestamp from the RTC, the humidity and the temperature.

The following picture shows the output of the serial monitor and the text file on the PC.

Serial Monitor

Text File from SD Card

How to Read Data From an External SD Card with a Microcontroller

In our next example we want to read the data that we wrote on the SD card in the previous example. You can take the wiring from the third chapter of this tutorial.

Program Code for Arduino and ESP8266

#include "SPI.h"
#include "SD.h"

const int chipSelect = 10;

void setup() {
  Serial.begin(9600);
  while (!Serial) {
  }

  if (!SD.begin(chipSelect)) {
    Serial.println("Initialization failed!");
    while (1);
  }

  File dataFile = SD.open("datalog.txt");
  if (dataFile) {
    Serial.println("datalog.txt:");

    // read from the file until there's nothing else in it:
    while (dataFile.available()) {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  } else {
    Serial.println("error opening datalog.txt");
  }
}

void loop() {
}

Program Code for ESP32

#include "FS.h"
#include "SD.h"
#include "SPI.h"

void readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if(!file){
      Serial.println("Failed to open file for reading");
      return;
  }

  Serial.print("Read from file: ");
  while(file.available()){
      Serial.write(file.read());
  }
  file.close();
}


void setup(){
  Serial.begin(9600);
  if(!SD.begin()){
      Serial.println("Card Mount Failed");
      return;
  }
  
  readFile(SD, "/datalog_ESP32.txt");
}

void loop(){
}

You know most of the program code from the example with the temperature logger. The only difference is that we open the file in the setup function without the FILE_WRITE argument. Therefore the Arduino, ESP8266 or ESP32 has only the permission to read the file.

In the following while loop, the program loops over every row of the text file and writes the line on the serial output so that we see the complete text file in the serial monitor of the Arduino IDE. If the last line is printed to the serial, the file is closed.

For the ESP32 we use again a function from the examples that opens the text file and uses the same while function to loop over every line of the text file.

I hope you learned a lot in this tutorial. If you have any questions regarding the SD card module, please use the comment section below to ask your questions. If will answer them as soon as possible.

Loading comments...