ESP32 开发笔记(三)源码示例 9_SPI_SDCard 使用SPI总线实现TF卡文件系统示例
开发板购买链接
https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111deb2Ij1As&ft=t&id=626366733674
开发板简介
开发环境搭建 windows
源码示例:
0_Hello Bug (ESP_LOGX与printf) 工程模板/打印调试输出
1_LED LED亮灭控制
2_LED_Task 使用任务方式控制LED
3_LEDC_PWM 使用LEDC来控制LED实现呼吸灯效果
4_ADC_LightR 使用ADC读取光敏电阻实现光照传感
5_KEY_Short_Long 按钮长按短按实现
6_TouchPad_Interrupt 电容触摸中断实现
7_WS2812_RMT RGB_LED彩虹变色示例
8_DHT11_RMT 使用RMT实现读取DHT11温湿度传感器
9_SPI_SDCard 使用SPI总线实现TF卡文件系统示例
10_IIC_ADXL345 使用IIC总线实现读取ADXL345角度加速度传感器
11_IIC_AT24C02 使用IIC总线实现小容量数据储存测试
12_IR_Rev_RMT 使用RMT实现红外遥控接收扫码(NEC)
13_IR_Send_RMT 使用RMT实现红外数据发送(NEC)
14_WIFI_Scan 附近WIFI信号扫描示例
15_WIFI_AP 创建软AP示例
16_WIFI_AP_TCP_Server 在软AP模式下实现TCP服务端
17_WIFI_AP_TCP_Client 在软AP模式下实现TCP客户端
18_WIFI_AP_UDP 在软AP模式下实现UDP通讯
19_WIFI_STA 创建STA站模
20_WIFI_STA_TCP_Server 在站模式STA下实现TCP服务端
21_WIFI_STA_TCP_Client 在站模式STA下实现TCP客户端
22_WIFI_STA_UDP 在站模式STA下实现UDP通讯
23_LVGL_Test LVGL图形库简单示例
Micro SD Card,原名Trans-flash Card(TF卡),2004年正式更名为Micro SD Card,由SanDisk(闪迪)公司发明,主要用于移动电话。
在Micro SD面市之前,手机制造商都采用嵌入式记忆体,虽然这类模组容易装设,然而有着无法应实际应潮流需求的困扰——容量被限制住了,无法再有升级空间。Micro SD仿效SIM卡的应用模式,即是同一张卡可以应用在不同型号的行动电话内,让行动电话制造商不用再为插卡式的研发设计而伤脑筋。 Micro SD卡足以堪称可移动式的储存IC。
Micro SD卡是一种极细小的快闪存储器卡,其格式源自SanDisk创造,原本这种记忆卡称为T-Flash,及后改称为Trans Flash;而重新命名为Micro SD的原因是因为被SD协会 (SDA) 采立。另一些被SDA采立的记忆卡包括Mini SD和SD卡。其主要应用于移动电话,但因它的体积微小和储存容量的不断提高,已经使用于GPS设备、便携式音乐播放器和一些快闪存储器盘中。它的体积为 15mm x 11mm x1mm ,差不多相等于手指甲的大小,是现时最细小的记忆卡。它也能通过SD转接卡来接驳于SD卡插槽中使用。 现时MicroSD卡提供128MB、256MB、512MB、1G、2G、4G、8G、16G、32G、64G、128G的容量(MWC 2014 世界移动通信大会期间,SanDisk(闪迪)打破了储存卡最高64GB容量的传统,正式发布了一款容量高达128GB的 Micro SD XC 储存卡。
SD卡的操作模式:SD卡模式(SDIO)、SPI模式(默认为SD模式)。
其中SD卡模式的信号线有:CLK、CMD、DAT0-DAT3,6根线。
SPI模式的信号线有:CS、CLK、MISO(DATAOUT)、MOSI(DATAIN),4根线。
- CLK 时钟同步线
- CMD 命令信号线,主机发出的命令以及从机对命令的响应都是通过这条线进行传输
- DAT[3:0] 表示4条数据线,主机和从机的数据都是从这四条数据线上传输
SD卡只能使用3.3V的I/O电平。SPI模式下信号线要加10-100K的上拉电阻。
SD卡有五个寄存器:
名称 | 宽度 | 描述 |
---|---|---|
CID | 128 | 卡标识寄存器 |
RCA | 16 | 相对地址寄存器(Relative Card Address):本地系统中卡的地址,动态变化,在主机初始化的时候确定,SPI模式中没有。 |
CSD | 128 | 卡描述数据:卡操作条件相关的信息数据 |
SCR | 64 | SD配置寄存器:SD卡特定信息数据 |
OCR | 32 | 操作条件寄存器 |
SD卡的命令格式:
命令CMD0就是0,CMD16就是16,以此类推。
SPI命令格式为6字节构成,高位在前(MSB)。
字节1 | 字节2-5 | 字节6 |
---|---|---|
7 | 6 | 5-0 |
0 | 1 | command |
字节1的最高2位固定是01,低6位为命令号(CMD0就是0,CMD16就是16,以此类推),字节2-5为命令参数,有些命令是没有参数的;字节6的高7位为CRC,最低位恒为1。
SD卡的命令总共有12类,下表为几个比较重要的命令:
SD卡的主要相关各种命令解析
CMD0: SD卡进入IDLE和复位SD卡
CMD1: 读OCR,是否为SD卡
CMD2: 获取卡CID信息
CMD3: 获取SD卡所分配的相对地址
CMD9: 获取SD卡的存储信息(容量、块大小等)
CMD12:停止传输操作
CMD13:获取卡的状态
CMD16:设置SD卡块大小
CMD17:使SD卡进入传输状态、读取单个块
CMD18: 使SD卡进入传输状态、读取多个块,直到收到CMD12为止
CMD24:使SD卡进入传输状态、写入单个块
CMD25: 使SD卡进入传输状态、写入多个块
命令 | 参数 | 回应 | 描述 |
---|---|---|---|
CMD0(0X00) | NONE | R1 | 复位SD卡 |
CMD8(0X08) | VHS+Check Pattern | R7 | 发送接口状态命令 |
CMD9(0X09) | NONE | R1 | 读取卡特定数据寄存器 |
CMD10(0X0A) | NONE | R1 | 读取卡标志数据寄存器 |
CMD16(0X10) | 块大小 | R1 | 设置块大小(字节数) |
CMD17(0X11) | 地址 | R1 | 读取一个块的数据 |
CMD24(0X18) | 地址 | R1 | 写入一个块的数据 |
CMD41(0X29) | NONE | R3 | 发送给主机容量支持信息和激活卡初始化过程 |
CMD55(0X37) | NONE | R1 | 告诉SD卡,下一个是特定应用命令 |
CMD58(0X3A) | NONE | R3 | 读取OCR寄存器 |
SD卡和单片机的通信采用发送应答机制:
ESP32 FAT 文件系统
ESP-IDF 使用 FatFs 库来实现 FAT 文件系统。FatFs 库位于 fatfs
组件中,您可以直接使用,也可以借助 C 标准库和 POSIX API 通过 VFS(虚拟文件系统)使用 FatFs 库的大多数功能。
此外,对 FatFs 库进行了扩展,新增了支持可插拔磁盘 I/O 调度层,从而允许在运行时将 FatFs 驱动映射到物理磁盘。
FatFs 与 VFS 配合使用
函数 esp_vfs_fat_register() 分配一个 FATFS 结构,并在 VFS 中注册特定路径前缀。如果文件路径以此前缀开头,则对此文件的后续操作将转至 FatFs API。函数 esp_vfs_fat_unregister_path() 删除在 VFS 中的注册,并释放 FATFS 结构。
多数应用程序在使用 esp_vfs_fat_ 函数时,采用如下步骤:
调用 esp_vfs_fat_register(),指定:
挂载文件系统的路径前缀(例如,"/sdcard" 或 "/spiflash")
FatFs 驱动编号
一个用于接收指向 FATFS 结构指针的变量
调用 ff_diskio_register() 为上述步骤中的驱动编号注册磁盘 I/O 驱动;
调用 FatFs 函数 f_mount,或 f_fdisk, f_mkfs,并使用与传递到 esp_vfs_fat_register() 相同的驱动编号挂载文件系统。请参考 FatFs 文档,
调用 C 标准库和 POSIX API 对路径中带有步骤 1 中所述前缀的文件(例如,"/sdcard/hello.txt")执行打开、读取、写入、擦除、复制等操作。
您可以选择直接调用 FatFs 库函数,但需要使用没有 VFS 前缀的路径(例如,"/hello.txt");
关闭所有打开的文件;
调用 f_mount 并使用 NULL FATFS* 参数为与上述编号相同的驱动卸载文件系统;
调用 FatFs 函数 ff_diskio_register() 并使用 NULL ff_diskio_impl_t* 参数和相同的驱动编号来释放注册的磁盘 I/O 驱动。
调用 esp_vfs_fat_unregister_path() 并使用文件系统挂载的路径将 FatFs 从 NVS 中移除,并释放步骤 1 中分配的 FatFs 结构。
esp_vfs_fat_sdmmc_mount 和 esp_vfs_fat_sdmmc_unmount 这两个便捷函数对上述步骤进行了封装,并加入对 SD 卡初始化的处理,非常便捷。
一、硬件设计/原理
查看开发板原理图,TF卡使用SPI总线连接到ESP32主控,对信号线进行10K上拉。
二、程序设计
先引用必要头文件
// SD card and FAT filesystem example
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "sdkconfig.h"
定义SPI总线GPIO
static const char *TAG = "TF Card Fat Example";
#define MOUNT_POINT "/sdcard"
#define SPI_DMA_CHAN 1
//在测试SD和SPI模式时,请记住,一旦在SPI模式下初始化了卡,在不接通卡电源的情况下就无法在SD模式下将其重新初始化。
#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5
主函数,测试文件系统,读取,写入、获取总容量、卡信息、剩余容量、更名、删除等操作
void app_main(void)
{
esp_err_t ret; // ESP错误定义
sdmmc_card_t* card; // SD / MMC卡信息结构
const char mount_point[] = MOUNT_POINT; // 根目录
char ReadFileBuff[64];
esp_vfs_fat_sdmmc_mount_config_t mount_config = { // 文件系统挂载配置
.format_if_mount_failed = false, // 如果挂载失败:true会重新分区和格式化/false不会重新分区和格式化
.max_files = 5, // 打开文件最大数量
.allocation_unit_size = 16 * 1024
};
printf("%s->Initializing SD card\r\n",TAG);
printf("%s->Using SPI peripheralr\r\n",TAG);
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
// SPI总线初始化
ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
if (ret != ESP_OK) {
printf("%s->Failed to initialize bus.\r\n",TAG);
return;
}
// 这将初始化没有卡检测(CD)和写保护(WP)信号的插槽。
// 如果您的主板有这些信号,请修改slot_config.gpio_cd和slot_config.gpio_wp。
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = PIN_NUM_CS;
slot_config.host_id = host.slot;
// 挂载文件系统
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
printf("%s->Failed to mount filesystem.%s\r\n",TAG,
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
printf("%s->Failed to initialize the card %s (%s). ",TAG,
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
// TF卡已经初始化,打印TF卡属性
sdmmc_card_print_info(stdout, card);
// Print FAT FS size information
size_t bytes_total, bytes_free;
get_fatfs_usage(&bytes_total, &bytes_free);
printf("%s->FAT FS Total: %d MB, Free: %d MB \r\n",TAG, bytes_total / 1024, bytes_free / 1024);
// 使用POSIX和C标准库函数来处理文件。
printf("%s->Opening file\r\n",TAG);
FILE* f = fopen(MOUNT_POINT"/hello.txt", "w");// 创建一个文件
if (f == NULL) {
printf("%s->Failed to open file for writing\r\n",TAG);
return;
}
fprintf(f, "Hello %s!\n", card->cid.name);
fclose(f);
printf("%s->File written\r\n",TAG);
// 重命名前检查目标文件是否存在
struct stat st;
if (stat(MOUNT_POINT"/foo.txt", &st) == 0) {
unlink(MOUNT_POINT"/foo.txt");// 删除(如果存在)
}
// 重命名文件
printf("%s->Renaming file\r\n",TAG);
if (rename(MOUNT_POINT"/hello.txt", MOUNT_POINT"/foo.txt") != 0) {
printf("%s->Rename failed\r\n",TAG);
return;
}
// 读取文件
printf("%s->Reading file\r\n",TAG);
f = fopen(MOUNT_POINT"/foo.txt", "r");// 读取方式打开文件
if (f == NULL) {
printf("%s->Failed to open file for reading\r\n",TAG);
return;
}
fgets(ReadFileBuff, sizeof(ReadFileBuff), f); // 读取一行数据
fclose(f); // 关闭文件
char* pos = strchr(ReadFileBuff, '\n'); // 在字符串中查找换行
if (pos) {
*pos = '\0'; // 替换为结束符
}
printf("%s->Read from file: '%s'\r\n",TAG,ReadFileBuff);
// 卸载分区并禁用SDMMC或SPI外设
esp_vfs_fat_sdcard_unmount(mount_point, card);
printf("%s->Card unmounted\r\n",TAG);
//卸载总线
spi_bus_free(host.slot);
}
三、下载测试
打开ESP-IDF Command Prompt
cd命令进入此工程目录
cd F:\ESP32_DevBoard_File\9_SPI_SDCard
查看电脑设备管理器中开发板的串口号
执行idf.py -p COM9 flash monitor从串口9下载并运行打开口显示设备调试信息 Ctrl+c退出运行,查看串口信息输出
测试卡为16G闪迪 class 10 TF卡
本文地址:https://blog.csdn.net/cnicfhnui/article/details/108493320
推荐阅读
-
ESP32 开发笔记(三)源码示例 13_IR_Send_RMT 使用RMT实现红外数据发送(NEC编码)
-
ESP32 开发笔记(三)源码示例 11_IIC_AT24C02 使用IIC总线实现EEPROM小容量数据储存测试
-
ESP32 开发笔记(三)源码示例 5_KEY_Short_Long 使用IO中断和系统时间来检测按键时长实现长按短按
-
ESP32 开发笔记(三)源码示例 9_SPI_SDCard 使用SPI总线实现TF卡文件系统示例
-
ESP32 开发笔记(三)源码示例 5_KEY_Short_Long 使用IO中断和系统时间来检测按键时长实现长按短按
-
ESP32 开发笔记(三)源码示例 11_IIC_AT24C02 使用IIC总线实现EEPROM小容量数据储存测试
-
ESP32 开发笔记(三)源码示例 9_SPI_SDCard 使用SPI总线实现TF卡文件系统示例
-
ESP32 开发笔记(三)源码示例 13_IR_Send_RMT 使用RMT实现红外数据发送(NEC编码)