Skip to content

SD Card

Library: Arduino SD (included with ESP32 Arduino core)
Access: SD global object, via SPI bus

The M5Cardputer has a built-in microSD slot accessed over SPI. Use it for storing WAV recordings, log files, configuration, images, or any persistent data.


Pin Assignments

Signal GPIO
SCK 40
MISO 39
MOSI 14
CS 12

These are pre-configured by M5Unified. You only need to pass CS to SD.begin().


Mount / Init

#include <SD.h>

void setup() {
    M5Cardputer.begin();

    SPI.begin(40, 39, 14, 12);   // SCK, MISO, MOSI, CS
    if (!SD.begin(12, SPI, 25000000)) {  // CS, SPI bus, frequency (25 MHz)
        M5Cardputer.Display.println("SD init failed!");
        return;
    }

    uint8_t  cardType = SD.cardType();
    uint64_t cardSize = SD.cardSize() / (1024 * 1024);  // MB

    if (cardType == CARD_NONE) {
        M5Cardputer.Display.println("No SD card");
    } else {
        M5Cardputer.Display.printf("SD Card: %llu MB\n", cardSize);
    }
}

Card Type Constants

Constant Meaning
CARD_NONE No card / unknown
CARD_MMC MMC card
CARD_SD SD card
CARD_SDHC SDHC card (most common)

File Operations

All file operations use fs::FS abstraction via the File class.

Open a File

File file = SD.open("/data.txt");              // Read mode (default)
File file = SD.open("/data.txt", FILE_WRITE);  // Write mode (create/truncate)
File file = SD.open("/data.txt", FILE_APPEND); // Append mode

Read

// Read byte by byte
while (file.available()) {
    char c = file.read();
    // ...
}

// Read into buffer
uint8_t buf[256];
size_t bytesRead = file.read(buf, sizeof(buf));

// Seek to position
file.seek(44);  // Skip WAV header (44 bytes)

Write

// Write text
file.print("Hello, SD!");
file.println(" line 2");

// Write binary
uint8_t data[] = {0x00, 0xFF, 0x55};
file.write(data, sizeof(data));

Close

file.close();  // Always close when done!

File / Directory Management

// Check existence
if (SD.exists("/config.json")) { ... }

// Delete
SD.remove("/old_file.txt");

// Rename
SD.rename("/old.txt", "/new.txt");

// Create directory
SD.mkdir("/logs");

// Remove directory (must be empty)
SD.rmdir("/empty_dir");

Directory Listing

File dir = SD.open("/");
while (File entry = dir.openNextFile()) {
    M5Cardputer.Display.printf("%s  %u bytes  %s\n",
        entry.name(),
        entry.size(),
        entry.isDirectory() ? "[DIR]" : "");
    entry.close();
}
dir.close();

Space Info

uint64_t total = SD.totalBytes();
uint64_t used  = SD.usedBytes();
uint64_t free  = total - used;

M5Cardputer.Display.printf("Total: %llu MB\n", total / 1024 / 1024);
M5Cardputer.Display.printf("Free:  %llu MB\n", free / 1024 / 1024);

WAV Recording to SD

Combining Microphone, Speaker, and SD card — see the full example at:

examples/Basic/mic_wav_record

Minimal WAV Write Snippet

struct WAVHeader {
    char     riff[4]       = {'R','I','F','F'};
    uint32_t fileSize      = 0;
    char     wave[4]       = {'W','A','V','E'};
    char     fmt[4]        = {'f','m','t',' '};
    uint32_t fmtSize       = 16;
    uint16_t audioFormat   = 1;            // PCM
    uint16_t numChannels   = 1;            // Mono
    uint32_t sampleRate    = 16000;
    uint32_t byteRate      = 16000 * 2;
    uint16_t blockAlign    = 2;
    uint16_t bitsPerSample = 16;
    char     data[4]       = {'d','a','t','a'};
    uint32_t dataSize      = 0;
};

void saveWAV(const char* path, int16_t* samples, size_t count) {
    File file = SD.open(path, FILE_WRITE);

    WAVHeader header;
    header.fileSize = 36 + count * sizeof(int16_t);
    header.dataSize = count * sizeof(int16_t);

    file.write((uint8_t*)&header, sizeof(WAVHeader));
    file.write((uint8_t*)samples, count * sizeof(int16_t));
    file.close();
}

Quick Example: Logging to SD

#include <SD.h>
#include <SPI.h>

void setup() {
    M5Cardputer.begin();
    SPI.begin(40, 39, 14, 12);
    SD.begin(12, SPI, 25000000);

    // Create log header once
    if (!SD.exists("/log.csv")) {
        File f = SD.open("/log.csv", FILE_WRITE);
        f.println("timestamp,event");
        f.close();
    }
}

void loop() {
    M5Cardputer.update();

    if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) {
        M5Cardputer.Keyboard.updateKeysState();
        for (char c : M5Cardputer.Keyboard.keysState().word) {
            File f = SD.open("/log.csv", FILE_APPEND);
            f.printf("%lu,%c\n", millis(), c);
            f.close();
        }
    }
}