数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 46|回复: 1

《DNESP32S3使用指南-IDF版_V1.6》第三十八章 SPIFFS实验

[复制链接]
发表于 昨天 09:19 | 显示全部楼层 |阅读模式
第三十八章 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);
该函数的形参描述,如下表所示:
形参
描述
conf
指向esp_vfs_spiffs_conf_t配置结构的指针
表38.3.2.1 函数esp_vfs_spiffs_register ()形参描述
该函数的返回值描述,如下表所示:
返回值
描述
ESP_OK
返回:0,配置成功
ESP_ERR_NO_MEM
如果无法分配对象
ESP_ERR_INVALID_STATE
如果已安装或分区已加密
ESP_ERR_NOT_FOUND
如果找不到SPIFFS的分区
ESP_FAIL
如果装载或格式化失败
表38.3.2.2 函数esp_vfs_spiffs_register ()返回值描述
该函数使用esp_vfs_spiffs_conf_t类型的结构体变量传入,该结构体的定义如下所示:
结构体
成员变量
可选参数
esp_vfs_spiffs_conf_t
base_path
与文件系统关联的文件路径前缀。
partition_label
可选,要使用的SPIFFS分区的标签。如果设置为NULL,则f
max_files
可以同时打开的最大文件数。
format_if_mount_failed
如果为true,则在装载失败时将格式化文件系统。
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);
该函数的形参描述,如下表所示:
形参
描述
param partition_label
指向分区标签的指针,分区表名称
total_bytes
文件系统的大小
used_bytes
文件系统中当前使用的字节数
表38.3.2.4 函数esp_spiffs_info ()形参描述
该函数的返回值描述,如下表所示:
返回值
描述
ESP_OK
返回:0,配置成功
ESP_FAIL
如果装载失败
表38.3.2.5 函数esp_spiffs_info ()返回值描述
3,注销和卸载SPIFFS
该函数从VFS注销和卸载SPIFFS,其函数原型如下所示:
esp_err_t esp_vfs_spiffs_unregister(const char* partition_label);
该函数的形参描述,如下表所示:
形参
描述
param partition_label
指向分区表的指针,分区表名称
表38.3.2.6 函数esp_vfs_spiffs_unregister ()形参描述
该函数的返回值描述,如下表所示:
返回值
描述
ESP_OK
返回:0,配置成功
ESP_ERR_INVALID_STATE
已注销
表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 程序运行效果图

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-8-6 07:32 , Processed in 0.093600 second(s), 7 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表