少走弯路,ESP32 使用Micro SD(TF)的经验说明

ESP32-S2 使用Micropython 读写tf卡(SPI协议) 使用Micropython 读写tf卡 SPI协议,OSError: timeout waiting for v2 card错误,OSError: [Errno 19] ENODEV错误 阅读详情
AI摘要

本文分享了作者使用ESP32及ESP32S3通过不同方式访问TF卡的经历,特别是解决了1-bit SDMMC模式下的常见问题,并提供了代码示例。

看了无数资料,各种折腾了4-5天后还是没有折腾通ESP32 通过1bit sdmmc方式访问TF卡,经常报错如下:

E (6054) sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107
E (7055) sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107
E (7055) sdmmc_req: handle_idle_state_events unhandled: 00001000 00000000
E (7059) sdmmc_req: handle_idle_state_events unhandled: 00001000 00000000
E (11065) sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107
E (11066) sdmmc_common: sdmmc_init_ocr: send_op_cond (1) returned 0x107
E (11070) vfs_fat_sdmmc: sdmmc_card_init failed (0x107).

通过关键信息:

sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107

去各种搜索,各种尝试始终没有答案。

如果你看到这里,别急,后面会有答案

我是为了使用TF卡,自己打了一块pcb板

 

最初看网上的资料说D0,D1,D2,D3,CMD 这些都需要接上拉10K的电阻, CLK不需要接

出于保险,CLK设计了电阻位,最初没有放上电阻

 esp32 对于tf卡的访问有三种模式:

4线SDMMC

1线SDMMC

SPI访问

4线访问由于端口冲突需要Setup中delay后再接入数据线


void setup()
{

    Serial.begin(115200);
    Serial.printf("\r\n开始SDMMC读取.");
    delay(7000);

    if (!SD_MMC.begin())
    {
        Serial.printf("\n SDMMC模式失败");
        return;
    }
    Serial.printf("\n启动成功");
      uint8_t cardType = SD_MMC.cardType();
    if (cardType == CARD_NONE) {
    Serial.println("No SD_MMC card attached");
    return;
  }

  Serial.print("SD_MMC Card Type: ");
  if (cardType == CARD_MMC) {
    Serial.println("MMC");
  } else if (cardType == CARD_SD) {
    Serial.println("SDSC");
  } else if (cardType == CARD_SDHC) {
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }

 
    Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
    SD_MMC.end();
}

除开D1,D2,D3不用接外1线SDMMC的访问大不同就是中间那句:

    if (!SD_MMC.begin("/sdcard",true))

代码就是这么简单,但是无论怎么都是报错:

E (6054) sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107
E (7055) sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107
E (7055) sdmmc_req: handle_idle_state_events unhandled: 00001000 00000000
E (7059) sdmmc_req: handle_idle_state_events unhandled: 00001000 00000000
E (11065) sdmmc_periph: sdmmc_host_clock_update_command(200): sdmmc_host_start_command returned 0x107
E (11066) sdmmc_common: sdmmc_init_ocr: send_op_cond (1) returned 0x107
E (11070) vfs_fat_sdmmc: sdmmc_card_init failed (0x107).

于是检查接线,反复检查,错误依然;

于是怀疑电路,接上CLK电阻,错误依然;反复贴和反复取下验证,反复用万用表测电压

网上有些说法是有些电阻可以不要,于是重新贴片,某些电阻不贴,还是不行

换单片机,从一块esp32换成了另外一块esp32.不行

怀疑卡座问题,飞线把引脚接地,最初是没有接GND的

怀疑没接的CD引脚问题

去esp32 forum中留言,无果

在4线和1线中反复横跳,无果

换线材,无果

从arduino换成了idf,从arduino ide换成platformio,还是无果

你能想到的可能的方案都尝试过

中间好像正确过,然后又统统不行了

不过,SPI方式倒是验证通过了,sdmmc方式始终不行。

反复研究官方示例:

/*
 * pin 1 - D2                |  Micro SD card     |
 * pin 2 - D3                |                   /
 * pin 3 - CMD               |                  |__
 * pin 4 - VDD (3.3V)        |                    |
 * pin 5 - CLK               | 8 7 6 5 4 3 2 1   /
 * pin 6 - VSS (GND)         | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄  /
 * pin 7 - D0                | ▀ ▀ █ ▀ █ ▀ ▀ ▀ |
 * pin 8 - D1                |_________________|
 *                             ║ ║ ║ ║ ║ ║ ║ ║
 *                     ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗
 *                     ║         ║ ║ ║ ║ ║ ╚══════╗    ║
 *                     ║   ╔═════╝ ║ ║ ║ ╚═════╗  ║    ║
 * Connections for     ║   ║   ╔═══╩═║═║═══╗   ║  ║    ║
 * full-sized          ║   ║   ║   ╔═╝ ║   ║   ║  ║    ║
 * SD card             ║   ║   ║   ║   ║   ║   ║  ║    ║
 * ESP32-S3 DevKit  | 21  47  GND  39 3V3 GND  40 41  42  |
 * ESP32-S3-USB-OTG | 38  37  GND  36 3V3 GND  35 34  33  |
 * ESP32            |  4   2  GND  14 3V3 GND  15 13  12  |
 * Pin name         | D1  D0  VSS CLK VDD VSS CMD D3  D2  |
 * SD pin number    |  8   7   6   5   4   3   2   1   9 /
 *                  |                                  █/
 *                  |__▍___▊___█___█___█___█___█___█___/
 * WARNING: ALL data pins must be pulled up to 3.3V with an external 10k Ohm resistor!
 * Note to ESP32 pin 2 (D0): Add a 1K Ohm pull-up resistor to 3.3V after flashing
 *
 * 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
 *

去看别人淘宝卖的模块,都是spi的

最后,阴差阳错的情况下去看了IDF的部分代码,在sdmmc_default_configs.h其中看到了如下内容:


/**
 * Macro defining default configuration of SDMMC host slot
 */
#if CONFIG_IDF_TARGET_ESP32P4
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
    .clk = GPIO_NUM_43, \
    .cmd = GPIO_NUM_44, \
    .d0 = GPIO_NUM_39, \
    .d1 = GPIO_NUM_40, \
    .d2 = GPIO_NUM_41, \
    .d3 = GPIO_NUM_42, \
    .d4 = GPIO_NUM_45, \
    .d5 = GPIO_NUM_46, \
    .d6 = GPIO_NUM_47, \
    .d7 = GPIO_NUM_48, \
    .cd = SDMMC_SLOT_NO_CD, \
    .wp = SDMMC_SLOT_NO_WP, \
    .width   = SDMMC_SLOT_WIDTH_DEFAULT, \
    .flags = 0, \
}

#elif CONFIG_IDF_TARGET_ESP32S3
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
    .clk = GPIO_NUM_14, \
    .cmd = GPIO_NUM_15, \
    .d0 = GPIO_NUM_2, \
    .d1 = GPIO_NUM_4, \
    .d2 = GPIO_NUM_12, \
    .d3 = GPIO_NUM_13, \
    .d4 = GPIO_NUM_33, \
    .d5 = GPIO_NUM_34, \
    .d6 = GPIO_NUM_35, \
    .d7 = GPIO_NUM_36, \
    .cd = SDMMC_SLOT_NO_CD, \
    .wp = SDMMC_SLOT_NO_WP, \
    .width   = SDMMC_SLOT_WIDTH_DEFAULT, \
    .flags = 0, \
}
#endif  // GPIO Matrix chips

#endif

这里写的是ESP32P4和esp32 s3,难道???

arduino中网上很多sdmmc能找到的一些说明都是2022年前的,而这份文件更新于2023年。

于是大胆找出嘉立创买的那块S3,开始折腾,最初按照默认接线不成功

后来做其他尝试,换成了 39,40,47 ,居然可以1线SDMMC访问了。

在esp32 s3 下,使用setpin经过验证还可以使用其他GPIO.

 SD_MMC.setPins(39,40,48);

几天折腾下来总结的经验如下:

  • 根据乐鑫对于TF模块的电路设计,最好都是10k上拉电阻;但是有些不上拉也没事;事后验证过两块不同上拉的电阻的pcb板都可以正常读取和写入;
  • SPI方法访问TF卡很方便,SDMMC方法非常折腾人,如果你不像我这样偏执那就使用SPI方式吧,某宝卖的TF模块都是使用了SPI方式;
  • 如果你ESP32 通过SDMMC方式访问不了,那就换成ESP32 S3试试;记得使用setpin方法,但是文档中又说setpin方法对于esp32无效;
  • 好像曾经在esp32下访问成功过,但是后来不知啥原因不能重现了;
  • SD.begin方法要注意第三个参数:if(!SD_MMC.begin("/sdcard",true,true);
  • 网上很多示例代码都是错误的,通过SPI和SDMMC方法tf卡调用的类库不一样,一个SD.h,一个是SD_MMC.h;
  • 通过网络上的测速:1线sdmmc和4线sdmmc的速度基本是一样的,sdmmc大约比spi方式快一倍;不过这个测试结果比较古早,是通过128m 的TF卡的结果;
  • IDF方式相对arduino能看到更多的提示信息,更深入;
  • 有些文档写的是"/sdcard",有些是"/cdcard",对于启动无任何影响;

以下是经过验证,esp32通过SPI方法访问TF的代码:


// #include "FS.h"
#include "SD.h"
// #include <sd_defines.h>
// #include "driver/sdmmc_types.h"

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.printf("\r\n 开始运行,暂停5秒,等待SD上电");
  delay(1000);
  // if(!SD_MMC.begin("/sdcard",true)){
  //   Serial.printf("挂载SD读卡器失败");
  //   return;
    
  // }
 
    SPIClass spi = SPIClass(HSPI);
  spi.begin(18 /* SCK */, 19 /* MISO */, 23 /* MOSI */, 5 /* SS */);
  if (!SD.begin(5 /* SS */, spi, 120000000,"/cdcard")) {
    Serial.println("Card Mount Failed");
    return;
  }
 Serial.printf("\r\n SD装载成功");
uint8_t cardType = SD.cardType();

  if (cardType == CARD_NONE)
  {
    Serial.println("未连接存储卡");
    // return;
  }
  else if (cardType == CARD_MMC)
  {
    Serial.println("挂载了MMC卡");
  }
  else if (cardType == CARD_SD)
  {
    Serial.println("挂载了SDSC卡");
  }
  else if (cardType == CARD_SDHC)
  {
    Serial.println("挂载了SDHC卡");
  }
  else
  {
    Serial.println("挂载了未知存储卡");
  }
  File file = SD.open("/test.txt", FILE_WRITE);
  if (file)
  {
    Serial.println("打开/建立 根目录下 test.txt 文件!");
  }

  char data[] = "hello world\r\n";
  file.write((uint8_t *)data, strlen(data));
  file.close();

  //重命名文件
  if (SD.rename("/test.txt", "/retest.txt"))
  {
    Serial.println("test.txt 重命名为 retest.txt !");
  }

  //读取文件数据
  file = SD.open("/retest.txt", FILE_READ);
  if (file)
  {
    Serial.print("文件内容是:");
    while (file.available())
    {
      Serial.print((char)file.read());
    }
  }
//读取文件数据
  file = SD.open("/1.txt", FILE_READ);
  if (file)
  {
    Serial.print("文件内容是:");
    while (file.available())
    {
      Serial.print((char)file.read());
    }
  }
  Serial.printf("存储卡总大小是: %lluMB \n", SD.cardSize() / (1024 * 1024)); // "/ (1024 * 1024)"可以换成">> 20"
  Serial.printf("文件系统总大小是: %lluMB \n", SD.totalBytes()/ (1024 * 1024));
  Serial.printf("文件系统已用大小是: %lluB \n", SD.usedBytes());
}

void loop() {
  // put your main code here, to run repeatedly:

}

以下是经过验证,esp32 s3通过1线sdmmc方法访问TF的代码:

#include <SD_MMC.h>

void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while (file) {
    if (file.isDirectory()) {
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if (levels) {
        listDir(fs, file.path(), levels - 1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}

void createDir(fs::FS &fs, const char *path) {
  Serial.printf("Creating Dir: %s\n", path);
  if (fs.mkdir(path)) {
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

void removeDir(fs::FS &fs, const char *path) {
  Serial.printf("Removing Dir: %s\n", path);
  if (fs.rmdir(path)) {
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

void readFile(fs::FS &fs, const char *path) {
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while (file.available()) {
    Serial.write(file.read());
  }
}

void writeFile(fs::FS &fs, const char *path, const char *message) {
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if (file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
}

void appendFile(fs::FS &fs, const char *path, const char *message) {
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if (file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
}

void renameFile(fs::FS &fs, const char *path1, const char *path2) {
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

void deleteFile(fs::FS &fs, const char *path) {
  Serial.printf("Deleting file: %s\n", path);
  if (fs.remove(path)) {
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

void testFileIO(fs::FS &fs, const char *path) {
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  if (file) {
    len = file.size();
    size_t flen = len;
    start = millis();
    while (len) {
      size_t toRead = len;
      if (toRead > 512) {
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    end = millis() - start;
    Serial.printf("%u bytes read for %lu ms\n", flen, end);
    file.close();
  } else {
    Serial.println("Failed to open file for reading");
  }

  file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  for (i = 0; i < 2048; i++) {
    file.write(buf, 512);
  }
  end = millis() - start;
  Serial.printf("%u bytes written for %lu ms\n", 2048 * 512, end);
  file.close();
}

void setup()
{

    Serial.begin(115200);
    Serial.printf("\r\n开始SDMMC读取.");
    // delay(1000);
    SD_MMC.setPins(39,40,48);
    // SD_MMC.setPins(14,15,2);
    if (!SD_MMC.begin("/sdcard", true))
    {
        Serial.printf("\n SDMMC模式失败");
        return;
    }
    Serial.printf("\n启动成功");
      uint8_t cardType = SD_MMC.cardType();
    if (cardType == CARD_NONE) {
    Serial.println("No SD_MMC card attached");
    return;
  }

  Serial.print("SD_MMC Card Type: ");
  if (cardType == CARD_MMC) {
    Serial.println("MMC");
  } else if (cardType == CARD_SD) {
    Serial.println("SDSC");
  } else if (cardType == CARD_SDHC) {
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }

  uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
  Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
listDir(SD_MMC, "/", 0);
  createDir(SD_MMC, "/mydir");
 
    Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
    SD_MMC.end();
}

void loop()
{
}

上面两份代码中的GPIO端口都是在esp32和esp32 s3中验证过的,如果出现错误,请检查其他原因。

一起玩儿物联网人工智能小车(ESP32)——63 SD和TF卡模块的使用 摘要:本文介绍SD和TF卡模块的使用方法 阅读详情

相关推荐

ESP32上SD卡的读写操作

本章学习使用ESP32的sdmmc组件读写MicroSD卡sdmmc组件就是ESP-IDF中封装的一组函数,包含了对存储卡进行的各种操作。

weixin_68768619的博客 2728

ESP32学习之SD卡

ESP32学习之SD卡

AuroraSmith的博客 1665

基于ESP32与SHT31的温湿度数据记录仪:蓝牙+SD卡双备份方案

在物联网和嵌入式系统开发中,环境数据采集是基础且关键的应用场景,其核心在于如何稳定、可靠地获取并保存传感器数据。数据记录仪(Data Logger)是实现这一目标的经典设备,它通过微控制器(MCU)读取传感器信息,并结合本地存储与无线通信技术,确保数据不丢失且易于访问。其技术价值在于为仓储、实验室、农业监测等场景提供了长期、无人值守的自动化监测方案。本文聚焦于一个具体的工程实践:使用ESP32作为主控,搭配高精度SHT31温湿度传感器,构建一个具备低功耗蓝牙(BLE)无线传输和MicroSD卡本地存储双备份

weixin_33801856的博客 363

Arduino ESP32 读取SD卡接口选择参考

ESP32 SD卡接口选择 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引脚

perseverance51博客 2万+

基于Arduino/ESP32的PM2.5与CO2空气质量检测仪DIY全攻略

传感器技术是物联网与智能硬件感知物理世界的核心。其原理是通过特定敏感元件,将环境参数(如颗粒物浓度、气体成分)转换为可测量的电信号。在嵌入式开发领域,以Arduino和ESP32为代表的微控制器,因其开源生态和丰富库支持,成为连接传感器与实现智能应用的理想平台。这种技术组合的工程价值在于,它允许开发者以透明、可定制的方式构建数据采集系统,深入理解从信号采集、处理到传输的全链路。在环境监测这一典型应用场景中,对室内空气中PM2.5(细颗粒物)和CO2(二氧化碳)浓度的实时感知需求日益增长。本文聚焦于使用激光散

weixin_34072458的博客 427

ESP32与SD卡交互实现:文件读写实战与初始化详解及引脚定义

本代码实现ESP32与SD卡的交互,包括定义SPI引脚、创建自定义SPI类实例、编写WriteFile与ReadFile函数进行文件读写。setup函数初始化串口、SPI、SD卡,向“/test.txt”写入“myfirstmessage”,读取并打印其内容。loop函数留空待扩展。

Firmin123456的博客 7358

ESP32-TF卡的使用

在ESP - IDF中对FATFS进行了封装和适配,通过esp_vfs_fat组件来挂载和操作FAT系统,并提供了一套文件系统接口,这些接口基于标准的 C 库文件操作函数(如 fopen、fread、fwrite 等),并在底层进行了适配和扩展。通过这些接口,开发者可以使用统一的方式操作不同的文件系统,而无需关心具体的实现细节。如果想使用FATFS原生的函数只需包含ff.h即可。关于FATFS这篇文章里有详细的介绍,有兴趣可以看一下。

qq_64171874的博客 1804

TensorFlow Lite Micro语音识别系统源码拆解:从ESP32到离线KWS

在嵌入式AI与TinyML快速发展的当下,语音识别已从云端大型模型走向资源受限的MCU。其核心原理在于利用TensorFlow Lite Micro运行时,结合模型量化与MFCC特征提取,在本地完成关键词唤醒(KWS)任务。这种方案无需网络连接,具备低延迟、高隐私、低功耗等技术价值,广泛应用于智能家居、便携设备等离线语音控制场景。本文基于一套实际可运行的TensorFlow Lite Micro语音识别系统源码,从工程实践角度拆解其架构、模型转换流程、音频采集与推理优化关键点,并分享调试中的常见陷阱,帮助开

weixin_34274029的博客 3599

ESP32驱动SD卡实战

SD卡有SD、MiniSD和microSD三种类型。可以访问如下链接查看更多规定。最新SD卡规格的参数如下图所示:其中脚位数对应实卡上的金手指数,不同的类型的卡的触点数量不同,访问的速度也不同。SD卡常见的两种访问接口模式是SDIO模式和SPI模式。

sky的博客 4026

Nangate 45nm FreePDK开源工艺库:从RTL到GDSII全流程实战

在数字IC设计中,标准单元库是连接逻辑综合与物理实现的基石,它定义了每个单元的逻辑功能、时序延迟与物理尺寸。开源EDA工具链的成熟,使得个人也能借助免费工艺套件完整跑通芯片设计流程。Nangate 45nm FreePDK作为一套经典的开源工艺库,凭借结构清晰、配套完善的特性,成为学习数字后端和时序收敛的理想训练场。从综合工具Yosys读取Liberty文件进行逻辑映射,到OpenROAD执行布局布线与时钟树综合,再到使用OpenSTA分析关键路径延迟,这套流程涵盖了数字设计最核心的环节。通过亲手操作,开发

weixin_29168393的博客 271

Oracle ERP EBS R12 GL总帐业务方案 系统操作

本文档是Oracle ERP系统的总账管理模块使用手册,主要包含以下内容:1.系统架构设计,详细介绍多组织架构、会计科目设置等核心概念;2.总账日常操作流程,包括凭证录入、审核、过账等全流程管理;3.特殊业务处理,涵盖预算控制、内部往来、合并报表等专项功能;4.期末处理,说明月结、年结的操作步骤;5.系统设置指南,提供会计科目表、权限控制等配置说明;6.附录包含各业务模块的分录示例和系统操作图标说明。本手册适用于财务人员学习和使用Oracle ERP总账系统,重点讲解系统功能要点和实操步骤。

anpeng2019的博客 1888

少走弯路,ESP32 读取Micro SD(TF)播放mp3的坑路历程。

在好不容易解决了SD卡用1线sdmmc读取的问题,遇到了惊天大雷,esp32 s3 只支持ble 5.0 ,不支持a2dp,那就意味着esp32 s3不能用做蓝牙音频播放的接受端 ,除非哪天升级到ble 5.2的版本才有le audio.你们看,从sd库本身的示例,到audioi2s的示例,到各种网络上关于sdmmc的示例都是在一大抄,如果没有这些错误的引导,也就不会产生错误的各种情况。因此从头到尾问题都出现在spi上,但是不管那个SPI,对于SD的一般访问读写,都是正常的,这TMD的谁能想到啊!

Sean.Pu的专栏 4642

测绘无人船避坑指南:云卓H12Pro遥控器接海康摄像头,从网络设置到RTSP流延迟优化全流程

本文详细解析了测绘无人船视频子系统的优化方案,重点介绍海康威视摄像头与云卓H12Pro遥控器的深度适配流程。从网络设置到RTSP流延迟优化,提供了一套经过实测的低延迟(<200ms)解决方案,适用于复杂水域环境下的测绘任务。

weixin_30415113的博客 625

基于ESP32与蓝牙SPP的智能婴儿摇床控制系统设计与实现

嵌入式系统开发是物联网应用的基础,其核心在于通过微控制器协调传感器、执行器与通信模块,实现物理世界的智能化控制。其工作原理涉及硬件接口驱动、实时任务调度与通信协议解析。该技术价值在于将抽象的逻辑算法转化为具体的自动化解决方案,广泛应用于智能家居、工业控制等领域。本文聚焦于一个典型的嵌入式物联网应用场景——智能婴儿安抚系统,详细阐述了如何利用ESP32单片机的蓝牙SPP通信、PWM电机控制与串口MP3模块驱动,构建一个可通过手机定时遥控的摇床与音乐联动装置。项目实践涵盖了从硬件选型、电路连接到嵌入式软件开发的

weixin_33802505的博客 463

SO逆向入门实战教程一:OASIS

文章目录一、前言二、准备三、Unidbg模拟执行四、ExAndroidNativeEmu 模拟执行五、算法分析六、尾声 一、前言 这是SO逆向入门实战教程的第一篇,总共会有十三篇,十三个实战。有以下几个注意点: 主打入门级的实战,适合有一定基础但缺少实战的朋友(了解JNI,也上过一些Native层逆向的课,但感觉实战匮乏,想要壮壮胆,入入门)。 侧重新工具、新思路、新方法的使用,算法分析的常见路子是Frida Hook + IDA ,在本系列中,会淡化Frida 的作用,采用Unidbg Hook + .

lilac的博客 2万+

CATIA P3 V5-6R2023在Windows 11 23H2上的稳定安装与系统级配置指南

CATIA是高端制造业核心的三维参数化设计平台,其运行依赖严格的系统底层支撑。理解CATIA的BRep几何内核原理与Windows子系统(如WSL、Hyper-V)的协同机制,是保障建模稳定性与计算精度的技术前提。CATIA Run-Time Library和OpenGL硬件加速能力共同决定了曲面重建、螺纹建模等关键操作的可靠性;而.NET Framework 3.5、VC++ 2022运行库及显卡Studio驱动的精准匹配,则构成工业软件在Win11环境落地的工程基础。本文聚焦于航空、轨交、能源等领域高频

weixin_30983353的博客 631

ESP32在ESP-IDF框架下为LVGL(v8.3)配置SD卡文件系统

4、在main.c的ui_init()函数之后,调用lv_img_set_src(ui_Image2,“S:pictures/xxx.bin”);2、并不是买回来的新的SD卡就一定能用(并不是说用读卡器插在电脑上能够正常读写,就表示一定能够实验成功),买过几张卡,确实有不能用的,导致改bug搞了一下午没有成功。(比如说:作为树莓派的系统盘),那么要把系统盘的分区合并成一个(这个网上有很多教程),并重新格式化,否则实验会失败。,不需要更改main.c的任何内容,就实现了初始化SD卡和文件系统。

小魏先生 5565

SAP ABAP Cloud 发展简史

其中用于云开发的 ABAP,官方术语是 「ABAP in the Cloud」,本文后续叙述方便起见,简称为 「ABAP Cloud」. 它涵盖了标准 ABAP 语言范围的一个子集,只能访问受限的 API,用于构建 SAP BTP ABAP 环境以及 SAP S/4HANA Cloud ABAP 环境上的云解决方案。SAP ABAP 平台是用于 SAP ECC、SAP S/4HANA 和 SAP BTP 等产品的技术平台,也是 ABAP 应用程序的开发和运行环境。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1393

物联网开发笔记(96)- Micropython ESP32开发之SPI接口控制Micro SD卡TF卡模块挂载内存卡

Micropython ESP32开发之SPI接口控制Micro SD卡TF卡模块挂载内存卡

zhusongziye的博客 2763

锂电池的充电和放电曲线解读

锂电池充放电曲线是反映其性能的关键指标。充电曲线分为恒流和恒压两阶段:恒流阶段电压快速上升,恒压阶段电流逐渐降低;放电曲线则呈现平台期和快速衰减期特征。这些曲线受温度、充放电倍率及材料体系(如三元锂或磷酸铁锂)显著影响。通过分析曲线特征,可优化电池管理系统,实现精准的SOC估算、快充策略制定及故障诊断,从而在电池性能与安全性间取得平衡。不同应用场景(如新能源汽车或消费电子)对曲线形态有特定要求。

start_up_go的博客 5066

嵌入式PCB电源完整性分析:PDN建模与电流密度优化

电源完整性(PI)是高速数字与混合信号系统稳定运行的基础,其核心在于保障芯片供电网络(PDN)在动态负载下的电压稳定与热安全。PDN分析本质上是通过量化电流密度与电压降两个关键物理量,揭示PCB走线、过孔及平面的载流瓶颈与压降路径。电流密度超标将引发局部温升与可靠性风险,而电压降则直接侵蚀器件供电裕量,导致复位、采样失真等典型故障。借助Altium Designer等工具开展工程级PDN建模,需严格依据电源预算表定义源/负载,并精准配置铜厚、过孔参数及IPC-2152限值,从而实现从原理图到制造工艺的闭环验

weixin_28949937的博客 211

【Arduino & Esp32】SD卡读写

SD卡读写

npc666666的博客 1万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

ESP32学习笔记(43)——SD卡使用(SDMMC方式)

一、简介 SD 卡(Secure Digital Memory Card) 在我们生活中已经非常普遍了,控制器对 SD 卡进行 读写通信操作一般有两种通信接口可选,一种是 SPI 接口,另外一种就是 SDIO 接口。 SDIO 全称是安全数字输入/输出接口,多媒体卡(MMC)、SD 卡、SD I/O 卡都有 SDIO 接口。 MMC 卡可以说是 SD 卡的前身,现阶段已经用得很少。 二、API说明 以下 SDMMC 接口位于 driver/include/driver/sdmmc_host.h。 2.1

Leung的博客 1万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

【MicroPython ESP32】通过sdcard模块读取SD卡实例

【MicroPython ESP32】通过sdcard模块读取SD卡实例

perseverance51博客 6100

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

使用esp32跑sdmmc出现sdmmc_cmd: sdmmc_read_sectors_dma: sdmmc_send_cmd returned 0x107

多次调用sdmmc_read_sectors(card, buff, sector, count);右键,格式化,选择fat32即可,如果有些保护,检查读卡器是否被锁。sd卡读512MB的内存卡没问题,读4GB的就报错。

aa6363636的博客 2093

聊聊今天esp32调试sd卡遇到的坑

1,用spi模式测试读写sd卡,结果显示挂载失败,我记得前天还用spi模式接max98357放mp3很正常,后面又试了几次还是不行,显示挂载失败要接上拉电阻,都已经接了10k的上拉,两张内存卡都试过都不行就放弃了,上网查了下金士顿内存卡测试成功了,不过我手头没有就没试了,我用esp32 S3测试过好像可以正常读取,过年时候测的,有点忘了是不是成功了,应该是成功了。然后因为有上拉接在IO2会导致无法下载程序,我到头文件里看了下可以用矩阵交换io,我调到其他io,但是都无法读取成功,把mmc速率调低也没用。

qq_44489753的博客 3014
上一篇: 少走弯路之:esp32 通过i2s 使用顺芯ES8156的说明
下一篇: 今日份意难平的ESP32 S3
platform
博客等级 码龄26年 1117粉丝 351原创
评论 16
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值