ใฏใใใซ
ESP32 WROOM 32EใงSdFat.hใไฝฟ็จใใฆ1kHzใฎใใผใฟใญใฎใณใฐใ่ฉฆใฟใ้ใซๆง่ฝไธ่ถณใฎๅ้กใซ็ด้ขใใพใใใ
ใใใงใๆฌกไธไปฃๆฉใจใใฆESP32 S3ใธใฎ็งป่กใๆค่จใใใซใใใใไปฅไธใฎ3ใคใฎSDใซใผใใฉใคใใฉใชใฎๆง่ฝใๆฏ่ผ่ฉไพกใใพใใใ
- SD.h - Arduinoๆจๆบใฉใคใใฉใช
- SdFat.h - ้ซๆง่ฝใ่ฌณใใตใผใใใผใใฃใฉใคใใฉใช
- SD_MMC.h - ESP32ใฎMMCใขใผใๅฐ็จใฉใคใใฉใช
ๆฌ่จไบใฏๆฆ็ฅ็ใชๆง่ฝๆฏ่ผใ็ฎ็ใจใใฆใใใๅณๅฏใชๆธฌๅฎใงใฏใใใพใใใ
็ฐๅข
- macOS Sonoma
- PlatformIO
- ESP32-S3- ้็บใใผใ
- ใใคใฏใญSDใซใผใในใญใใDIPๅใญใใ
- KIOXIAใใคใฏใญSDใซใผใ16GB
่ฉไพกๆนๆณ
ๆฌกใฎ3ใคใ่ฉไพกใใพใใใ
- ๆธใ่พผใฟ้ๅบฆ๏ผMB/s๏ผ
- ไธๅฎใตใคใบใฎใใผใฟใๆธใ่พผใๆ้ใ่จๆธฌ
- ใฌใคใใณใท๏ผms๏ผ
- ๆธใ่พผใฟ้ๅงใใๅฎไบใพใงใฎ้ ๅปถๆ้
- ๆๅคง/ๅนณๅ/ๆๅฐใ่จๆธฌ
- IOPS (Input/Output Operations Per Second)
- 1็งใใใใฎๆธใ่พผใฟๆไฝๅๆฐ
๏ผๆฌๅฝใฏSDใซใผใใๆฐ็จฎ้กๆบๅใใๆนใ่ฏใใงใใใใ้ใใชใใใใๅฎถใซใใฃใ1็จฎ้กใฎใฟใง่ฉไพกใใพใใใ๏ผ
ใใกใคใซใตใคใบใฏใ64KB/256KB/1MBใฎ3็จฎ้กใงใใใใใใฎใใกใคใซใตใคใบใใฉใคใใฉใชใง10ๅใใคๆธฌๅฎใใๅนณๅใๆฑใใพใใใ
ใณใผใ
SD_MMC.h
#include <Arduino.h>
#include <SD_MMC.h>
class SDMMCBenchmark {
private:
const size_t BUFFER_SIZE = 512;
uint8_t *buffer;
public:
SDMMCBenchmark() {
buffer = new uint8_t[BUFFER_SIZE];
for (size_t i = 0; i < BUFFER_SIZE; i++) {
buffer[i] = random(0, 255);
}
}
~SDMMCBenchmark() { delete[] buffer; }
void printCSVHeader() {
Serial.println(
"Iteration,FileSize(KB),BlockSize(B),WriteSpeed(MB/s),Latency(ms),MinLatency(ms),MaxLatency(ms),IOPS");
}
void runBenchmark(const char *filename, size_t totalBytes, int iterations = 10) {
for (int i = 0; i < iterations; i++) {
File file = SD_MMC.open(filename, FILE_WRITE);
if (!file) {
Serial.println("Error: Failed to open file for writing");
return;
}
unsigned long startTime = millis();
size_t bytesWritten = 0;
int operations = 0;
float minLatency = 999999;
float maxLatency = 0;
float totalLatency = 0;
while (bytesWritten < totalBytes) {
unsigned long writeStart = micros();
size_t written = file.write(buffer, BUFFER_SIZE);
unsigned long writeEnd = micros();
float latency = (writeEnd - writeStart) / 1000.0;
minLatency = min(minLatency, latency);
maxLatency = max(maxLatency, latency);
totalLatency += latency;
bytesWritten += written;
operations++;
}
unsigned long endTime = millis();
float duration = (endTime - startTime) / 1000.0;
float speed = (bytesWritten / 1024.0 / 1024.0) / duration;
float avgLatency = totalLatency / operations;
float iops = operations / duration;
Serial.print(i + 1);
Serial.print(",");
Serial.print(totalBytes / 1024.0, 2);
Serial.print(",");
Serial.print(BUFFER_SIZE);
Serial.print(",");
Serial.print(speed, 2);
Serial.print(",");
Serial.print(avgLatency, 2);
Serial.print(",");
Serial.print(minLatency, 2);
Serial.print(",");
Serial.print(maxLatency, 2);
Serial.print(",");
Serial.println(iops, 0);
file.close();
delay(3000);
}
}
};
void setup() {
Serial.begin(115200);
if (!SD_MMC.setPins(14, 15, 2, 4, 12, 13)) { // ใใใใฎใใณ็ชๅทใฏไพใงใ
Serial.println("Pin configuration failed!");
return;
}
if (!SD_MMC.begin()) {
Serial.println("SD_MMC initialization failed!");
return;
}
SDMMCBenchmark benchmark;
Serial.println("SD_MMC initialization succeeded!");
benchmark.printCSVHeader();
const size_t sizes[] = {64 * 1024, 256 * 1024, 1024 * 1024}; // 64KB, 256KB, 1MB
for (size_t size : sizes) {
String filename = "/test_" + String(size / 1024) + "kb.txt";
benchmark.runBenchmark(filename.c_str(), size);
delay(5000);
}
}
void loop() {
// Empty
}
SD.h
#include <Arduino.h>
#include <SD.h>
#define CUSTOM_CS 4
#define CUSTOM_MOSI 5
#define CUSTOM_MISO 6
#define CUSTOM_SCK 7
class SDBenchmark {
private:
const size_t BUFFER_SIZE = 512;
uint8_t *buffer;
const int chipSelect = CUSTOM_CS;
public:
SDBenchmark() {
buffer = new uint8_t[BUFFER_SIZE];
for (size_t i = 0; i < BUFFER_SIZE; i++) {
buffer[i] = random(0, 255);
}
}
~SDBenchmark() { delete[] buffer; }
void printCSVHeader() {
Serial.println(
"Iteration,FileSize(KB),BlockSize(B),WriteSpeed(MB/s),Latency(ms),MinLatency(ms),MaxLatency(ms),IOPS");
}
void runBenchmark(const char *filename, size_t totalBytes, int iterations = 10) {
for (int i = 0; i < iterations; i++) {
File file = SD.open(filename, FILE_WRITE);
if (!file) {
Serial.println("Error: Failed to open file for writing");
return;
}
unsigned long startTime = millis();
size_t bytesWritten = 0;
int operations = 0;
float minLatency = 999999;
float maxLatency = 0;
float totalLatency = 0;
while (bytesWritten < totalBytes) {
unsigned long writeStart = micros();
size_t written = file.write(buffer, BUFFER_SIZE);
unsigned long writeEnd = micros();
float latency = (writeEnd - writeStart) / 1000.0;
minLatency = min(minLatency, latency);
maxLatency = max(maxLatency, latency);
totalLatency += latency;
bytesWritten += written;
operations++;
}
unsigned long endTime = millis();
float duration = (endTime - startTime) / 1000.0;
float speed = (bytesWritten / 1024.0 / 1024.0) / duration;
float avgLatency = totalLatency / operations;
float iops = operations / duration;
Serial.print(i + 1);
Serial.print(",");
Serial.print(totalBytes / 1024.0, 2);
Serial.print(",");
Serial.print(BUFFER_SIZE);
Serial.print(",");
Serial.print(speed, 2);
Serial.print(",");
Serial.print(avgLatency, 2);
Serial.print(",");
Serial.print(minLatency, 2);
Serial.print(",");
Serial.print(maxLatency, 2);
Serial.print(",");
Serial.println(iops, 0);
file.close();
delay(3000);
}
}
};
void setup() {
Serial.begin(115200);
SPI.begin(CUSTOM_SCK, CUSTOM_MISO, CUSTOM_MOSI, CUSTOM_CS);
SPI.setDataMode(SPI_MODE0);
if (!SD.begin(CUSTOM_CS)) {
Serial.println("SD initialization failed!");
return;
}
SDBenchmark benchmark;
Serial.println("SD initialization succeeded!");
benchmark.printCSVHeader();
const size_t sizes[] = {64 * 1024, 256 * 1024, 1024 * 1024}; // 64KB, 256KB, 1MB
for (size_t size : sizes) {
String filename = "/test_" + String(size / 1024) + "kb.txt";
benchmark.runBenchmark(filename.c_str(), size);
delay(5000);
}
}
void loop() {
// Empty
}
SdFat.h
#include <Arduino.h>
#include <SPI.h>
#include <SdFat.h>
#define CUSTOM_CS 4
#define CUSTOM_MOSI 5
#define CUSTOM_MISO 6
#define CUSTOM_SCK 7
SdFat SDFAT;
class SDBenchmark {
private:
const size_t BUFFER_SIZE = 512;
uint8_t *buffer;
const int chipSelect = CUSTOM_CS;
public:
SDBenchmark() {
buffer = new uint8_t[BUFFER_SIZE];
for (size_t i = 0; i < BUFFER_SIZE; i++) {
buffer[i] = random(0, 255);
}
}
~SDBenchmark() { delete[] buffer; }
void printCSVHeader() {
Serial.println(
"Iteration,FileSize(KB),BlockSize(B),WriteSpeed(MB/s),Latency(ms),MinLatency(ms),MaxLatency(ms),IOPS");
}
void runBenchmark(const char *filename, size_t totalBytes, int iterations = 10) {
for (int i = 0; i < iterations; i++) {
File32 file;
file.open(filename, O_RDWR | O_CREAT | O_AT_END);
if (!file) {
Serial.println("Error: Failed to open file for writing");
return;
}
unsigned long startTime = millis();
size_t bytesWritten = 0;
int operations = 0;
float minLatency = 999999;
float maxLatency = 0;
float totalLatency = 0;
while (bytesWritten < totalBytes) {
unsigned long writeStart = micros();
size_t written = file.write(buffer, BUFFER_SIZE);
unsigned long writeEnd = micros();
float latency = (writeEnd - writeStart) / 1000.0;
minLatency = min(minLatency, latency);
maxLatency = max(maxLatency, latency);
totalLatency += latency;
bytesWritten += written;
operations++;
}
unsigned long endTime = millis();
float duration = (endTime - startTime) / 1000.0;
float speed = (bytesWritten / 1024.0 / 1024.0) / duration;
float avgLatency = totalLatency / operations;
float iops = operations / duration;
Serial.print(i + 1);
Serial.print(",");
Serial.print(totalBytes / 1024.0, 2);
Serial.print(",");
Serial.print(BUFFER_SIZE);
Serial.print(",");
Serial.print(speed, 2);
Serial.print(",");
Serial.print(avgLatency, 2);
Serial.print(",");
Serial.print(minLatency, 2);
Serial.print(",");
Serial.print(maxLatency, 2);
Serial.print(",");
Serial.println(iops, 0);
file.close();
delay(3000);
}
}
};
void setup() {
Serial.begin(115200);
SPI.begin(CUSTOM_SCK, CUSTOM_MISO, CUSTOM_MOSI, CUSTOM_CS);
SPI.setDataMode(SPI_MODE0);
if (!SDFAT.begin(CUSTOM_CS, SD_SCK_MHZ(10))) {
Serial.println("SD initialization failed!");
return;
}
SDBenchmark benchmark;
Serial.println("SD initialization succeeded!");
benchmark.printCSVHeader();
const size_t sizes[] = {64 * 1024, 256 * 1024, 1024 * 1024}; // 64KB, 256KB, 1MB
for (size_t size : sizes) {
String filename = "/test_" + String(size / 1024) + "kb.txt";
benchmark.runBenchmark(filename.c_str(), size);
delay(5000);
}
}
void loop() {
// Empty
}
ใใณๆฅ็ถ
SD.h&SdFat.h
| ESP32 pin | SPI pin name | SD card pin | Notes |
|---|---|---|---|
| 4 | CS | CS | - |
| 5 | MOSI | MOSI/DI | 10k pullup |
| 6 | MISO | MISO/DO | 10k pullup |
| 7 | SCK | SCK/CLK | 10k pullup |
SD_MMC.h
| ESP32 pin | SD card pin | Notes |
|---|---|---|
| IO14 | CLK | 10k pullup |
| IO15 | CMD | 10k pullup |
| IO2 | D0 | 10k pullup |
| IO4 | D1 | 10k pullup |
| IO12 | D2 | 10k pullup |
| IO13 | D3 | 10k pullup |
ใฉใกใใจใVSSใจVDDใฎ้ใซใใใใๅฎน้ใฎๅคงใใใในใณใณใ้ ็ฝฎใใฆใใ ใใใ
็ตๆ
้ทใใฎใงๅนณๅใฎใฟ่ผใใพใใ
่ฆใใใใฎใงSDMMCใ้คใใใฐใฉใใไฝๆใใพใใใ
ๆธฌๅฎ็ตๆใใ
ๆธใ่พผใฟ้ๅบฆใซใคใใฆ
- ๅ จใฆใฎใใกใคใซใตใคใบใง็ด3.9MB/sใ็ถญๆ
- SD.hใSdFat.hใจๆฏ่ผใใฆ็ด8-9ๅใฎ้ๅบฆๅทฎ
- ใใกใคใซใตใคใบใซใใๆง่ฝๅคๅใๅฐใชใ
- SD.hใจSdFat.hใฏใปใผๅใใ ใใSdFat.hใใใ้ใ
-> SD.hใSdFat.hใใใผใฟ็ท2ๆฌใฎSPIใซๅฏพใใฆSD_MMC.hใฏ4ๆฌใ ใใ๏ผ
ใฌใคใใณใทใซใคใใฆ
- SD_MMC.hใฏๆๅฐใฌใคใใณใทใง0.05msไปฅไธใๅฎ็พ
- SD.hใจSdFat.hใฏไผผใๅพๅใ็คบใใใSdFat.hใใใ็ญใ
IOPSใซใคใใฆ
- SD_MMC.hใๆใ้ซใ
- ใใกใคใซใตใคใบใๅคงใใใชใใซใคใใฆIOPSใฏไฝไธๅพๅ
็ตใใใซ
ๆใฃใใใSD_MMCใๅงๅ็ใช้ใใงใใใ
Qiitaๆ็จฟ2ๅ็ฎ&ใกใขใใชใใๆธใใ่จไบใชใฎใงใ้้ใ็ญใใใพใใใใณใกใณใใงๆใใฆใใใ ใใใจใใใใใใงใใ
ๅ่ใซใใใตใคใ







Comments
Let's comment your feelings that are more than good