第三十八章 SPIFFS实验 上一章实验中已经成功驱动SD卡,并可对SD卡进行读写操作,但读写SD卡时都是直接读出或写入二进制数据,这样使用起来显得十分不方便,因此本章将介绍SPIFFS,SPIFFS是一个用于SPI NOR flash设备的嵌入式文件系统,支持磨损均衡以及文件系统一致性检查等功能。通过本章的学习,读者将学习到SPIFFS的基本使用。 本章分为如下几个小节: 38.1 SPIFFS简介 38.2 硬件设计 38.3 程序设计 38.4 下载验证 38.1 SPIFFS介绍 SPIFFS是一个用于嵌入式目标上的SPI NOR flash设备的文件系统,并且有如下特点: l 小目标,没有堆的少量RAM l 只有大范围的数据块才能被擦除 l 擦除会将块中的所有位重置为1 l 写操作将1置0 l 0只能被擦除成1 l 磨损均衡 以上几点是SPIFFS的特点,下面则说明了SPIFFS具体能做些什么: l 专门为低ram使用而设计 l 使用静态大小的ram缓冲区,与文件的数量无关 l 类可移植操作系统接口:打开、关闭、读、写、查找、统计等 l 它可以在任何NOR闪存上运行,不仅是SPI闪存,理论上也可以在微处理器的嵌入式闪存上运行 l 多个spiffs配置可以在相同的目标上运行—甚至可以在相同的SPI闪存设备上运行 l 实现静态磨损调平(也就是flash的寿命维护) l 内置文件系统一致性检查 l 高度可配置的 38.2 硬件设计 38.2.1 例程功能 1.在nor flash指定区域新建holle.txt文件,然后对这文件进行读写操作 2. LED闪烁,指示程序正在运行 38.2.2 硬件资源 1. LED灯 LED -IO0 2. XL9555 IIC_SDA-IO41 IIC_SCL-IO42 3. SPILCD CS-IO21 SCK-IO12 SDA-IO11 DC-IO40(在P5端口,使用跳线帽将IO_SET和LCD_DC相连) PWR- IO1_3(XL9555) RST- IO1_2(XL9555) 4. SPIFFS 38.2.3 原理图 本章实验使用的SPIFFS为软件库,因此没有对应的连接原理图。 38.3 程序设计 38.3.1 程序流程图 程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图: ![]() 图38.3.1.1 IIC_EXIO实验程序流程图 38.3.2 SPIFFS函数解析 SPIFFS涉及到的文件并不算多,主要调用到了C库的函数,关于C库的函数我们在这里就不过多介绍了,主要介绍一下调用到ESP32 IDF库中的函数。 1,注册装载SPIFFS 该函数使用给定的路径前缀将SPIFFS注册并装载到VFS,其函数原型如下所示: esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf); 该函数的形参描述,如下表所示:
表38.3.2.1 函数esp_vfs_spiffs_register ()形参描述 该函数的返回值描述,如下表所示:
表38.3.2.2 函数esp_vfs_spiffs_register ()返回值描述 该函数使用esp_vfs_spiffs_conf_t类型的结构体变量传入,该结构体的定义如下所示:
表38.3.2.3 esp_vfs_spiffs_conf_t结构体参数值描述 完成上述结构体参数配置之后,可以将结构传递给esp_vfs_spiffs_register 函数,用以实例化SPIFFS。 2,获取SPIFFS的信息 该函数用于获取SPIFFS的信息,其函数原型如下所示: esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes); 该函数的形参描述,如下表所示:
表38.3.2.4 函数esp_spiffs_info ()形参描述 该函数的返回值描述,如下表所示:
表38.3.2.5 函数esp_spiffs_info ()返回值描述 3,注销和卸载SPIFFS 该函数从VFS注销和卸载SPIFFS,其函数原型如下所示: esp_err_t esp_vfs_spiffs_unregister(const char* partition_label); 该函数的形参描述,如下表所示:
表38.3.2.6 函数esp_vfs_spiffs_unregister ()形参描述 该函数的返回值描述,如下表所示:
表38.3.2.7 函数esp_vfs_spiffs_unregister ()返回值描述 38.3.3 SPIFFS驱动解析 在IDF版的27_spiffs例程中,作者在分区表中添加了SPIFFS的内容,27_spiffs \components\BSP路径下并无新的驱动文件增加。分区表内容如下: # ESP-IDF Partition Table # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, , phy_init, data, phy, 0xf000, 0x1000, , factory, app, factory, 0x10000, 0x1F0000, , vfs, data, fat, 0x200000, 0xA00000, , storage, data, spiffs, 0xc00000, 0x400000, , 38.3.4 CMakeLists.txt文件 打开本实验BSP下的CMakeLists.txt文件,其内容如下所示: set(src_dirs IIC LCD LED SPI XL9555) set(include_dirs IIC LCD LED SPI XL9555) set(requires driver ) idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format) 该例程驱动文件与依赖库并没有新的文件添加。 38.3.5 实验应用代码 打开main/main.c文件,该文件定义了工程入口函数,名为app_main。该函数代码如下。 i2c_obj_t i2c0_master; #define DEFAULT_FD_NUM 5 #define DEFAULT_MOUNT_POINT "/spiffs" #define WRITE_DATA "ALIENTEK ESP32-S3\r\n" static const char *TAG = "spiffs"; /** * @Brief spiffs初始化 * @param partition_label:分区表的分区名称 * @param mount_point:文件系统关联的文件路径前缀 * @param max_files:可以同时打开的最大文件数 * @retval 无 */ esp_err_t spiffs_init(char *partition_label,char *mount_point,size_t max_files) { /* 配置spiffs文件系统各个参数 */ esp_vfs_spiffs_conf_t conf = { .base_path = mount_point, .partition_label = partition_label, .max_files = max_files, .format_if_mount_failed = true, }; /* 使用上面定义的设置来初始化和挂载SPIFFS文件系统 */ esp_err_t ret_val = esp_vfs_spiffs_register(&conf); /* 判断SPIFFS挂载及初始化是否成功 */ if (ret_val != ESP_OK) { if (ret_val == ESP_FAIL) { printf("Failed to mount or format filesystem\n"); } else if (ret_val == ESP_ERR_NOT_FOUND) { printf("Failed to find SPIFFS partition\n"); } else { printf("Failed to initialize SPIFFS(%s)\n",esp_err_to_name(ret_val)); } return ESP_FAIL; } /* 打印SPIFFS存储信息 */ size_t total = 0, used = 0; ret_val = esp_spiffs_info(conf.partition_label, &total, &used); if (ret_val != ESP_OK) { ESP_LOGE(TAG, "Failed to get SPIFFS partition information(%s)", esp_err_to_name(ret_val)); } else { ESP_LOGE(TAG, "Partition size: total: %d, used: %d", total, used); } return ret_val; } /** * @brief 注销spiffs初始化 * @param partition_label:分区表标识 * @retval 无 */ esp_err_t spiffs_deinit(char *partition_label) { return esp_vfs_spiffs_unregister(partition_label); } /** * @brief 测试spiffs * @param 无 * @retval 无 */ void spiffs_test(void) { ESP_LOGI(TAG, "Opening file"); /* 建立一个名为/spiffs/hello.txt的只写文件 */ FILE* f = fopen("/spiffs/hello.txt", "w"); if (f == NULL) { ESP_LOGE(TAG, "Failed to open file for writing"); return; } /* 写入字符 */ fprintf(f, WRITE_DATA); fclose(f); ESP_LOGI(TAG, "File written"); /* 重命名之前检查目标文件是否存在 */ struct stat st; if (stat("/spiffs/foo.txt", &st) == 0) /* 获取文件信息,获取成功返回0 */ { /* 从文件系统中删除一个名称。 如果名称是文件的最后一个连接,并且没有其它进程将文件打开, 名称对应的文件会实际被删除。 */ unlink("/spiffs/foo.txt"); } /* 重命名创建的文件 */ ESP_LOGI(TAG, "Renaming file"); if (rename("/spiffs/hello.txt", "/spiffs/foo.txt") != 0) { ESP_LOGE(TAG, "Rename failed"); return; } /* 打开重命名的文件并读取 */ ESP_LOGI(TAG, "Reading file"); f = fopen("/spiffs/foo.txt", "r"); if (f == NULL) { ESP_LOGE(TAG, "Failed to open file for reading"); return; } char line[64]; fgets(line, sizeof(line), f); fclose(f); char* pos = strchr(line, '\n'); /* 指针pos指向第一个找到‘\n’ */ if (pos) { *pos = '\0'; /* 将‘\n’替换为‘\0’ */ } ESP_LOGI(TAG, "Read from file: '%s'", line); lcd_show_string(90, 110, 200, 16, 16, line, RED); } 在SPIFFS驱动中,首先初始化并挂载了一个SPIFFS分区,然后使用POSIX和C库API写入和读取数据。 i2c_obj_t i2c0_master; /** * @brief 程序入口 * @param 无 * @retval 无 */ void app_main(void) { esp_err_t ret; ret = nvs_flash_init(); /* 初始化NVS */ if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret==ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); led_init(); /* LCD初始化 */ i2c0_master = iic_init(I2C_NUM_0); /* 初始化IIC0 */ spi2_init(); /* SPI初始化 */ xl9555_init(i2c0_master); /* XL9555初始化 */ lcd_init(); /* LCD初始化 */ spiffs_init("storage", DEFAULT_MOUNT_POINT, DEFAULT_FD_NUM);/*SPIFFS初始化*/ /* 显示实验信息 */ lcd_show_string(10, 50, 200, 16, 16, "ESP32", RED); lcd_show_string(10, 70, 200, 16, 16, "SPIFFS TEST", RED); lcd_show_string(10, 90, 200, 16, 16, "ATOM@ALIENTEK", RED); lcd_show_string(10, 110, 200, 16, 16, "Read file:", BLUE); spiffs_test(); /* SPIFFS测试 */ while (1) { LED_TOGGLE(); vTaskDelay(500); } } 可以看到,本实验的应用代码中,在一系列初始化之后,配置spiffs文件系统各个参数,再建立一个名为/spiffs/hello.txt的只写文件,LED闪烁表明程序正在运行。 38.4 下载验证 在完成编译和烧录操作后,在指定区域新建hello.txt文件,然后对这文件进行读写操作。 ![]() 图38.4.1 程序运行效果图
|
191 浏览 0 评论
318 浏览 0 评论
336 浏览 0 评论
QuarkPi-CA2 RK3588S卡片电脑:6.0Tops NPU+8K视频编解码+接口丰富,高性能嵌入式开发!
1485 浏览 0 评论
1263 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
12854 浏览 31 评论