图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);
该函数的形参描述,如下表所示:
| |
| 指向esp_vfs_spiffs_conf_t配置结构的指针 |
表38.3.2.1 函数esp_vfs_spiffs_register ()形参描述
该函数的返回值描述,如下表所示:
表38.3.2.2 函数esp_vfs_spiffs_register ()返回值描述
该函数使用esp_vfs_spiffs_conf_t类型的结构体变量传入,该结构体的定义如下所示:
| 成员变量 | |
| | |
| 可选,要使用的SPIFFS分区的标签。如果设置为NULL,则f |
| |
| |
表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";
/**
*
@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文件,然后对这文件进行读写操作。