Introduction: Select SD Interface for ESP32

About: Make it yourself if you cannot buy one ;)

This instructables show something about selecting a SD interface for your ESP32 project.

Step 1: SD Interface

In original Arduino SD library, SD Interface is using SD SPI bus transfer mode.

SD actually have more transfer mode:

  • SPI bus mode: ESP32 have more than 1 SPI bus, it can customize while initialization
  • 1-bit / 4-bit SD bus mode: ESP32 dedicate another library called SD_MMC to implement the SD bus mode API
  • SD UHS-II mode: ESP32 not supported

Ref.:

https://www.arduino.cc/en/reference/SD

https://en.wikipedia.org/wiki/SD_card

https://docs.espressif.com/projects/esp-idf/en/lat...

Step 2: ESP32 GPIO Pins Mapping

Here are the default ESP32 GPIO pins mapping:

SD card pinMicroSD pinName4-bit SD bus1-bit SD busSPI bus
(HSPI / VSPI
native pins)
1 2 D3 13 - SS (15 / 5)
2 3 CMD 15 15 MOSI (13 / 23)
3 - VSS GND GND GND
4 4 VDD 3.3V 3.3V 3.3V
5 5 CLK 14 14 SCK (14 / 18)
6 6 VSS GND GND GND
7 7 D0 2 2 MISO (12 / 19)
8 8 D1 4 - -
9 1 D2 12 - -

The GPIO pins mapping of 1-bit / 4-bit SD bus cannot be changed.

Simple call SD_MMC begin() to initial 4-bit SD bus mode:

SD_MMC.begin();

1-bit SD bus mode can be selected at SD_MMC begin() method, e.g.

SD_MMC.begin("/cdcard", true);

The SPI bus (HSPI or VSPI) can be selected while create the SPIClass instance, e.g.

SPIClass spi = SPIClass(HSPI);

As you can see 1-bit / 4-bit SD bus pin share pins with HSPI but the SD card pins mapping are not the same. So if the hardware connected according to SD bus pin map, it cannot direct use HSPI native pins. The GPIO pins can be override at SPIClass begin() method, e.g.

SPIClass spi = SPIClass(HSPI);
spi.begin(14 /* SCK */, 2 /* MISO */, 15 /* MOSI */, 13 /* SS */);

And also SD library can override SS pin, SPI bus and bus frequency at SD begin() method, e.g.

SD.begin(13 /* SS */, spi, 80000000);

Step 3: SD Pull-up Requirements

If you want to use 4-bit SD bus mode, please sticky follow the ESP32 SD Pull-up Requirements, especially:

  • Pull-up Conflicts on GPIO13
  • Conflicts Between Bootstrap and SDIO on DAT2

Ref.:

https://docs.espressif.com/projects/esp-idf/en/lat...

Step 4: Various Hardware

ESP32 have tons of dev kit and dev board, some of them have built-in MicroSD card slot.

Here are some example in my hand:

  • TTGO T-Watch, it connected to GPIO pins 2, 13, 14 and 15 according to 1-bit SD bus mode, so it can use 1-bit SD bus mode and SPI bus mode
  • M5Stack Series, it connected to GPIO pins 4, 18, 19 and 23 according to VSPI native pins, so it can use default SD library settings [SD.begin(4)]
  • ODROID-GO, it connected to GPIO pins 18, 19, 22 and 23 according to VSPI native pins, so it can use default SD library settings [SD.begin(22)]
  • ESP32-CAM, it connected to GPIO pins 2, 4, 12, 13, 14 and 15 according to 4-bit SD bus mode, so it can use all 4-bit / 1-bit SD bus mode and SPI bus mode
  • TTGO T8 dev board, it connected to GPIO pins 2, 13, 14 and 15 according to 1-bit SD bus mode, so it can use 1-bit SD bus mode and SPI bus mode

http://www.lilygo.cn/prod_view.aspx?Id=1123

https://docs.m5stack.com/

https://wiki.odroid.com/odroid_go/odroid_go

http://wiki.ai-thinker.com/esp32-cam

https://github.com/LilyGO/TTGO-T8-ESP32

Step 5: SD Card Slot Breakout Board

Dev board with built-in MicroSD card slot may not connected all pins and most cannot use 4-bit SD bus mode. An individual SD card slot breakout board provide better flexibility.

At the same time, many LCD breakout board also breakout a full size SD card slot. However, most of them only break out the SPI mode pins. It is not enough to use as 4-bit SD bus mode, but you can still use it as 1-bit SD bus mode by this connection mapping:

LCD     -> ESP32
SD_CS   -> nil
SD_MOSI -> 15
SD_MISO -> 2
SD_SCK  -> 14

Step 6: Detach GPIO 2 While Program

The 4-bit SD bus mode connection make ESP32 failed to enter program mode. Please remember detach the GPIO 2 from SD card slot breakout board DAT0 before upload new program.

Step 7: Benchmark

I have written a simple Arduino program for the benchmark:

https://github.com/moononournation/ESP32_SD_Benchm...

Here are the hardware for the benchmark:

ESP32

NodeMCU ESP32-32S V1.1 (WROOM-32)

SD Card Slot

A MicroSD card slot breakout board

SD Card

I have a SanDisk 8 GB MicroSD and an old 128 MB MicroSD in hand.

Step 8: SD_MMC 4-bit Mode Benchmark

SanDisk 8 GB MicroSD

20:27:46.000 -> Test write /test_1k.bin
20:27:59.399 -> Write file used: 13404 ms, 312.914368 KB/s
20:27:59.399 -> Test write /test_2k.bin
20:28:17.248 -> Write file used: 17834 ms, 235.185822 KB/s
20:28:17.248 -> Test write /test_4k.bin
20:28:21.122 -> Write file used: 3873 ms, 1082.959961 KB/s
20:28:21.122 -> Test write /test_8k.bin
20:28:23.147 -> Write file used: 2024 ms, 2072.284668 KB/s
20:28:23.147 -> Test write /test_16k.bin
20:28:27.237 -> Write file used: 4097 ms, 1023.750061 KB/s
20:28:27.237 -> Test write /test_32k.bin
20:28:30.088 -> Write file used: 2842 ms, 1475.828247 KB/s
20:28:30.088 -> Test write /test_64k.bin
20:28:31.882 -> Write file used: 1811 ms, 2316.015381 KB/s
20:28:31.882 -> Test read /test_1k.bin
20:28:35.422 -> Read file used: 3520 ms, 1191.563599 KB/s
20:28:35.422 -> Test read /test_2k.bin
20:28:38.813 -> Read file used: 3389 ms, 1237.622925 KB/s
20:28:38.813 -> Test read /test_4k.bin
20:28:42.273 -> Read file used: 3474 ms, 1207.341431 KB/s
20:28:42.273 -> Test read /test_8k.bin
20:28:45.752 -> Read file used: 3487 ms, 1202.840210 KB/s
20:28:45.752 -> Test read /test_16k.bin
20:28:48.988 -> Read file used: 3213 ms, 1305.416748 KB/s
20:28:48.988 -> Test read /test_32k.bin
20:28:52.077 -> Read file used: 3093 ms, 1356.063354 KB/s
20:28:52.077 -> Test read /test_64k.bin
20:28:55.141 -> Read file used: 3080 ms, 1361.786987 KB/s

Old 128 MB MicroSD

20:30:43.309 -> E (274) sdmmc_sd: sdmmc_check_scr: send_scr returned 0x109
20:30:43.309 -> Card Mount Failed

Step 9: SD_MMC 1-bit Mode Benchmark

SanDisk 8 GB MicroSD

20:31:45.194 -> Test write /test_1k.bin
20:31:59.506 -> Write file used: 14325 ms, 292.796082 KB/s
20:31:59.506 -> Test write /test_2k.bin
20:32:17.686 -> Write file used: 18163 ms, 230.925735 KB/s
20:32:17.686 -> Test write /test_4k.bin
20:32:21.291 -> Write file used: 3611 ms, 1161.535278 KB/s
20:32:21.291 -> Test write /test_8k.bin
20:32:23.939 -> Write file used: 2652 ms, 1581.562622 KB/s
20:32:23.939 -> Test write /test_16k.bin
20:32:28.397 -> Write file used: 4448 ms, 942.964050 KB/s
20:32:28.397 -> Test write /test_32k.bin
20:32:31.835 -> Write file used: 3429 ms, 1223.185791 KB/s
20:32:31.835 -> Test write /test_64k.bin
20:32:33.882 -> Write file used: 2058 ms, 2038.048584 KB/s
20:32:33.882 -> Test read /test_1k.bin
20:32:38.031 -> Read file used: 4146 ms, 1011.650757 KB/s
20:32:38.031 -> Test read /test_2k.bin
20:32:42.062 -> Read file used: 4019 ms, 1043.618774 KB/s
20:32:42.062 -> Test read /test_4k.bin
20:32:46.170 -> Read file used: 4106 ms, 1021.506104 KB/s
20:32:46.170 -> Test read /test_8k.bin
20:32:50.288 -> Read file used: 4121 ms, 1017.787903 KB/s
20:32:50.288 -> Test read /test_16k.bin
20:32:54.112 -> Read file used: 3840 ms, 1092.266724 KB/s
20:32:54.112 -> Test read /test_32k.bin
20:32:57.840 -> Read file used: 3739 ms, 1121.771606 KB/s
20:32:57.840 -> Test read /test_64k.bin
20:33:01.568 -> Read file used: 3711 ms, 1130.235474 KB/s

Old 128 MB MicroSD

20:33:27.366 -> Test write /test_1k.bin
20:33:42.386 -> Write file used: 15020 ms, 279.247925 KB/s
20:33:42.386 -> Test write /test_2k.bin
20:33:57.927 -> Write file used: 15515 ms, 270.338654 KB/s
20:33:57.927 -> Test write /test_4k.bin
20:34:13.108 -> Write file used: 15195 ms, 276.031860 KB/s
20:34:13.108 -> Test write /test_8k.bin
20:34:28.162 -> Write file used: 15048 ms, 278.728333 KB/s
20:34:28.162 -> Test write /test_16k.bin
20:34:43.287 -> Write file used: 15142 ms, 276.998016 KB/s
20:34:43.287 -> Test write /test_32k.bin
20:34:58.278 -> Write file used: 14964 ms, 280.292969 KB/s
20:34:58.278 -> Test write /test_64k.bin
20:35:13.370 -> Write file used: 15101 ms, 277.750092 KB/s
20:35:13.370 -> Test read /test_1k.bin
20:35:17.563 -> Read file used: 4197 ms, 999.357666 KB/s
20:35:17.563 -> Test read /test_2k.bin
20:35:21.746 -> Read file used: 4191 ms, 1000.788330 KB/s
20:35:21.746 -> Test read /test_4k.bin
20:35:25.942 -> Read file used: 4181 ms, 1003.182007 KB/s
20:35:25.942 -> Test read /test_8k.bin
20:35:30.101 -> Read file used: 4176 ms, 1004.383118 KB/s
20:35:30.101 -> Test read /test_16k.bin
20:35:34.279 -> Read file used: 4174 ms, 1004.864380 KB/s
20:35:34.279 -> Test read /test_32k.bin
20:35:38.462 -> Read file used: 4173 ms, 1005.105225 KB/s
20:35:38.462 -> Test read /test_64k.bin
20:35:42.612 -> Read file used: 4173 ms, 1005.105225 KB/s

Step 10: SD SPI Mode at HSPI Bus Benchmark

SanDisk 8 GB MicroSD

