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

物联沃分享整理
物联沃-IOTWORD物联网 » ESP32S3利用SPI实现MicroSD/TF卡的读写操作(基于ESPIDF官方库详解)

发表回复