I have also been having issues with SD speed and have been troubleshooting.
I found a benchmarking sketch that helped me. (
https://www.instructables.com/Select-SD ... for-ESP32/)
I modified it heavily to test with an ESP-Cam board. (MISO:2 MOSI:15 SCK:14 CS:13) and runs in 1bit/4bit/SPI modes. (well SPI is more a crawl)
I tested with this code on the current Arduino IDE and found the throughput to be very low (read of about 1KB/Sec).
After looking for other examples I tried the same code under PlatformIO's Arduino Framework, and it just worked.
Further reading got me to check the speed that the SPI interface is set at.
This is not the fix for the current ESP32 board package but makes a ridiculous improvement on the ones that do work.
By default the SD library sets the SPI speed at 4MHz.
After a lot of reading and testing I have found 40MHz works much better on an ESP32.
SD.begin(13,spi,40000000)
Then I started with older versions in Arduino.
From what I can see:
Arduino ESP32 board package V2.0.2 is based on SDK V4.4-beta (latest as at writing) : SPI effectively a fail, 1bit & 4bit are good but not terrific.
Arduino ESP32 board package V2.0.0 is based on SDK V4.4-dev : SPI works but second slowest, 1bit & 4bit is quickest on reads.
PlatformIO-Arduino Framework is V3.5.0 is based on SDK V3.3.5 (latest as at writing) : SPI works really well - 2 to 3 times the rate of V2.0.0, 1bit & 4bit are good.
Arduino ESP32 board package 1.0.6 is based on SDK V3.3.5 : Works almost same identically as PlatformIO (expected as is same version of SDK).
I have not been able to find the solution yet to get the speed of the SD-SPI rates of 1.0.6 in 2.0.x, but can at least get SD cards working in SPI mode in 2.0.0.
I have a large project that I am working on, and conversion to back to 1.0.6 is complicated due to dependencies, and I would also prefer to use SPI so I can use different pins to not conflict with flashing via serial.
I hope the details help, please post if you find a solution.
Here are my speed results across the 3 modes and across 7 block sizes. my code
Code: Select all
/*
* Original Benchmark code from : https://www.instructables.com/Select-SD-Interface-for-ESP32/ by 陳亮
*
* Updated by James Wallis 2022
* Connect the SD card to the following pins: *
* SD Card | ESP32
* CMD 15
* VSS GND
* VDD 3.3V
* CLK 14
* VSS GND
* D0 2 //some notes say to add 1K pull up after flashing, seems to work without it.
* D1 4 //only for 4bit
* D2 12 //only for 4bit
* D3 13 //only for 4bit
*/
#define SD_MODE_4pin
#define SD_MODE_1pin
//#define SD_MODE_SPI
#include "FS.h"
#include "SD.h"
#include "SD_MMC.h"
#include "core_version.h"
int TEST_FILE_SIZE = (1024 * 1024); // 1 MB
//int TEST_FILE_SIZE =(64* 1024); // 64K for when it gets so very slow.
void TestSDFile(fs::FS &fs, const char *path, uint8_t *buf, int len)
{
// First do write benchmark
unsigned long start_time = millis();
File file = fs.open(path, FILE_WRITE);
if (!file) { Serial.println("Failed to open file for writing"); return; }
int loop = TEST_FILE_SIZE / len;
Serial.printf("%5d passes @ %2dKB = %d\t",loop,len/1024,TEST_FILE_SIZE);
while (loop--) { if (!file.write(buf, len)) {Serial.println("Write failed");return; }}
file.flush();
file.close();
unsigned long time_used = millis() - start_time;
Serial.printf("%5d\t", int(TEST_FILE_SIZE / time_used));
// Secondly do read benchmark
start_time = millis();
file = fs.open(path);
if (!file) {Serial.println("Failed to open file for reading"); return; }
loop = TEST_FILE_SIZE / len;
while (loop--) { if (!file.read(buf, len)) { Serial.println("Read failed"); return; }}
file.close();
time_used = millis() - start_time;
Serial.printf("%5d\r\n", int(TEST_FILE_SIZE / time_used));
}
void testIO(fs::FS &fs)
{
uint8_t *buf = (uint8_t*) malloc(64 * 1024); /* malloc will not reset all bytes to zero, so it is a random data */
TestSDFile(fs, "/test_1k.bin", buf, 1024);
TestSDFile(fs, "/test_2k.bin", buf, 2 * 1024);
TestSDFile(fs, "/test_4k.bin", buf, 4 * 1024);
TestSDFile(fs, "/test_8k.bin", buf, 8 * 1024);
TestSDFile(fs, "/test_16k.bin", buf, 16 * 1024);
TestSDFile(fs, "/test_32k.bin", buf, 32 * 1024);
TestSDFile(fs, "/test_64k.bin", buf, 64 * 1024);
Serial.println("Done.");
}
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("5 seconds to clear screen and insert SD");
delay(5000);
Serial.printf("SDK Version : %s Arduino Version : %s\r\n",ESP.getSdkVersion(),ARDUINO_ESP32_RELEASE);
#ifdef SD_MODE_4pin
Serial.println("4bit");
if (!SD_MMC.begin("/sdcard", false)) Serial.println("Card Mount Failed");
else testIO(SD_MMC);
#endif
#ifdef SD_MODE_1pin
Serial.println("1bit");
if (!SD_MMC.begin("/sdcard", true)) Serial.println("Card Mount Failed");
else testIO(SD_MMC);
#endif
#ifdef SD_MODE_SPI
Serial.println("SPI_HSPI");
SPIClass spi = SPIClass(HSPI);
spi.begin(14 , 2 , 15 , 13 );// spi.begin(SCK,MISO,MOSI,CS);
// SD.begin defaults to 4MHz,
if (!SD.begin(13,spi,40000000)) Serial.println("Card Mount Failed");
else testIO(SD);
#endif
}
void loop() {}