08:41:19.703 -> Test write /test_1k.bin
08:41:53.458 -> Write file used: 33743 ms, 124.301453 KB/s
08:41:53.458 -> Test write /test_2k.bin
08:42:10.000 -> Write file used: 16540 ms, 253.585495 KB/s
08:42:10.000 -> Test write /test_4k.bin
08:42:17.269 -> Write file used: 7298 ms, 574.719666 KB/s
08:42:17.308 -> Test write /test_8k.bin
08:42:22.640 -> Write file used: 5345 ms, 784.715454 KB/s
08:42:22.640 -> Test write /test_16k.bin
08:42:32.285 -> Write file used: 9662 ms, 434.103088 KB/s
08:42:32.285 -> Test write /test_32k.bin
08:42:36.659 -> Write file used: 4355 ms, 963.100830 KB/s
08:42:36.659 -> Test write /test_64k.bin
08:42:39.594 -> Write file used: 2949 ms, 1422.280151 KB/s
08:42:39.594 -> Test read /test_1k.bin
08:42:44.774 -> Read file used: 5192 ms, 807.839783 KB/s
08:42:44.774 -> Test read /test_2k.bin
08:42:49.969 -> Read file used: 5189 ms, 808.306824 KB/s
08:42:49.969 -> Test read /test_4k.bin
08:42:55.123 -> Read file used: 5161 ms, 812.692139 KB/s
08:42:55.158 -> Test read /test_8k.bin
08:43:00.300 -> Read file used: 5176 ms, 810.336914 KB/s
08:43:00.334 -> Test read /test_16k.bin
08:43:05.277 -> Read file used: 4948 ms, 847.676636 KB/s
08:43:05.277 -> Test read /test_32k.bin
08:43:10.028 -> Read file used: 4773 ms, 878.756348 KB/s
08:43:10.028 -> Test read /test_64k.bin
08:43:14.760 -> Read file used: 4731 ms, 886.557617 KB/s

Old 128 MB MicroSD

08:43:47.777 -> Test write /test_1k.bin
08:44:04.148 -> Write file used: 16390 ms, 255.906281 KB/s
08:44:04.183 -> Test write /test_2k.bin
08:44:20.648 -> Write file used: 16494 ms, 254.292709 KB/s
08:44:20.648 -> Test write /test_4k.bin
08:44:36.674 -> Write file used: 16001 ms, 262.127625 KB/s
08:44:36.674 -> Test write /test_8k.bin
08:44:52.849 -> Write file used: 16175 ms, 259.307831 KB/s
08:44:52.849 -> Test write /test_16k.bin
08:45:09.225 -> Write file used: 16397 ms, 255.797043 KB/s
08:45:09.225 -> Test write /test_32k.bin
08:45:25.363 -> Write file used: 16143 ms, 259.821838 KB/s
08:45:25.397 -> Test write /test_64k.bin
08:45:41.632 -> Write file used: 16263 ms, 257.904694 KB/s
08:45:41.632 -> Test read /test_1k.bin
08:45:46.488 -> Read file used: 4856 ms, 863.736389 KB/s
08:45:46.488 -> Test read /test_2k.bin
08:45:51.332 -> Read file used: 4840 ms, 866.591736 KB/s
08:45:51.332 -> Test read /test_4k.bin
08:45:56.163 -> Read file used: 4834 ms, 867.667358 KB/s
08:45:56.163 -> Test read /test_8k.bin
08:46:00.998 -> Read file used: 4827 ms, 868.925598 KB/s
08:46:00.998 -> Test read /test_16k.bin
08:46:05.808 -> Read file used: 4825 ms, 869.285828 KB/s
08:46:05.843 -> Test read /test_32k.bin
08:46:10.637 -> Read file used: 4824 ms, 869.466003 KB/s
08:46:10.637 -> Test read /test_64k.bin
08:46:15.478 -> Read file used: 4825 ms, 869.285828 KB/s

Step 11: SD SPI Mode at VSPI Bus Benchmark

SanDisk 8 GB MicroSD

