ESP32: connecting to SD Card

In this tutorial we are going to learn how to interact with a SD card from the ESP32, using the Arduino core.

Introduction

In this tutorial we are going to learn how to interact with a SD card from the ESP32, using the Arduino core.

It’s important to mention that there are a couple of ways to connect the SD card to the microcontroller. One of the easiest is to use board with a SD card socket, where we can plug our card and start using it right away.

In my case, I’m using a HW-818 ESP32 board model, which can be bought at eBay for around 10 Euros (link here).

Other approach is to use a SD card adapter, which can also be found at eBay for very low prices. These modules have a socket for the card and then expose pins that we can connect to the ESP32.

Other possible way is wiring the card directly to the ESP32, like shown on this diagram.

In this introductory tutorial we are going to learn how to mount the card and obtain some simple information, such as the card type or its total capacity.

For that, we will use the Arduino core library that allows to interact with the SD card. Note that there are two libraries available: SD and SD_MMC. You can read the difference about them here. For more details, you can also consult the Espressif documentation about the lower level drivers.

In short, the SD library operates over SPI and the SD_MMC uses the SDMMC hardware bus  of the ESP32 [1]. So, depending on your hardware setup, you should choose the correct library. For the board I’m using, I need to use the SC_MMC one.

The code shown on this tutorial was based on the example from the Arduino core library, which I recommend you to check.

The code

We start by including the SD_MMC.h library from the Arduino core, so we have access to all the methods we need to interact with the SD card.

Including this library will expose to us an extern variable called SD_MMC that we will use in our code. That variable is an object of class SDMMCFS and you can check its implementation here.

#include "SD_MMC.h"

We will write the rest of our code in the Arduino setup. We start, as usual, by opening a serial connection, to output the results of our program.

Serial.begin(115200);

Then we will call the begin method on our SD_MMC extern variable. This will take care of mounting the card, so we can start to use it. Note that this method will return a Boolean indicating if the mounting procedure was successful (true) or not (false), which we will use for error checking.

if(!SD_MMC.begin()){
     Serial.println("Failed to mount card");
     return;
}

After this we will check the type of SD card used. To obtain this information, we can simply call the cardType method on our extern variable. This method takes no arguments and returns an enumerated value of sdcard_type_t.

uint8_t cardType = SD_MMC.cardType();

Then we will use some if-else conditions to check the obtained value against the values of the mentioned enums.

if(cardType == CARD_NONE){
    Serial.println("No card attached");
    return;
}
if(cardType == CARD_MMC){
    Serial.println("MMC");
} else if(cardType == CARD_SD){
    Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
} else {
    Serial.println("UNKNOWN");
}

After this we will obtain the total size of the SD card. This is again very easy to do. We just need to call the cardSize method on the extern variable.

This method takes no arguments and returns the total size, in bytes. Note that the returned value is an unsigned long.

uint64_t cardSize = SD_MMC.cardSize();

Then we will convert the value from bytes to mbytes and print it.

int cardSizeInMB = cardSize/(1024 * 1024);
Serial.println(cardSizeInMB);

After this we will also obtain the total number of bytes available and the total number of bytes used. To do so, we will use the totalBytes and usedBytes methods, respectively.

Like before, we are also going to convert the returned values to mbytes and print them.

uint64_t bytesAvailable = SD_MMC.totalBytes(); 
int bytesAvailableInMB = bytesAvailable/(1024 * 1024);
Serial.println(bytesAvailableInMB);

uint64_t bytesUsed = SD_MMC.usedBytes();
int bytesUsedInMB = bytesUsed/(1024 * 1024);
Serial.println(bytesUsedInMB);

The final code can be seen below.

#include "SD_MMC.h"

void setup(){
  
    Serial.begin(115200);
    
    if(!SD_MMC.begin()){
        Serial.println("Failed to mount card");
        return;
    }
    uint8_t cardType = SD_MMC.cardType();

    Serial.print("\nCard Type: ");
    
    if(cardType == CARD_NONE){
        Serial.println("No card attached");
        return;
    }
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD_MMC.cardSize();
    int cardSizeInMB = cardSize/(1024 * 1024);
    
    Serial.print("Card size: ");
    Serial.println(cardSizeInMB);


    uint64_t bytesAvailable = SD_MMC.totalBytes(); 
    int bytesAvailableInMB = bytesAvailable/(1024 * 1024);

    Serial.print("MB available: ");
    Serial.println(bytesAvailableInMB);


    uint64_t bytesUsed = SD_MMC.usedBytes();
    int bytesUsedInMB = bytesUsed/(1024 * 1024);

    Serial.print("MB used: ");
    Serial.println(bytesUsedInMB);
}

void loop(){}

Testing the code

To test the code, simply compile it and upload it to your device, after the SD card is properly connected to the ESP32.

You should get an output similar to figure 1. As can be seen, I’ve used a SDSC card with 1886 mbytes of total capacity. From those, I used 1 and have 1885 available.

Output of the program in the Arduino IDE serial monitor.
Figure 1 – Output of the program in the Arduino IDE serial monitor.

References

[1] https://github.com/espressif/arduino-esp32/tree/master/libraries/SD#faq

Leave a Reply

%d bloggers like this: