赞
踩
一、SDIO介绍
SDIO,全称:Secure Digital Input and Output,即安全数字输入输出接口。它是在SD卡接口的基础上发展而来,它可以兼容之前的SD卡,并可以连接SDIO接口设备,比如:蓝牙、WIFI、照相机等。SDIO和SD卡规范间的一个重要区别是增加了低速标准。低速卡的目标应用是以最小的硬件开支支持低速I/O能力。低速卡支持类似调制解调器、条码扫描仪和GPS接收器等应用。
以下是SDIO的兼容性:
这里也提一下MMC卡,MMC(Multi-Media Card,多媒体卡)由西门子公司Siemens和SanDisk于1997年推出。由于它的封装技术较为先进,7针引脚,体积小、重量轻、非常符合移动存储的需要。MMC支持1bit模式,20MHz时钟,采用总线结构。 SD卡是基于MMC卡发展而来的,具体的关系和历史发展大家可以看下图 :
发展到今天MMC卡基本退出历史,取而代之的是eMMC卡主要应用于嵌入式领域,eMMC卡是bga封装,一般焊接在板子上。
在配套教程的开发板上,预留了一个MicroSD/TF卡座,在esp-idf中驱动SD卡/MicroSD卡/eMMC卡的组件称为sdmmc模块,这个模块对常用的存储卡操作进行了封装兼容,并向上提供了友好的接口,我们无须关注具体的驱动实现以及协议内容,即可方便的操作MicroSD卡。
ESP32 的 SDMMC 主机外设共有两个卡槽,用于插入 SD 卡、连接 SDIO 设备或连接 eMMC 芯片,每个卡槽均可单独使用。
信号 | 卡槽 0 | 卡槽 1 |
CMD | GPIO11 | GPIO15 |
CLK | GPIO6 | GPIO14 |
D0 | GPIO7 | GPIO2 |
D1 | GPIO8 | GPIO4 |
D2 | GPIO9 | GPIO12 |
D3 | GPIO10 | GPIO13 |
D4 | GPIO16 | |
D5 | GPIO17 | |
D6 | GPIO5 | |
D7 | GPIO18 | |
CD | 来自 GPIO 交换矩阵的任意输入 | 来自 GPIO 交换矩阵的任意输入 |
WP | 来自 GPIO 交换矩阵的任意输入 | 来自 GPIO 交换矩阵的任意输入 |
由于卡槽0引脚与官方的ESP32 模组Flash引脚有冲突,因此我们一般使用卡槽1。MicroSD卡,对于MicroSD卡的接口,CD插入检测与D3引脚公用,没有WP写保护引脚。具体MicroSD卡接口如下图所示。
MicroSD可以使用SPI和SDIO模式,本例程使用SDIO模式,可同时传输4bit数据。
二、ESP32读写MicroSD卡
由于esp-idf中对SD卡的操封装的相当好,因此初始化、读写SD卡等操作代码量不多,并且加入了VFS虚拟文件系统管理,使得我们对SD卡的操作可以使用C语言标准文件读写api,比如fopen、fwrite等操作。我们先看下代码。代码位于esp32-board/sdcard
void app_main(void)。
- void app_main(void)
- {
- esp_err_t ret;
- esp_vfs_fat_sdmmc_mount_config_t mount_config = {
- .format_if_mount_failed = true, //挂载失败是否执行格式化
- .max_files = 5, //最大可打开文件数
- .allocation_unit_size = 16 * 1024 //执行格式化时的分配单元大小(分配单元越大,读写越快)
- };
- sdmmc_card_t *card;
- const char mount_point[] = MOUNT_POINT;
- ESP_LOGI(TAG, "Initializing SD card");
-
- ESP_LOGI(TAG, "Using SDMMC peripheral");
- //默认配置,速度20MHz,使用卡槽1
- sdmmc_host_t host = SDMMC_HOST_DEFAULT();
- //默认的IO管脚配置,
- sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
- //4位数据
- slot_config.width = 4;
- //不使用通过IO矩阵进行映射的管脚,只使用默认支持的SDMMC管脚,可以获得最大性能
- #if 0
- slot_config.clk = CONFIG_EXAMPLE_PIN_CLK;
- slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD;
- slot_config.d0 = CONFIG_EXAMPLE_PIN_D0;
- slot_config.d1 = CONFIG_EXAMPLE_PIN_D1;
- slot_config.d2 = CONFIG_EXAMPLE_PIN_D2;
- slot_config.d3 = CONFIG_EXAMPLE_PIN_D3;
- #endif
- // Enable internal pullups on enabled pins. The internal pullups
- // are insufficient however, please make sure 10k external pullups are
- // connected on the bus. This is for debug / example purpose only.
- //管脚启用内部上拉
- slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
- ESP_LOGI(TAG, "Mounting filesystem");
- ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
- if (ret != ESP_OK) {
- if (ret == ESP_FAIL) {
- ESP_LOGE(TAG, "Failed to mount filesystem. ");
- } else {
- ESP_LOGE(TAG, "Failed to initialize the card (%s). "
- "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
- }
- return;
- }
- ESP_LOGI(TAG, "Filesystem mounted");
- // Card has been initialized, print its properties
- sdmmc_card_print_info(stdout, card);
- // Use POSIX and C standard library functions to work with files:
- // First create a file.
- const char *file_hello = MOUNT_POINT"/hello.txt";
- char data[EXAMPLE_MAX_CHAR_SIZE];
- snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Hello", card->cid.name);
- ret = s_example_write_file(file_hello, data);
- if (ret != ESP_OK) {
- return;
- }
- const char *file_foo = MOUNT_POINT"/foo.txt";
- // Check if destination file exists before renaming
- struct stat st;
- if (stat(file_foo, &st) == 0) {
- // Delete it if it exists
- unlink(file_foo);
- }
- // Rename original file
- ESP_LOGI(TAG, "Renaming file %s to %s", file_hello, file_foo);
- if (rename(file_hello, file_foo) != 0) {
- ESP_LOGE(TAG, "Rename failed");
- return;
- }
- ret = s_example_read_file(file_foo);
- if (ret != ESP_OK) {
- return;
- }
-
- const char *file_nihao = MOUNT_POINT"/nihao.txt";
- memset(data, 0, EXAMPLE_MAX_CHAR_SIZE);
- snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Nihao", card->cid.name);
- ret = s_example_write_file(file_nihao, data);
- if (ret != ESP_OK) {
- return;
- }
- //Open file for reading
- ret = s_example_read_file(file_nihao);
- if (ret != ESP_OK) {
- return;
- }
- // All done, unmount partition and disable SDMMC peripheral
- esp_vfs_fat_sdcard_unmount(mount_point, card);
- ESP_LOGI(TAG, "Card unmounted");
- }
初始化的时候需要填充esp_vfs_fat_sdmmc_mount_config_t、sdmmc_slot_config_t这两个结构体,然后通过esp_vfs_fat_sdmmc_mount函数把SD卡挂载到对应的挂载点上(函数的第一个参数)。具体的内容大家可以自行查看定义,并不复杂,这里有几点要注意一下,
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP这句是对SDIO的管脚启用内部上拉电阻,严格来说我们在设计电路的时候要对SDIO四个DATA管脚都接一个10K-90K的上拉电阻,而ESP32内部给我们提供了上拉的功能,是不是就意味着我们不用外接上拉呢?其实这里官方也给了注释,启用这个内部上拉,功能有待验证,最稳的还是接个10K上拉,但在实际应用中我发现了一个问题,如果DATA2(GPIO12)引脚接了上拉,则ESP32在上电的时候认为Flash是1.8V供电的,而板子上全都用3.3V供电,这样我们程序起不来。官方的解决方法是烧录efuse的存储信息,让ESP32强制以3.3V工作。还有一个地方是DATA0(GPIO2)引脚,如果我接了10K上拉,则无法烧录程序,这个和系统的启动模式有关。因此保险起见,我把DATA0和DATA2上的上拉都NC了,启用了内部上拉,实际测试工作正常。大家如果有需要可以自行焊接这两个电阻。
在挂载成功后,sdmmc_card_print_info(stdout, card)函数可以打印SD卡信息,之后我们就可以使用fopen、fwrite、fread标准C库函数进行操作了。
最后附上相关资料:
ESP32教程资料链接:
https://pan.baidu.com/s/1kCjD8yktZECSGmHomx_veg?pwd=q8er
提取码:q8er
配套源码下载地址:
esp32-board: esp32开发板配套的经典例程
鉴于实验需要开发板的支持,我也设计了一款ESP32开发板,包含部分传感器模块,1.69寸LCD高亮屏,Type-C一键下载,方便大家学习和做各种实验。开发板链接如下:
请大家多多支持。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。