08:54:17.412 -> Test write /test_1k.bin
08:54:48.398 -> Write file used: 30994 ms, 135.326324 KB/s
08:54:48.398 -> Test write /test_2k.bin
08:55:06.079 -> Write file used: 17677 ms, 237.274658 KB/s
08:55:06.079 -> Test write /test_4k.bin
08:55:13.357 -> Write file used: 7274 ms, 576.615906 KB/s
08:55:13.357 -> Test write /test_8k.bin
08:55:18.691 -> Write file used: 5323 ms, 787.958679 KB/s
08:55:18.691 -> Test write /test_16k.bin
08:55:28.336 -> Write file used: 9669 ms, 433.788818 KB/s
08:55:28.336 -> Test write /test_32k.bin
08:55:32.646 -> Write file used: 4309 ms, 973.382202 KB/s
08:55:32.646 -> Test write /test_64k.bin
08:55:35.551 -> Write file used: 2915 ms, 1438.869263 KB/s
08:55:35.584 -> Test read /test_1k.bin
08:55:40.745 -> Read file used: 5183 ms, 809.242554 KB/s
08:55:40.745 -> Test read /test_2k.bin
08:55:45.916 -> Read file used: 5182 ms, 809.398682 KB/s
08:55:45.949 -> Test read /test_4k.bin
08:55:51.091 -> Read file used: 5162 ms, 812.534668 KB/s
08:55:51.091 -> Test read /test_8k.bin
08:55:56.257 -> Read file used: 5177 ms, 810.180420 KB/s
08:55:56.293 -> Test read /test_16k.bin
08:56:01.244 -> Read file used: 4956 ms, 846.308289 KB/s
08:56:01.244 -> Test read /test_32k.bin
08:56:06.006 -> Read file used: 4764 ms, 880.416443 KB/s
08:56:06.006 -> Test read /test_64k.bin
08:56:10.716 -> Read file used: 4728 ms, 887.120117 KB/s

Old 128 MB MicroSD

08:51:01.939 -> Test write /test_1k.bin
08:51:18.358 -> Write file used: 16422 ms, 255.407623 KB/s
08:51:18.358 -> Test write /test_2k.bin
08:51:34.529 -> Write file used: 16173 ms, 259.339874 KB/s
08:51:34.529 -> Test write /test_4k.bin
08:51:50.911 -> Write file used: 16372 ms, 256.187653 KB/s
08:51:50.911 -> Test write /test_8k.bin
08:52:07.056 -> Write file used: 16137 ms, 259.918457 KB/s
08:52:07.056 -> Test write /test_16k.bin
08:52:23.383 -> Write file used: 16351 ms, 256.516663 KB/s
08:52:23.383 -> Test write /test_32k.bin
08:52:39.533 -> Write file used: 16128 ms, 260.063507 KB/s
08:52:39.533 -> Test write /test_64k.bin
08:52:55.764 -> Write file used: 16250 ms, 258.111023 KB/s
08:52:55.764 -> Test read /test_1k.bin
08:53:00.645 -> Read file used: 4855 ms, 863.914307 KB/s
08:53:00.645 -> Test read /test_2k.bin
08:53:05.459 -> Read file used: 4839 ms, 866.770813 KB/s
08:53:05.459 -> Test read /test_4k.bin
08:53:10.306 -> Read file used: 4833 ms, 867.846863 KB/s
08:53:10.306 -> Test read /test_8k.bin
08:53:15.127 -> Read file used: 4827 ms, 868.925598 KB/s
08:53:15.127 -> Test read /test_16k.bin
08:53:19.963 -> Read file used: 4826 ms, 869.105652 KB/s
08:53:19.963 -> Test read /test_32k.bin
08:53:24.758 -> Read file used: 4824 ms, 869.466003 KB/s
08:53:24.792 -> Test read /test_64k.bin
08:53:29.592 -> Read file used: 4824 ms, 869.466003 KB/s

Step 12: Round Up

4-bit SD bus mode has best performance, 1-bit SD bus mode is around 20% slower and SPI mode is around 50% slower. One of the main reason is SD_MMC protocol layer does not implement any kind of locking but SPI does. And also 4-bit SD bus mode has double data lines so theoretically double the speed. But my old MicroSD cannot support 4-bit SD bus mode.

I will recommend 1-bit SD bus mode in most case, because:

  • good performance
  • better SD card compatibility
  • looser SD Pull-up requirements
  • only 3 GPIO pins required
  • lesser code configuration
  • many dev kit, dev board and breakout board can use this mode