Chapter 150: SD Card and SDIO Interface
Chapter Objectives
Upon completing this chapter, you will be able to:
- Understand different types of SD cards (SD, SDHC, SDXC) and their specifications.
- Differentiate between SD mode (using the SDMMC peripheral) and SPI mode for SD card communication.
- Learn about the FAT filesystem and its relevance to SD cards.
- Initialize and mount SD cards using ESP-IDF drivers and the Virtual File System (VFS).
- Perform standard file operations (create, read, write, delete, list directories) on an SD card.
- Understand the role of
sdmmc_host_t
,sdmmc_slot_config_t
(for SD mode), andsdspi_device_config_t
(for SPI mode). - Identify which ESP32 variants support the SDMMC host peripheral versus those limited to SPI mode.
- Troubleshoot common problems encountered when interfacing SD cards with ESP32 devices.
Introduction
In many embedded applications, the need for persistent data storage that exceeds the internal flash capacity of a microcontroller is common. Whether it’s for logging sensor data over extended periods, storing configuration files, hosting web server content, or saving images and audio, external storage becomes essential. Secure Digital (SD) cards offer a convenient, removable, and high-capacity solution for these needs.
This chapter explores how to integrate SD cards with ESP32 microcontrollers using the ESP-IDF. We will cover the two primary communication modes—SPI mode and the faster SD mode (via the SDMMC peripheral on compatible ESP32 variants)—and learn how to manage files using the FAT filesystem through ESP-IDF’s Virtual File System (VFS) layer. Practical examples will guide you through initializing SD cards and performing common file operations.
Theory
SD Card Family
SD cards come in various types, primarily differing in capacity and the underlying filesystem they are typically formatted with:
- SD (Standard Capacity): Capacities up to 2GB. Usually formatted with FAT16.
- SDHC (High Capacity): Capacities from over 2GB up to 32GB. Usually formatted with FAT32.
- SDXC (Extended Capacity): Capacities from over 32GB up to 2TB (and theoretically beyond). Usually formatted with exFAT. ESP-IDF’s FatFs library primarily supports FAT16/FAT32; exFAT support might require additional configuration or libraries.
- microSD Cards: Smaller form factor versions of the above, commonly used with ESP32 development boards and modules.
- Speed Classes: Indicate minimum sequential write speeds (e.g., Class 2, 4, 6, 10; UHS Class 1, 3). Higher class numbers mean faster minimum write speeds.
Feature | SD (Standard Capacity) | SDHC (High Capacity) | SDXC (Extended Capacity) |
---|---|---|---|
Capacity Range | Up to 2GB | >2GB up to 32GB | >32GB up to 2TB (theoretically more) |
Typical Filesystem (Default) | FAT16 | FAT32 | exFAT |
Addressing Mode | Byte Addressing | Block Addressing (512 bytes/block) | Block Addressing (512 bytes/block) |
Primary ESP-IDF FatFs Support | Yes (FAT16) | Yes (FAT32) | FAT32 (if formatted as such within 32GB limit for some tools). Native exFAT support in ESP-IDF might require extra configuration or specific FatFs versions/settings. Default FatFs often focuses on FAT16/FAT32. |
Common Use | Older devices, very small storage needs. | Most common for general-purpose embedded storage, logging, configurations. | Large media files, extensive data logging, high-capacity needs. |
Notes | Less common now. | Widely supported and good balance for ESP32 projects. | Ensure your application and ESP-IDF setup can handle exFAT if used, or reformat to FAT32 if capacity allows and exFAT is problematic. |
Communication Modes
ESP32 devices can communicate with SD cards using two primary modes:
- SPI Mode:
- Uses a standard Serial Peripheral Interface (SPI) bus.
- Requires fewer pins: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCLK (Serial Clock), and CS (Chip Select).
- Simpler to implement in terms of hardware connections and supported by virtually all microcontrollers with an SPI peripheral, including all ESP32 variants.
- Generally slower than SD mode.
- ESP-IDF uses the
sdspi_host.h
driver for this mode.

