ESP32 读取SD卡接口选择参考


ESP3232读取SD卡可以通过spi和sdmmc两种方式来读取,不过我们在市面上能买到的都基本上是4线的SPI接口的SD卡模块套件。

  • 卡类型有如下,8-9Pin被引出,但是安装到我们的卡套上就只剩下MOSI,MISO,SCK,CS,GND,VCC
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

ESP32一共有3组SPI接口

除了下面2两组,另外一组给片上的SPI flash使用。
在这里插入图片描述

SD接口

在Arduino libraries库当中SD接口大多采用的SD SPI总线传输模式。
SD实际上有更多的传输模式:

  • SPI总线模式:ESP32有1个以上的SPI总线,可以在初始化时自定义.
  • 1位/ 4位SD总线模式:ESP32提供了另一个名为SD_MMC的库来实现SD总线模式API
  • SD UHS-II模式:ESP32不支持.

ESP32 SPI接口,GPIO引脚映射

在这里插入图片描述

1位/ 4位SD总线的GPIO引脚映射不能更改。

  • 简单调用SD_MMC begin()初始4位SD总线模式:
    在这里插入图片描述
SD_MMC.begin();
  • 可以在SD_MMC begin()方法中选择1位SD总线模式:
SD_MMC.begin("/cdcard", true);
  • 可以在创建SPIClass实例时选择SPI总线(HSPI或VSPI)
SPIClass spi = SPIClass(HSPI);

如你所见,1位/ 4位SD总线引脚与HSPI共享引脚,但SD卡引脚的映射是不一样的。所以如果硬件按照SD总线的引脚图连接,就不能直接使用HSPI本地引脚。GPIO脚可以在SPIClass begin()方法中覆盖.

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

SD库也可以在SD begin()方法中覆盖SS引脚、SPI总线和总线频率.

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

不同模式下的测试的下载速度

在这里插入图片描述
在这里插入图片描述

测试程序

/*
 * Connect the SD card to the following pins:
 *
 * SD Card | ESP32
 *    D2       12
 *    D3       13
 *    CMD      15
 *    VSS      GND
 *    VDD      3.3V
 *    CLK      14
 *    VSS      GND
 *    D0       2  (add 1K pull up after flashing)
 *    D1       4
 */
#include "FS.h"
#include "SD.h"
#include "SD_MMC.h"

#define TEST_FILE_SIZE (4 * 1024 * 1024)

void testWriteFile(fs::FS &fs, const char *path, uint8_t *buf, int len)
{
  unsigned long start_time = millis();
  Serial.printf("Test write %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  int loop = TEST_FILE_SIZE / len;
  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("Write file used: %d ms, %f KB/s\n", time_used, (float)TEST_FILE_SIZE / time_used);
}

void testReadFile(fs::FS &fs, const char *path, uint8_t *buf, int len)
{
  unsigned long start_time = millis();
  Serial.printf("Test read %s\n", path);

  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }
  int loop = TEST_FILE_SIZE / len;
  while (loop--)
  {
    if (!file.read(buf, len)) {
      Serial.println("Read failed");
      return;
    }
  }
  file.close();
  unsigned long time_used = millis() - start_time;
  Serial.printf("Read file used: %d ms, %f KB/s\n", time_used, (float)TEST_FILE_SIZE / time_used);
}

void testIO(fs::FS &fs)
{
  /* malloc will not reset all bytes to zero, so it is a random data */
  uint8_t *buf = (uint8_t*)malloc(64 * 1024);

  testWriteFile(fs, "/test_1k.bin", buf, 1024);
  testWriteFile(fs, "/test_2k.bin", buf, 2 * 1024);
  testWriteFile(fs, "/test_4k.bin", buf, 4 * 1024);
  testWriteFile(fs, "/test_8k.bin", buf, 8 * 1024);
  testWriteFile(fs, "/test_16k.bin", buf, 16 * 1024);
  testWriteFile(fs, "/test_32k.bin", buf, 32 * 1024);
  testWriteFile(fs, "/test_64k.bin", buf, 64 * 1024);

  testReadFile(fs, "/test_1k.bin", buf, 1024);
  testReadFile(fs, "/test_2k.bin", buf, 2 * 1024);
  testReadFile(fs, "/test_4k.bin", buf, 4 * 1024);
  testReadFile(fs, "/test_8k.bin", buf, 8 * 1024);
  testReadFile(fs, "/test_16k.bin", buf, 16 * 1024);
  testReadFile(fs, "/test_32k.bin", buf, 32 * 1024);
  testReadFile(fs, "/test_64k.bin", buf, 64 * 1024);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  /* test SD_MMC 4-bit Mode */
//  if (!SD_MMC.begin()) {
//    Serial.println("Card Mount Failed");
//    return;
//  }
//  testIO(SD_MMC);

  /* test SD_MMC 1-bit Mode */
  if (!SD_MMC.begin("/cdcard", true)) {
    Serial.println("Card Mount Failed");
    return;
  }
  testIO(SD_MMC);

  /* test SD SPI Mode at HSPI */
//  SPIClass spi = SPIClass(HSPI);
//  spi.begin(14 /* SCK */, 2 /* MISO */, 15 /* MOSI */, 13 /* SS */);
//  if (!SD.begin(13 /* SS */, spi, 80000000)) {
//    Serial.println("Card Mount Failed");
//    return;
//  }
//  testIO(SD);

  /* test SD SPI Mode at VSPI */
//  SPIClass spi = SPIClass(VSPI);
//  spi.begin(18 /* SCK */, 19 /* MISO */, 23 /* MOSI */, 5 /* SS */);
//  if (!SD.begin(5 /* SS */, spi, 80000000)) {
//    Serial.println("Card Mount Failed");
//    return;
//  }
//  testIO(SD);
}

void loop() {
}
  • SD_MMC 4位模式基准测试

SanDisk 8 GB MicroSD

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
  • SD_MMC 1位模式基准测试

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
  • 在HSPI总线基准的SD SPI模式

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
  • 在VSPI总线基准的SD SPI模式

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

总结

4位SD总线模式有最好的性能,1位SD总线模式大约慢20%,SPI模式大约慢50%。其中一个主要原因是SD_MMC协议层没有实现任何类型的锁定,而SPI实现了。而且4位SD总线模式有双数据线,所以理论上速度加倍。但是我的旧MicroSD不支持4位SD总线模式。

  • 我推荐1位SD总线模式在大多数情况下,因为:

良好的性能
更好的SD卡兼容性
更宽松的SD上拉要求
只需要3个GPIO引脚
较小的代码配置
许多开发套件、开发板和转接板都可以使用该模式

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