利用ESP32-S3及其板载flash实现FATFS文件系统
前言
距离上一次更新,已经是很久远的事了,考研,秋招,让自己并没有过多的时间去更新文章,尽管在此期间,自己确实有积累一定的项目经验,但因为懒以及各种小项目的推进,导致更新计划屡屡搁浅。
目前,手头上的事情终于没有那么多了,自己也终于可以进行一些文章的更新了,希望可以给自己这个菜鸟带来一点点进步。
背景
最近入手了一块ESP32-S3-WROOM-2的板子,其板子上搭载了一块32MB的flash,我下意识就想着说,这么大的flash能不能跑个fafts,顺便可以给lvgl的图片显示提供支持,于是便有了这篇文章。
开发环境
vscode+idf
主要开发步骤
1.在例程的基础上进行修改
利用乐鑫idf提供的例程,我们可以很轻松的在上面进行修改,所以我们在示例项目中选择ext_flash_fafts这个例程去进行修改。
后续的改动也是按照这个例程去进行修改。2.例程的相关代码进行修改
例程创建后,会发现烧录到板子上根本就没有办法正常使用,以及跟flash正常握手,这是一个很奇怪的现象。
其中有几个要去注意修改的点
第一个点就是,例程中所使用的引脚就是VSPI引脚,而很多时候,在实际的开发中,我们并不可能每一次都是用VSPI的引脚去进行对板载flash的握手,在大多数时候都是要进行修改的,而这次也不例外。
其主要的修改处如下所示:
上图中的修改处主要在于对总线配置引脚的结构体进行修改,治理需要结合自己的引脚去进行修改,其次就是host_id以及cs_id也要进行修改,一般来说前者应该是SPI1_HOST,而后者是一。
为什么?
通过SPI1总线可以访问外部的flash,其次在SPI1总线的使用注意事项中也有提及这一事项
可以从中获取到的信息就是,SPI1总线可以在设备跟flash或者psram中的数据缓存区去进行数据传输。回到正题
第二个现象就是修改了管脚之后还是会出现问题,
其主要的错误现象如下图所示:
其主要的问题就在于flash的初始化问题,也就是例程中的example_init_ext_flash()函数,更准确来说,问题是出在ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &bus_config, 1));这一条函数语句上,板子会不停的上电重启,其主要原因就是在于spi总线的初始化并不能顺利进行。
那我们应该怎么去修改??
主要的思路就是偷懒,如何理解?就是自己编写一个初始化的程序,但并不与其对应的错误检查函数进行配套使用。
具体的代码如下所示:
#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的修改
注意:是要在ESP-IDF Terminal 中输入idf.py menuconfig,而不是传统的CMD窗口中进行输入。
在serial flash config中选择合适的flash大小,以及采样模式等等的参数
其次就是对分区表进行修改
从例程esp-idf\examples\system\console下面找到partitions_example.csv并刚才复制到工程文件夹下。
并且根据自己的需要,对于分区的大小进行修改。
对上图的分区做出一点解释:
factory:是默认的 app 分区。启动加载器将默认加载该应用程序。但如果存在类型为 data/ota 分区,则启动加载器将加载 data/ota 分区中的数据,进而判断启动哪个 OTA 镜像文件。OTA 升级永远都不会更新 factory 分区中的内容.如果您希望在 OTA 项目中预留更多 flash,可以删除 factory 分区,转而使用 ota_0 分区。
其次,fat就是我们的flash中搭载的fafts文件系统的占用空间的大小。
最后,我们可以不用写偏移地址,只需要需要的大小即可,系统会自动帮我们进行折算。设置分区表
选用自己修改过后的分区表进行分区。
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);
}
主要目的在于创建文件,写入文件,读取文件,反馈对应的数据进行参考,具体就不做过多的解释了。
最后选择好对应的串口,型号,和下载方式即可。
结果测试
boot loader的打印
对该分区表进行解释
flash从0x9000以前的区域,都是bootloader,用于esp32的启动。
而factory分区,我是分了5M的大小给他,具体的length计算方式为510241024=(hex)500000;
同理,对应的 storage分区,我分了25M给他,具体的length计算方式为2510241024=(hex)1900000;
初步验证成功。最后通过日志打印查看结果,并且做出一定解释:
1.33554432:33554432/1024/1024=32,与flash的大小对的上。
2.25348kb即为24.75390625MB,大致与分区表设置相同。
3.文件内容的读写正常。最后,你还可以更改名字,一样可以使用,只用调整对应的代码以及分区表名称即可。
例如:
label处就变为了fatfs,更方便管理,提高了可读性。
**
综上所述,目标已经达到。
**
具体代码已开源。
https://gitee.com/kockpaiki/kockpaiki_esp32_est_flash_fafts.git