ESP32S3利用SPI实现MicroSD/TF卡的读写操作(基于ESPIDF官方库详解)
强大的ESPIDF肯定有库,不仅是SPI驱动程序层级的库,还有特定应用于SD/MMC的库,将POSIX函数经过SPI协议读写SD卡的方法集成了。之所以出上三篇文章,就是官方库讨论热度低,稍微配置偏差了点可能就不能运作,故障也没人来讨论,因为经过多层封装,程序中间哪儿出问题不容易排查。但是熟悉官方库后,直接调用官方库是最成熟省事的。
官方库的component组件在电脑C:\Users\esp\v5.1.2\esp-idf\components\fatfs这个文件夹里,在main.c主程序源文件里面直接#include,不需要在cmakelist.txt里面配置东西了。
#include "esp_vfs_fat.h"
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
一、初始化配置代码
#define pin_CS 9
#define pin_MOSI 10
#define pin_MISO 12
#define pin_CLK 11
#define MOUNT_POINT "/sdcard"
void sdcard_init()
{
sdmmc_host_t host=SDSPI_HOST_DEFAULT();
host.slot=SPI2_HOST;
spi_bus_config_t bus_cnf={
.mosi_io_num = pin_MOSI,
.miso_io_num = pin_MISO,
.sclk_io_num = pin_CLK,
.quadhd_io_num=-1, //这行不能省略
.quadwp_io_num=-1, //这行不能省略
.max_transfer_sz=400000,
};
spi_bus_initialize(host.slot,&bus_cnf,SPI_DMA_CH_AUTO);
static sdspi_device_config_t slot_cnf={
.gpio_cs=pin_CS,
.gpio_cd=SDSPI_SLOT_NO_CD, //这行不能省略
.gpio_int=GPIO_NUM_NC,//这行不能省略
.gpio_wp=GPIO_NUM_NC,//这行不能省略
.host_id=SPI2_HOST,
};
sdmmc_card_t *card;
esp_vfs_fat_sdmmc_mount_config_t mount_cnf={
.format_if_mount_failed=true,
.max_files=5,
.allocation_unit_size=16*1024,
};
esp_vfs_fat_sdspi_mount(mount_point,&host,&slot_cnf,&mount_cnf,&card);
sdmmc_card_print_info(stdout,card); //这行不写也行
}
看这么简单一个函数内就能完成初始化,下一步你就能用fopen()、fread()、fwrite()等POSIX函数直接管理SD卡文件。我们看看这个自定义函数sdcard_init()里面完成了什么事情。
(1)sdmmc_host_t选了SPI2,就是将ESP32S3四个SPI外设中的SPI2选中,开启DMA,你也可以选SPI3;
(2)spi_bus_config_t指定了GPIO的连线引脚号码;
(3)sdspi_device_config_t配置了SD卡这种从设备的通讯特性,让系统自动控制CS线,让从设备与SPI2这条通讯线路关联起来;
(4)sdmmc_card_t没什么具体意义,创造一个card handle,后面对这一张sd卡的所有操作都是抓住这个handle进行的操作。esp_vfs_fat_sdmmc_mount_config_t的属性.allocation_unit_size=16*1024表示FATFS文件系统一次读写16*1024字节,由于一个扇区是512字节,这相当于人为将32个扇区划分为一个block。
(5)esp_vfs_fat_sdspi_mount()这个函数是这个库的核心精髓,其他函数都不用看,被这个函数集成在一起了。根据sdcard的数据手册的顺序完成了一系列初始化指令过程,包括CMD0、CMD8等,然后将FATFS系统挂载在sdcard上,还把vfs系统与FATFS系统关联对接了。
二、注意事项
这个库几乎不可能在FATFS系统、VFS系统上出问题,基本问题都出在esp_vfs_fat_sdspi_mount()里面的sdmmc_card_init()过程,这是个SD卡硬件物理初始化过程。sdmmc_card_init()初始化过程就是SD卡手册写的初始化步骤,每一步的故障都会报错,但不一定会明确报是哪一步的故障。我经历过的故障分享一下:
(1)gpio_isr故障,这个故障原因是sdspi_device_config_t配置里面没配置
gpio_cd、gpio_int、gpio_wp这三项。我一开始以为默认就是不开启这三个引脚,就懒得写配置了,查了好久发现就是这儿出问题,哪怕不用这几个引脚,也要配置为“不启用”。
(2)0x107故障代码,就是ESP_ERR_TIMEOUT,一般出在ACMD41这儿(send_op_cond),轮询100次ACMD41也不能返回0x00的话就会超时,初始化失败。如果前面步骤通讯正常,这一关卡住,那不可能是接线顺序错误,要考虑硬件问题,可能是SD卡读写模块的问题(比如上拉电阻)、SD卡的问题。电压问题基本不考虑,用ESP32S3的3v3引脚供电完全可以的。
(3)其他故障代码。ESP_ERR_INVALID_CRC、ESP_ERR_INVALID_RESPONSE、ESP_ERR_NOT_FOUND这些故障在官方库里不大可能出现,官方对SD卡协议的理解一定是对的,若出现了这些故障很可能故障不是这些原因本身,而是通讯失败。
通讯失败的话,要查找这些原因:
a)接线顺序是否错误?
b) menuconfig里面是否设置好pin_mosi、pin_clk这些引脚并保存好?用官方例程的话,官方做了个kconfig文件强调让你把引脚配置好,不仅是修改代码。
c)重启esp32s3主板往往没什么效果,要把sd卡拔出来,再插上去,然后重启试试看,sd卡断电这个也是有影响的。sd卡初始化第一步错误的话,后面就进行不了,sd卡重新插拔后再重新进行第一步。
d)不能偷懒漏写一两条配置语句,这个官方库就是不能容许漏写,否则就会报错。
三、文件读写操作
上面步骤完成后,就可以用全网统一标准的文件读写函数了。FATFS文件操作函数在这个文件夹里:
C:\Users\esp\v5.1.2\esp-idf\components\fatfs\src\ff.h
作者:gyui21g