Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ESP32-S3 SDใ‚ซใƒผใƒ‰ๆ›ธใ่พผใฟ้€Ÿๅบฆๆฏ”่ผƒ

Last updated at Posted at 2024-11-24

ใฏใ˜ใ‚ใซ

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ใคใ‚’่ฉ•ไพกใ—ใพใ—ใŸใ€‚

  1. ๆ›ธใ่พผใฟ้€Ÿๅบฆ๏ผˆMB/s๏ผ‰
    • ไธ€ๅฎšใ‚ตใ‚คใ‚บใฎใƒ‡ใƒผใ‚ฟใ‚’ๆ›ธใ่พผใ‚€ๆ™‚้–“ใ‚’่จˆๆธฌ
  2. ใƒฌใ‚คใƒ†ใƒณใ‚ท๏ผˆms๏ผ‰
    • ๆ›ธใ่พผใฟ้–‹ๅง‹ใ‹ใ‚‰ๅฎŒไบ†ใพใงใฎ้…ๅปถๆ™‚้–“
    • ๆœ€ๅคง/ๅนณๅ‡/ๆœ€ๅฐใ‚’่จˆๆธฌ
  3. IOPS (Input/Output Operations Per Second)
    • 1็ง’ใ‚ใŸใ‚Šใฎๆ›ธใ่พผใฟๆ“ไฝœๅ›žๆ•ฐ

๏ผˆๆœฌๅฝ“ใฏSDใ‚ซใƒผใƒ‰ใ‚‚ๆ•ฐ็จฎ้กžๆบ–ๅ‚™ใ—ใŸๆ–นใŒ่‰ฏใ„ใงใ™ใŒใ€ใŠ้‡‘ใŒใชใ„ใŸใ‚ใ€ๅฎถใซใ‚ใฃใŸ1็จฎ้กžใฎใฟใง่ฉ•ไพกใ—ใพใ—ใŸใ€‚๏ผ‰

ใƒ•ใ‚กใ‚คใƒซใ‚ตใ‚คใ‚บใฏใ€64KB/256KB/1MBใฎ3็จฎ้กžใงใ€ใใ‚Œใžใ‚Œใฎใƒ•ใ‚กใ‚คใƒซใ‚ตใ‚คใ‚บใ€ใƒฉใ‚คใƒ–ใƒฉใƒชใง10ๅ›žใšใคๆธฌๅฎšใ—ใ€ๅนณๅ‡ใ‚’ๆฑ‚ใ‚ใพใ—ใŸใ€‚

ใ‚ณใƒผใƒ‰

SD_MMC.h
main.cpp
#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
main.cpp
#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
main.cpp
#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ใฎ้–“ใซใใ“ใใ“ๅฎน้‡ใฎๅคงใใ„ใƒ‘ใ‚นใ‚ณใƒณใ‚’้…็ฝฎใ—ใฆใใ ใ•ใ„ใ€‚

็ตๆžœ

้•ทใ„ใฎใงๅนณๅ‡ใฎใฟ่ผ‰ใ›ใพใ™ใ€‚

ๅ–ๅพ—ใ—ใŸๅ€คใฎๅนณๅ‡
image.png

ใ‚ฐใƒฉใƒ•
image.png

image.png

image.png

่ฆ‹ใšใ‚‰ใ„ใฎใงSDMMCใ‚’้™คใ„ใŸใ‚ฐใƒฉใƒ•ใ‚‚ไฝœๆˆใ—ใพใ—ใŸใ€‚
image.png

image.png

image.png

ๆธฌๅฎš็ตๆžœใ‹ใ‚‰

ๆ›ธใ่พผใฟ้€Ÿๅบฆใซใคใ„ใฆ

  • ๅ…จใฆใฎใƒ•ใ‚กใ‚คใƒซใ‚ตใ‚คใ‚บใง็ด„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ๅ›ž็›ฎ&ใƒกใƒขใ—ใชใŒใ‚‰ๆ›ธใ„ใŸ่จ˜ไบ‹ใชใฎใงใ€้–“้•ใ„็ญ‰ใ‚ใ‚Šใพใ—ใŸใ‚‰ใ‚ณใƒกใƒณใƒˆใงๆ•™ใˆใฆใ„ใŸใ ใ‘ใ‚‹ใจใ‚ใ‚ŠใŒใŸใ„ใงใ™ใ€‚

ๅ‚่€ƒใซใ—ใŸใ‚ตใ‚คใƒˆ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

@Kai0930's pickup articles

Kai0930

@Kai0930(Kai)

Next.js, React, Vue.js, Go, React Native, Flutter, Unity, GCP, AWSใชใฉ่‰ฒใ€…ๅ‹‰ๅผทไธญใงใ™ใ€‚

Today's trending articles

katohiro_fi

ITๆฅญ็•Œใซ่”“ๅปถใ™ใ‚‹ใ€ŽใƒŠใƒณใƒ‹ใƒ‡ใƒขPMใ€ ใใ‚Œใ€ๆœฌๅฝ“ใซใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใƒžใƒใ‚ธใƒกใƒณใƒˆ๏ผŸ

Comments

No comments

Let's comment your feelings that are more than good

Being held Article posting campaign

1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address