ESP32/Storage/38. microSD cards
Your chip
Your language
Storage · 38 of 81

microSD cards

Gigabytes for a couple of pounds, and the one thing nobody budgets for - the card occasionally stops for tens of milliseconds to reorganise itself, and a logger sampling on a timer loses every sample that lands in the gap.

/esp32/microsd-cards · arduino · S3

The pause you have to buffer around

SPI mode
400 kB/s
Samples per second200 Hz
RAM buffer before writing0.5 kB
Throughput
400 kB/s
Samples lost per pause
0
Buffer covers
107 ms
Four wires on any pins you like, at about 400 kB/s. That is plenty for a data logger and not enough for video. Two things bite here: cards want a 3.3 V supply that can deliver 100 mA bursts, and cheap breakout boards have a level shifter that only works in one direction, which fails as a card that mounts and then cannot be read.

SPI or SDMMC

SPI — four wires on any pins, about 400 kB/s, works on every chip. Right for almost every project.

SDMMC — one or four data lines on fixed pins, two to five times faster, and on the classic ESP32 those pins include GPIO 2 and 15, which are strapping pins. Worth it for audio or camera work, not for a data logger.

Habits that keep a logger alive

  • Open the file once, not per row.
  • Buffer a few kilobytes and write blocks.
  • Flush on a timer, so a power cut costs seconds rather than everything.
  • Start a new file per hour or per day; a corrupt tail then costs one file.
  • Write CSV. It survives being read by anything, including a person.
On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

Buffer in RAM, write in blocks, keep the file open. Opening and closing a file per reading is what makes SD logging slow and what wears the card out fastest.

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

const int CS = 5;
File log;
char buf[2048];
size_t used = 0;

void setup() {
  Serial.begin(115200);
  if (!SD.begin(CS)) { Serial.println("no card"); return; }
  log = SD.open("/data.csv", FILE_APPEND);
}

void addRow(unsigned long t, float v) {
  used += snprintf(buf + used, sizeof(buf) - used, "%lu,%.2f\n", t, v);
  if (used > sizeof(buf) - 64) {          // write a block at a time
    log.write((uint8_t *)buf, used);
    used = 0;
  }
}

void loop() {
  static unsigned long lastFlush = 0;
  addRow(millis(), analogRead(34) * 3.3 / 4095);
  if (millis() - lastFlush > 10000) {     // survive a power cut
    log.flush();
    lastFlush = millis();
  }
  delay(10);
}

Flush on a timer rather than on every write. An unflushed file loses its tail on a power cut, and flushing every row costs most of the throughput.

When it does not work

Card mount failed on a card that works in my laptop

Formatting or wiring. FAT32, one partition, 32 GB or less is the safe combination. Then check that the breakout's level shifter works in both directions - many cheap ones do not.

Samples go missing at regular intervals

The card pausing for internal housekeeping. Nothing is wrong with your code. Buffer a few kilobytes in RAM so the pause is covered.

The board resets when the card is inserted

Current. A card draws 100 mA in bursts, and on the classic ESP32 the SDMMC pins include strapping pins - a card present at boot can also stop the board starting.

The last few minutes of data are missing after a power cut

The file was never flushed. Flush on a timer, and accept losing that window - or write to a new file each hour so a corrupt tail costs less.

Where this goes next

All three stores live in the same chip, divided by a table you have never looked at. This is that table.

Partition tables and flash size

Edit this page — content/esp32/microsd-cards.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse ESP32 on the forum