利用ESP32-S3及其板载flash实现FATFS文件系统

前言

距离上一次更新,已经是很久远的事了,考研,秋招,让自己并没有过多的时间去更新文章,尽管在此期间,自己确实有积累一定的项目经验,但因为懒以及各种小项目的推进,导致更新计划屡屡搁浅。

目前,手头上的事情终于没有那么多了,自己也终于可以进行一些文章的更新了,希望可以给自己这个菜鸟带来一点点进步。

背景

最近入手了一块ESP32-S3-WROOM-2的板子,其板子上搭载了一块32MB的flash,我下意识就想着说,这么大的flash能不能跑个fafts,顺便可以给lvgl的图片显示提供支持,于是便有了这篇文章。

开发环境

vscode+idf

主要开发步骤

1.在例程的基础上进行修改

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_iot


利用乐鑫idf提供的例程,我们可以很轻松的在上面进行修改,所以我们在示例项目中选择ext_flash_fafts这个例程去进行修改。

后续的改动也是按照这个例程去进行修改。2.例程的相关代码进行修改

例程创建后,会发现烧录到板子上根本就没有办法正常使用,以及跟flash正常握手,这是一个很奇怪的现象。

其中有几个要去注意修改的点

第一个点就是,例程中所使用的引脚就是VSPI引脚,而很多时候,在实际的开发中,我们并不可能每一次都是用VSPI的引脚去进行对板载flash的握手,在大多数时候都是要进行修改的,而这次也不例外。

其主要的修改处如下所示:

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_单片机_02


上图中的修改处主要在于对总线配置引脚的结构体进行修改,治理需要结合自己的引脚去进行修改,其次就是host_id以及cs_id也要进行修改,一般来说前者应该是SPI1_HOST,而后者是一。

为什么?

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_iot_03

通过SPI1总线可以访问外部的flash,其次在SPI1总线的使用注意事项中也有提及这一事项

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_iot_04

可以从中获取到的信息就是,SPI1总线可以在设备跟flash或者psram中的数据缓存区去进行数据传输。回到正题

第二个现象就是修改了管脚之后还是会出现问题,

其主要的错误现象如下图所示:

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_github_05

其主要的问题就在于flash的初始化问题,也就是例程中的example_init_ext_flash()函数,更准确来说,问题是出在ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &bus_config, 1));这一条函数语句上,板子会不停的上电重启,其主要原因就是在于spi总线的初始化并不能顺利进行。

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_mcu_06

那我们应该怎么去修改??
主要的思路就是偷懒,如何理解?就是自己编写一个初始化的程序,但并不与其对应的错误检查函数进行配套使用。
具体的代码如下所示:

#define MOUNT_PATH "/storage/data"
static void initialize_filesystem(void)
{
    spi_flash_init();
    ESP_LOGE(TAG,"chip_size is (%d)",spi_flash_get_chip_size());
    static wl_handle_t wl_handle;
    const esp_vfs_fat_mount_config_t mount_config = {
        .max_files = 40,
        .format_if_mount_failed = true};
    esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
        return;
    }
}

上述代码中的MOUNT_PATH,需要与后续的文件系统分区去进行对应。
在主函数中,对应的初始化函数也要进行替换。

3.对例程进行添加和设置
很好理解,例程改完错,我们还要对自己的板子进行设置,毕竟搭载的flash大小和psram并不一致。

首先是进行flash的修改

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_mcu_07

注意:是要在ESP-IDF Terminal 中输入idf.py menuconfig,而不是传统的CMD窗口中进行输入。

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_mcu_08

在serial flash config中选择合适的flash大小,以及采样模式等等的参数

其次就是对分区表进行修改

从例程esp-idf\examples\system\console下面找到partitions_example.csv并刚才复制到工程文件夹下。

并且根据自己的需要,对于分区的大小进行修改。

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_单片机_09

对上图的分区做出一点解释:

factory:是默认的 app 分区。启动加载器将默认加载该应用程序。但如果存在类型为 data/ota 分区,则启动加载器将加载 data/ota 分区中的数据,进而判断启动哪个 OTA 镜像文件。OTA 升级永远都不会更新 factory 分区中的内容.如果您希望在 OTA 项目中预留更多 flash,可以删除 factory 分区,转而使用 ota_0 分区。

其次,fat就是我们的flash中搭载的fafts文件系统的占用空间的大小。

最后,我们可以不用写偏移地址,只需要需要的大小即可,系统会自动帮我们进行折算。设置分区表

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_iot_10


选用自己修改过后的分区表进行分区。

4.编写测试函数以及烧录程序和结果测试

主函数如下:

void app_main(void)
{

     initialize_filesystem();
    // // Print FAT FS size information 
   
    size_t bytes_total, bytes_free;
    example_get_fatfs_usage(&bytes_total, &bytes_free);
    ESP_LOGI(TAG, "FAT FS: %d kB total, %d kB free", bytes_total / 1024, bytes_free / 1024);
    FILE *f = fopen("/storage/data/hello.txt", "wb");
    // // Create a file in FAT FS
    ESP_LOGI(TAG, "Opening file");
     
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }
    fprintf(f, "this is a goddamn fafts %s\n", esp_get_idf_version());
    fclose(f);
    ESP_LOGI(TAG, "File written");

    // Open file for reading
    ESP_LOGI(TAG, "Reading file");
    f = fopen("/storage/data/hello.txt", "rb");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for reading");
        return;
    }
    char line[128];
    fgets(line, sizeof(line), f);
    fclose(f);
    // strip newline
    char *pos = strchr(line, '\n');
    if (pos) {
        *pos = '\0';
    }
    ESP_LOGI(TAG, "Read from file: '%s'", line);
  
}

主要目的在于创建文件,写入文件,读取文件,反馈对应的数据进行参考,具体就不做过多的解释了。

最后选择好对应的串口,型号,和下载方式即可。

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_单片机_11

结果测试

boot loader的打印

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_开源_12

对该分区表进行解释

flash从0x9000以前的区域,都是bootloader,用于esp32的启动。

而factory分区,我是分了5M的大小给他,具体的length计算方式为510241024=(hex)500000;

同理,对应的 storage分区,我分了25M给他,具体的length计算方式为2510241024=(hex)1900000;

初步验证成功。最后通过日志打印查看结果,并且做出一定解释:

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_单片机_13


1.33554432:33554432/1024/1024=32,与flash的大小对的上。

2.25348kb即为24.75390625MB,大致与分区表设置相同。

3.文件内容的读写正常。最后,你还可以更改名字,一样可以使用,只用调整对应的代码以及分区表名称即可。

例如:

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_单片机_14

label处就变为了fatfs,更方便管理,提高了可读性。

**

综上所述,目标已经达到。

**

怎样把文件放到esp32 spi flash文件目录 esp32 fatfs_单片机_15


具体代码已开源。

https://gitee.com/kockpaiki/kockpaiki_esp32_est_flash_fafts.git