- SD Mode (SDIO – Secure Digital Input Output):
- Uses a dedicated SD/MMC host controller peripheral (if available on the ESP32 variant).
- Offers higher data transfer rates than SPI mode.
- Can operate in 1-bit or 4-bit data bus modes:
- 1-bit SD mode: Uses CLK, CMD, and DAT0 lines.
- 4-bit SD mode: Uses CLK, CMD, and DAT0-DAT3 lines for higher throughput. This is the most common high-performance mode.
- ESP-IDF uses the
sdmmc_host.h
driver for this mode.

Feature | SPI Mode | SD Mode (SDIO via SDMMC) |
---|---|---|
Primary Interface | Standard SPI Bus | Dedicated SD/MMC Bus (SDIO protocol) |
Typical Pins Required | 4 pins: MOSI, MISO, SCLK, CS |
|
Data Transfer Speed | Slower (typically up to 20-25 MHz SPI clock) | Faster (typically up to 40-50 MHz SD clock, or higher with UHS modes on capable cards/hosts) |
Complexity | Simpler hardware, widely supported. | More complex protocol, requires SDMMC host peripheral. Pin requirements and pull-ups need care. |
ESP-IDF Driver | sdspi_host.h, esp_vfs_fat_sdspi_mount() | sdmmc_host.h, esp_vfs_fat_sdmmc_mount() |
ESP32 Variant Support | All ESP32 variants (with SPI peripheral). | ESP32 (original), ESP32-S3 (variants with SDMMC host). Not available on ESP32-S2, C3, C6, H2. |
Pull-up Resistors | Generally not strictly required by SPI protocol itself, but often recommended on CS and MISO for stability, or if sharing bus. | Crucial: Typically required on CMD and DAT0-3 lines (10k-50kΩ to 3.3V) for reliable operation, especially at higher speeds. |
Pros |
|
|
Cons |
|
|
FAT Filesystem (File Allocation Table)
SD cards are typically pre-formatted with a FAT filesystem (FAT16, FAT32, or exFAT). This filesystem allows operating systems and microcontrollers to organize data into files and directories.
- FAT16: Used for smaller capacity cards (typically < 2GB).
- FAT32: Most common for SDHC cards (2GB-32GB). Offers support for larger volumes and files than FAT16.
- exFAT: Designed for larger capacity SDXC cards (>32GB).
ESP-IDF integrates the FatFs library, a generic FAT/exFAT filesystem module for small embedded systems. This library enables reading from and writing to FAT-formatted SD cards.
Virtual File System (VFS) in ESP-IDF
ESP-IDF includes a Virtual File System (VFS) component. The VFS provides an abstraction layer that allows standard C file I/O functions (like fopen()
, fread()
, fwrite()
, fclose()
, opendir()
, readdir()
, stat()
, etc.) to work seamlessly with different underlying filesystems and storage devices.
graph TD A[Start: Use SD Card] --> B{Choose Communication Mode}; style A fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6 style B fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E B -- SPI Mode --> C["Configure <b>spi_bus_config_t</b> <br> (MOSI, MISO, SCLK pins)"]; C --> D["Initialize SPI Bus <br> <b>spi_bus_initialize()</b>"]; D --> E["Configure <b>sdspi_device_config_t</b> <br> (CS pin, host_id)"]; E --> F["Call <b>esp_vfs_fat_sdspi_mount()</b> <br> (mount_point, slot_config, mount_config, &card)"]; style C fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style D fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style E fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style F fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF B -- SD Mode (SDMMC) --> G["Configure <b>sdmmc_host_t</b> <br> (flags for 1/4 bit, freq)"]; G --> H["Configure <b>sdmmc_slot_config_t</b> <br> (CLK, CMD, DAT0-3 pins, width)"]; H --> I["Call <b>esp_vfs_fat_sdmmc_mount()</b> <br> (mount_point, host_config, slot_config, mount_config, &card)"]; style G fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style H fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style I fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF F --> J{Mount Successful?}; I --> J; style J fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E J -- Yes --> K["SD Card Initialized & FAT Filesystem Mounted <br> e.g., at <b>/sdcard</b>"]; K --> L["Access SD Card via VFS <br> using standard C file I/O: <br> <b>fopen(<b>/sdcard/file.txt, w</b>)</b> <br> <b>fread()</b>, <b>fwrite()</b>, <b>fclose()</b>, etc."]; style K fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46 style L fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF J -- No (Error) --> M["Error: Mount Failed <br> (Check wiring, power, card format, logs)"]; style M fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B L --> N[Perform File Operations]; N --> O{Finished with SD Card?}; style N fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style O fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E O -- Yes --> P["Unmount Filesystem <br> <b>esp_vfs_fat_sdcard_unmount()</b>"]; P --> Q["Deinitialize Bus (if SPI & not shared) <br> <b>spi_bus_free()</b>"]; P --> R[End]; style P fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style Q fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF style R fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46 O -- No (Continue Operations) --> N; classDef LStartStyle fill:#EDE9FE,stroke:#5B21B6,stroke-width:1.5px,color:#5B21B6 classDef LProcessStyle fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF classDef LDecisionStyle fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E classDef LSuccessStyle fill:#D1FAE5,stroke:#059669,stroke-width:1.5px,color:#065F46 classDef LErrorStyle fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B
When an SD card is initialized and a FAT filesystem is detected, it can be “mounted” to a specific path in the VFS (e.g., /sdcard
). After mounting, you can access files on the SD card using paths like /sdcard/mylog.txt
.
The functions esp_vfs_fat_sdmmc_mount()
(for SD mode) and esp_vfs_fat_sdspi_mount()
(for SPI mode) handle the initialization of the SD card, FatFs, and registration with the VFS.
ESP-IDF SD Card Drivers
sdmmc_host.h
: Provides APIs for configuring the SDMMC host peripheral (for SD mode). Key structure:sdmmc_host_t
.sdspi_host.h
: Provides APIs for configuring an SPI peripheral to communicate with an SD card in SPI mode.sdmmc_cmd.h
: Contains definitions and helper functions for SD commands and data structures.esp_vfs_fat.h
: Provides helper functions to mount FAT filesystems from SD cards (using either SDMMC or SPI host) to the VFS.
Header File / Component | Key Structures / Functions | Purpose |
---|---|---|
sdmmc_host.h (for SD Mode) |
|
Configuration and initialization of the SDMMC host peripheral for communication with SD cards in native SD mode (1-bit or 4-bit). Defines host capabilities and slot pin configurations. |
sdspi_host.h (for SPI Mode) |
|
Configuration of an SPI peripheral to act as a host for an SD card operating in SPI mode. Defines SPI bus and CS pin for the SD card device. |
driver/spi_common.h (Used with SPI Mode) |
|
General SPI bus initialization and deinitialization, used before configuring an SD card device on that bus in SPI mode. |
esp_vfs_fat.h (Filesystem Layer) |
|
Provides high-level functions to initialize an SD card (either in SD or SPI mode), initialize the FatFs library, and register the FAT filesystem with the ESP-IDF Virtual File System (VFS) at a specified mount point. |
sdmmc_cmd.h (Common SD Definitions) |
|
Contains common data structures (like sdmmc_card_t to hold card information) and helper functions (like printing card info) used by both SDMMC and SDSPI drivers. Also defines SD protocol level commands. |
Practical Examples
Prerequisites:
- ESP-IDF v5.x installed and configured with VS Code.
- An ESP32 development board.
- A microSD card and a compatible SD card module/socket wired to the ESP32.
- Ensure the microSD card is formatted with FAT32 for these examples.
Example 1: SD Card in SPI Mode
This example demonstrates initializing an SD card in SPI mode, mounting it, and performing basic file operations.
1. Connections (Example for SPI Mode):
- SD Card MOSI (DI/CMD on some breakouts) -> ESP32 SPI MOSI pin (e.g., GPIO23 for VSPI)
- SD Card MISO (DO) -> ESP32 SPI MISO pin (e.g., GPIO19 for VSPI)
- SD Card SCLK (CLK) -> ESP32 SPI SCLK pin (e.g., GPIO18 for VSPI)
- SD Card CS (Chip Select) -> Any ESP32 GPIO (e.g., GPIO5 for VSPI_CS)
- VCC -> 3.3V (ESP32)
- GND -> GND (ESP32)
Warning: Pin assignments can vary. Always check your ESP32 board’s documentation for default SPI pins. The example uses VSPI (SPI3_HOST on original ESP32, SPI2_HOST on S2/S3).
Flow:
sequenceDiagram participant App as User Application participant VFS as ESP-IDF VFS Layer participant FatFs as FatFs Library participant SDDriver as SD Card Driver (SPI/SDMMC) participant SDCard as SD Card Hardware App->>+VFS: fopen("/sdcard/log.txt", "w") VFS->>+FatFs: Resolve path, <br>request file open (f_open) FatFs->>+SDDriver: Read/Verify FAT, <br>directory entries (disk_read) SDDriver->>+SDCard: Send SD Commands (CMDx),<br>Read Data Blocks SDCard-->>-SDDriver: Data / Status SDDriver-->>-FatFs: Sector Data FatFs-->>-VFS: File handle / Error VFS-->>-App: FILE* fp / NULL alt File Opened Successfully App->>+VFS: fwrite(buffer, size, count, fp) VFS->>+FatFs: Request file write (f_write) FatFs->>+SDDriver: Write data to sectors, <br>update FAT (disk_write) SDDriver->>+SDCard: Send SD Commands (CMDx),<br> Write Data Blocks SDCard-->>-SDDriver: Status SDDriver-->>-FatFs: Write Status FatFs-->>-VFS: Bytes written / Error VFS-->>-App: Bytes written / Error App->>+VFS: fclose(fp) VFS->>+FatFs: Request file close (f_close) FatFs->>+SDDriver: Flush buffers, <br>update directory entry (disk_write) SDDriver->>+SDCard: Send SD Commands, <br>Write Data Blocks SDCard-->>-SDDriver: Status SDDriver-->>-FatFs: Status FatFs-->>-VFS: Success / Error VFS-->>-App: Success / Error else File Open Failed App->>VFS: Handle error (e.g., log, retry) end
2. Code (main/sd_spi_example_main.c
):
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/spi_common.h"
#include "driver/sdspi_host.h"
#include "sdmmc_cmd.h"
static const char *TAG = "SD_SPI_Example";
// Define the mount point for the SD card
#define MOUNT_POINT "/sdcard"
// SPI Bus configuration (VSPI_HOST is SPI3 on ESP32 classic, HSPI_HOST is SPI2)
// For ESP32-S2/S3, these are SPI2_HOST and SPI3_HOST respectively.
// For ESP32-C3, only SPI2_HOST is available.
#define SPI_BUS_HOST SPI2_HOST // Example: Using SPI2 host (often referred to as HSPI on ESP32 classic)
// Pin Configuration for SPI mode (Update these to match your wiring)
// Note: Using default SPI pins for HSPI on ESP32 classic for this example.
// Check your board's schematic or ESP-IDF docs for correct pins for your chosen SPI_BUS_HOST.
#define PIN_NUM_MISO 12 // Default HSPI_MISO
#define PIN_NUM_MOSI 13 // Default HSPI_MOSI
#define PIN_NUM_CLK 14 // Default HSPI_SCLK
#define PIN_NUM_CS 15 // Default HSPI_CS
void app_main(void)
{
esp_err_t ret;
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false, // Set to true to format if mount fails
.max_files = 5, // Max number of open files
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card in SPI mode");
// Initialize SPI bus
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000, // Max transfer size in bytes
};
ret = spi_bus_initialize(SPI_BUS_HOST, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
return;
}
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = PIN_NUM_CS;
slot_config.host_id = SPI_BUS_HOST;
ESP_LOGI(TAG, "Mounting filesystem");
ret = esp_vfs_fat_sdspi_mount(mount_point, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set format_if_mount_failed = true.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
spi_bus_free(SPI_BUS_HOST); // Free SPI bus if mount fails
return;
}
ESP_LOGI(TAG, "Filesystem mounted");
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
// --- Perform file operations ---
const char *file_path = MOUNT_POINT "/hello.txt";
ESP_LOGI(TAG, "Opening file %s for writing", file_path);
FILE *f = fopen(file_path, "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
goto cleanup;
}
fprintf(f, "Hello from ESP32! SD Card via SPI.\n");
fclose(f);
ESP_LOGI(TAG, "File written successfully");
// Check if file exists
struct stat st;
if (stat(file_path, &st) == 0) {
ESP_LOGI(TAG, "File %s exists, size: %ld bytes", file_path, st.st_size);
} else {
ESP_LOGE(TAG, "File %s does not exist", file_path);
}
ESP_LOGI(TAG, "Opening file %s for reading", file_path);
f = fopen(file_path, "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
goto cleanup;
}
char line[128];
fgets(line, sizeof(line), f);
fclose(f);
// Strip newline
char *pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGI(TAG, "Read from file: '%s'", line);
// --- Unmount and cleanup ---
cleanup:
ESP_LOGI(TAG, "Unmounting filesystem");
esp_vfs_fat_sdcard_unmount(mount_point, card);
ESP_LOGI(TAG, "Card unmounted");
// Deinitialize SPI bus
spi_bus_free(SPI_BUS_HOST);
ESP_LOGI(TAG, "SPI bus freed");
}
3. CMakeLists.txt
(in main
directory):
idf_component_register(SRCS "sd_spi_example_main.c"
INCLUDE_DIRS "."
REQUIRES esp_vfs_fat sdmmc) # sdmmc component provides common SD definitions
4. Build, Flash, and Observe Steps:
- Wire your SD card module to the ESP32 using the SPI pins defined.
- Insert a FAT32 formatted microSD card.
- Build and flash the project.
- Open the ESP-IDF Monitor. You should see logs indicating SD card initialization, mounting, file creation, reading, and unmounting.
- You can remove the SD card and check its contents on a PC to verify
hello.txt
.
Example 2: SD Card in SD Mode (4-bit using SDMMC)
This example is for ESP32 variants that have an SDMMC host peripheral (e.g., original ESP32, ESP32-S3).
1. Connections (Example for SD 4-bit Mode on ESP32 original – Slot 1):
- SD Card CLK -> ESP32 GPIO14 (HS2_CLK)
- SD Card CMD -> ESP32 GPIO15 (HS2_CMD)
- SD Card DAT0 -> ESP32 GPIO2 (HS2_D0)
- SD Card DAT1 -> ESP32 GPIO4 (HS2_D1)
- SD Card DAT2 -> ESP32 GPIO12 (HS2_D2)
- SD Card DAT3 -> ESP32 GPIO13 (HS2_D3)
- VCC -> 3.3V
- GND -> GND
Important: These pins (GPIOs 2, 4, 12, 13, 14, 15) are commonly used for SDMMC Slot 1 on ESP32-WROOM/WROVER modules. Always verify with your specific board’s schematic. Pull-up resistors (typically 10k-50k Ohm) are usually required on CMD and DAT0-3 lines for reliable SD mode operation, though some modules include them.
2. Code (main/sd_sdmmc_example_main.c
):
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/sdmmc_host.h"
#include "sdmmc_cmd.h"
static const char *TAG = "SD_SDMMC_Example";
#define MOUNT_POINT "/sdcard"
void app_main(void)
{
esp_err_t ret;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card in SDMMC mode (4-bit)");
// Configure SDMMC host peripheral
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
// For 4-line SD mode, set bus width. For 1-line mode, use SDMMC_HOST_FLAG_1BIT.
host.flags = SDMMC_HOST_FLAG_4BIT;
// host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; // Or SDMMC_FREQ_DEFAULT, SDMMC_FREQ_PROBING
// Configure SDMMC slot
// GPIOs for SDMMC slot 1 on ESP32: CLK=14, CMD=15, D0=2, D1=4, D2=12, D3=13
// These are defaults for SDMMC_SLOT_CONFIG_DEFAULT() when using slot 1.
// For ESP32-S3, check its specific default pins or configure manually.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// For ESP32, SDMMC_SLOT_CONFIG_DEFAULT uses:
// CMD: GPIO15
// CLK: GPIO14
// D0: GPIO2
// D1: GPIO4 (for 4-bit/8-bit)
// D2: GPIO12 (for 4-bit/8-bit)
// D3: GPIO13 (for 4-bit/8-bit)
// D4-D7: Not used by default for SD (used for eMMC 8-bit)
// slot_config.width = 4; // Explicitly set 4-bit mode if not using default flags in host
// For robust D0 line behavior, ensure it has a pull-up resistor if not internal.
// slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; // Enable internal pullups if needed and available
ESP_LOGI(TAG, "Mounting filesystem");
// Note: esp_vfs_fat_sdmmc_mount initializes the host internally.
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set format_if_mount_failed = true.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors if needed.", esp_err_to_name(ret));
}
return;
}
ESP_LOGI(TAG, "Filesystem mounted");
sdmmc_card_print_info(stdout, card);
// --- Perform file operations (same as SPI example) ---
const char *file_path = MOUNT_POINT "/hello_sdmmc.txt";
ESP_LOGI(TAG, "Opening file %s for writing", file_path);
FILE *f = fopen(file_path, "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
goto cleanup_sdmmc;
}
fprintf(f, "Hello from ESP32! SD Card via SDMMC (4-bit).\n");
fclose(f);
ESP_LOGI(TAG, "File written successfully");
// ... (add read and stat operations similar to SPI example) ...
cleanup_sdmmc:
ESP_LOGI(TAG, "Unmounting filesystem");
esp_vfs_fat_sdcard_unmount(mount_point, card);
ESP_LOGI(TAG, "Card unmounted");
// Host deinitialization is handled by esp_vfs_fat_sdcard_unmount
// if it was initialized by esp_vfs_fat_sdmmc_mount.
}
3. CMakeLists.txt
(in main
directory):
idf_component_register(SRCS "sd_sdmmc_example_main.c"
INCLUDE_DIRS "."
REQUIRES esp_vfs_fat sdmmc)
4. Build, Flash, and Observe Steps:
Similar to the SPI example, but ensure your wiring matches the SDMMC pins for your ESP32 variant.
Variant Notes
ESP32 Variant | SDMMC Host Peripheral (for SD Mode) | SPI Mode Support | Typical Use & Notes |
---|---|---|---|
ESP32 (Original) | Yes (2 slots) Slot 0 (HS1_*) often for internal Flash/PSRAM. Slot 1 (HS2_*) commonly for external SD. |
Yes (Multiple SPI controllers) | Supports both high-performance SD mode (4-bit recommended) and SPI mode. Ideal for applications needing fast SD access. |
ESP32-S2 | No | Yes (Multiple SPI controllers) | Limited to SPI mode for SD card communication. Performance will be lower than SD mode. |
ESP32-S3 | Yes (1 slot) | Yes (Multiple SPI controllers) | Supports high-performance SD mode (4-bit recommended) and SPI mode. Flexible GPIO mapping for SDMMC. |
ESP32-C3 | No | Yes (Fewer SPI controllers than ESP32/S3) | Limited to SPI mode. Resource constraints (RAM, CPU) might impact performance for intensive SD operations. |
ESP32-C6 | No | Yes (Fewer SPI controllers) | Limited to SPI mode. Primarily for IoT applications where SD card might be for basic logging or configuration. |
ESP32-H2 | No | Yes (Fewer SPI controllers) | Limited to SPI mode. Focused on low-power wireless; SD card use likely for minimal data storage. |
- ESP32 (Original):
- Features two SDMMC host peripherals (Slot 0 and Slot 1).
- Slot 1 (HS2_*) is commonly used for external SD cards. Default pins: CLK=14, CMD=15, D0=2, D1=4, D2=12, D3=13.
- Slot 0 (HS1_*) is often connected to the integrated flash/PSRAM chip on WROVER modules and might not be available for external SD cards on such modules.
- Can also use SPI mode on any of its SPI peripherals (SPI0-SPI3, though SPI0/1 are often for flash/PSRAM).
- ESP32-S2:
- No dedicated SDMMC host peripheral.
- Must use SPI mode for SD card communication.
- Has multiple SPI peripherals that can be used.
- ESP32-S3:
- Features one SDMMC host peripheral.
- Can use SD mode (1-bit or 4-bit) for higher performance. Pin mapping for SDMMC is flexible via GPIO matrix.
- Can also use SPI mode on any of its SPI peripherals.
- ESP32-C3 / ESP32-C6 / ESP32-H2:
- No dedicated SDMMC host peripheral.
- Must use SPI mode for SD card communication.
- Typically have fewer SPI peripherals compared to ESP32/S3. Resource constraints (RAM, CPU) might also be a factor for high-throughput SD card operations.
Common Mistakes & Troubleshooting Tips
Mistake / Issue | Symptom(s) | Troubleshooting / Solution |
---|---|---|
Incorrect Wiring / Pin Definitions |
|
|
Missing Pull-Up Resistors (SD Mode) |
|
|
Power Supply Issues |
|
|
SD Card Not Formatted / Incompatible Filesystem |
|
|
Mounting/Unmounting Issues |
|
|
SPI Bus Conflicts / Incorrect Host ID |
|
|
SD Card Speed Issues / Timeouts |
|
|
Exercises
- Directory Listing:
- Create a few files and directories on your SD card using a PC.
- Write an ESP32 program that mounts the SD card, then lists all files and directories in the root directory (
/sdcard/
) and prints their names (and types: file/directory) to the serial monitor. Useopendir
,readdir
, andstat
ord_type
fromdirent.h
.
- Data Logging with Timestamps:
- Initialize the SNTP service (Chapter 98) to get the current time.
- Modify the SPI or SDMMC example to create a log file (e.g.,
datalog.csv
). - Periodically (e.g., every 10 seconds) write a new line to the file containing a timestamp and some dummy sensor data (e.g., “YYYY-MM-DD HH:MM:SS, Temperature: 25.5, Humidity: 45.0”).
- File Deletion and Renaming:
- Write a program that:
- Creates a file named
temp_file.txt
. - Writes some text into it.
- Closes it.
- Renames
temp_file.txt
torenamed_file.txt
(userename()
). - Verifies
renamed_file.txt
exists andtemp_file.txt
does not. - Deletes
renamed_file.txt
(useunlink()
).
- Creates a file named
- Write a program that:
- Performance Comparison (SPI vs. SD 4-bit on ESP32/S3):
- If you have an ESP32 (original) or ESP32-S3, set up connections for both SPI mode and SD 4-bit mode (you might need to re-wire between tests or use different pins if available).
- Write a test program that creates a moderately large file (e.g., 1MB or 5MB) by repeatedly writing a small buffer.
- Measure the time taken to write the entire file in SPI mode and then in SD 4-bit mode.
- Print the results to compare the throughput. Use
esp_timer_get_time()
for timing.
Summary
- SD cards provide versatile external storage for ESP32 projects, supporting various capacities and speeds.
- Communication can be achieved via SPI mode (simpler, fewer pins, slower) or SD mode (higher performance using SDMMC peripheral on compatible ESP32s).
- ESP-IDF uses the FatFs library, integrated with its Virtual File System (VFS), to manage FAT16/FAT32 filesystems on SD cards.
- Key ESP-IDF components include
sdmmc_host.h
(SD mode),sdspi_host.h
(SPI mode), andesp_vfs_fat.h
(mounting). - ESP32 (original) and ESP32-S3 have SDMMC host peripherals for SD mode. ESP32-S2, C3, C6, H2 are limited to SPI mode for SD cards.
- Proper wiring, power supply, pull-up resistors (for SD mode), and card formatting are crucial for reliable operation.
- Standard C file I/O functions can be used once the SD card is mounted to the VFS.
Further Reading
- ESP-IDF Programming Guide – SDMMC Host Driver:
- https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/peripherals/sdmmc_host.html (Navigate to S3 section for its specific details).
- ESP-IDF Programming Guide – SDSPI Host Driver:
- ESP-IDF Programming Guide – Virtual Filesystem Component:
- ESP-IDF Programming Guide – Wear Levelling (for FAT on SPI Flash, but concepts are useful):
- FatFs Generic FAT Filesystem Module:
- SD Association – Specifications:
- ESP-IDF Examples – Storage – SD Card: