A microSD module gives the ESP32 gigabytes of storage — for data loggers, recorded sensor history or files served over Wi-Fi. The cheap blue module has a 3.3 V regulator and a level shifter on board, so it wants 5 V on VCC but talks 3.3 V logic.
On the ESP32 DevKit V1, wire it to the VSPI bus — SCK GPIO18, MISO GPIO19, MOSI GPIO23 — with CS on GPIO5, and use the SD library built into the ESP32 core. The sketch mounts the card, prints its type and size, and appends a line to /log.txt every five seconds.
Wiring
| ESP32 DevKit V1 | MicroSD card module (SPI) | Wire | Notes |
|---|---|---|---|
| VIN | VCC | red | The common module has an AMS1117 3.3 V regulator, which needs about 4.5 V in. From 3V3 it’s unreliable. (3.3 V-only boards without a regulator go on 3V3.) |
| GND | GND | black | |
| D18 | SCK | yellow | |
| D19 | MISO | blue | |
| D23 | MOSI | green | |
| D5 | CS | purple | VSPI’s default SS. A strapping pin, but chip select idles HIGH — the level the ESP32 expects at boot. |
4.5–5.5 V on the common module with regulator (3.3 V-only boards also sold) part, 3.3 V board. The common blue module has an AMS1117 3.3 V regulator and a 74LVC125 level shifter, so it needs 5 V on VCC — 3.3 V leaves the card under-powered. Its signal pins accept 3.3 V or 5 V logic, so ESP32, Pico and Uno all connect directly.
Board quirks
- The ESP32 core ships its own SD library (
SD.hon top of SPI). Don’t install the Arduino “SD” library — it’s for AVR boards and gets in the way. - GPIO18/19/23 are the VSPI bus, the default
SPIpins on the DevKit V1, soSD.begin(5)needs no other setup. - The module’s level shifter (74LVC125) outputs 3.3 V, so MISO is safe for the ESP32 even though the module runs from 5 V.
- On many of these modules MISO never goes high-impedance. Sharing the SPI bus with an RC522 or a TFT then fails. Give the other device its own bus (HSPI on 12/13/14/15 is risky at boot), or use a module without the level shifter.
- Cards over 32 GB come formatted exFAT. Reformat them as FAT32 (a tool like “guiformat” on Windows) or they won’t mount.
- The sketch closes the file after every line. During a power cut you lose at most one line, not the whole file.
Code
// microSD card module on an ESP32 DevKit V1 — mount, show card info, append a log line every 5 s.
// CS → D5, SCK → D18, MISO → D19, MOSI → D23 (VSPI), VCC → VIN (5 V), GND → GND.
// Uses the SD library built into the ESP32 core. Card: FAT32, 32 GB or smaller.
#include <SPI.h>
#include <SD.h>
constexpr uint8_t CS_PIN = 5; // VSPI's default SS
const char *LOG = "/log.txt";
void setup() {
Serial.begin(115200);
if (!SD.begin(CS_PIN)) { // VSPI pins 18/19/23 are the default SPI bus
Serial.println("Card mount failed — check wiring, 5 V on VCC and a FAT32 card");
while (true) delay(1000);
}
const char *type[] = {"none", "MMC", "SDSC", "SDHC/SDXC", "unknown"};
uint8_t t = SD.cardType();
Serial.printf("Card: %s, %llu MB\n", type[t > 4 ? 4 : t], SD.cardSize() / (1024ULL * 1024ULL));
}
void loop() {
File f = SD.open(LOG, FILE_APPEND);
if (!f) {
Serial.println("Could not open /log.txt");
} else {
f.printf("%lu ms, uptime %lu s\n", millis(), millis() / 1000);
f.close(); // close (or flush) every time — a power cut loses only the last line
File r = SD.open(LOG);
Serial.printf("Appended to %s (%u bytes)\n", LOG, (unsigned)r.size());
r.close();
}
delay(5000);
}// microSD card module on an ESP32 DevKit V1 — mount, show card info, append a log line every 5 s.
// CS → D5, SCK → D18, MISO → D19, MOSI → D23 (VSPI), VCC → VIN (5 V), GND → GND.
// Uses the SD library built into the ESP32 core. Card: FAT32, 32 GB or smaller.
#include <SPI.h>
#include <SD.h>
constexpr uint8_t CS_PIN = 5; // VSPI's default SS
const char *LOG = "/log.txt";
void setup() {
Serial.begin(115200);
if (!SD.begin(CS_PIN)) { // VSPI pins 18/19/23 are the default SPI bus
Serial.println("Card mount failed — check wiring, 5 V on VCC and a FAT32 card");
while (true) delay(1000);
}
const char *type[] = {"none", "MMC", "SDSC", "SDHC/SDXC", "unknown"};
uint8_t t = SD.cardType();
Serial.printf("Card: %s, %llu MB\n", type[t > 4 ? 4 : t], SD.cardSize() / (1024ULL * 1024ULL));
}
void loop() {
File f = SD.open(LOG, FILE_APPEND);
if (!f) {
Serial.println("Could not open /log.txt");
} else {
f.printf("%lu ms, uptime %lu s\n", millis(), millis() / 1000);
f.close(); // close (or flush) every time — a power cut loses only the last line
File r = SD.open(LOG);
Serial.printf("Appended to %s (%u bytes)\n", LOG, (unsigned)r.size());
r.close();
}
delay(5000);
}Library: SD (Arduino, SparkFun (ESP32 and Pico cores ship their own SD library)).
Expected serial output
Card: SDHC/SDXC, 15193 MB
Appended to /log.txt (19 bytes)
Appended to /log.txt (39 bytes)
Appended to /log.txt (61 bytes)Card: SDHC/SDXC, 15193 MB Appended to /log.txt (19 bytes) Appended to /log.txt (39 bytes) Appended to /log.txt (61 bytes)
Common errors
“Card mount failed”
Wiring (MISO/MOSI swapped is the usual one), VCC on 3V3 instead of 5 V, or an exFAT/NTFS card. Try another card of 32 GB or less, formatted FAT32.
Works alone, fails with a TFT or RFID on the same SPI bus
The module holds MISO and blocks the other device. Put the SD card on its own bus or use a module whose MISO is tri-stated.
Board won’t boot or upload with the card module attached
Something pulls GPIO5 low at reset. Check CS really goes to CS, or move CS to GPIO4 and use SD.begin(4).