ESP32存储-4.SPIFFS文件系统

本文最后更新于:4 个月前

说明:

  1. 本文档由DuRuofu撰写,由DuRuofu负责解释及执行。
  2. 本文档主要介绍,ESP32 flash SPIFFS文件系统的使用.

修订历史:

文档名称 版本 作者 时间 备注
ESP32存储-SPIFFS文件系统 v1.0.0 DuRuofu 2024-03-06 首次建立

ESP32存储-SPIFFS文件系统

一、介绍

关于esp32的spiffs文件系统的详细内容,请看esp32官网的介绍:espidf编程指南-spiffs

  • SPIFFS是一种专门为像ESP32/8266这种嵌入式设备而开发的微型文件系统,SPIFFS是设置在Flash中的一块空间,可以用来存放如网页、图片等体积小的静态资源,而无需采用存储于外部SD卡的方式。
  • SPIFFS中的数据不会因为断电而丢失

对于spiffs,乐鑫提供了很好的支持,专门提供了工具(spiffsgen.py,mkspiffs)用于对实现spiffs 在esp32 上的创建、格式化等操作。

注意:

  1. 目前,SPIFFS 尚不支持目录,但可以生成扁平结构。如果 SPIFFS 挂载在 /spiffs 下,在 /spiffs/tmp/myfile.txt 路径下创建一个文件则会在 SPIFFS 中生成一个名为 /tmp/myfile.txt 的文件,而不是在 /spiffs/tmp 下生成名为 myfile.txt 的文件;
  2. SPIFFS 并非实时栈,每次写操作耗时不等;
  3. 目前,SPIFFS 尚不支持检测或处理已损坏的块。
  4. SPIFFS 只能稳定地使用约 75% 的指定分区容量。
  5. 当文件系统空间不足时,垃圾收集器会尝试多次扫描文件系统来寻找可用空间。根据所需空间的不同,写操作会被调用多次,每次函数调用将花费几秒
  6. 被删除文件通常不会被完全清除,会在文件系统中遗留下无法使用的部分
  7. 如果 ESP32 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。

二、SPIFFS文件系统使用

2.1 新建工程,准备自定义分区表

在分区表里添加 soiffs 文件系统的分区

1
2
3
4
5
6
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x4000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, spiffs, , 0xF0000,

选择自定义分区表:

2.2 建立soiffs镜像

在项目根目录建立soiffs镜像文件夹spiffs_image

在项目mian组件cmarklist文件添加镜像构建工具相关代码:
spiffs_create_partition_image(my_spiffs_partition my_folder FLASH_IN_PROJECT)

1
2
3
4
5
6
7
8
9
10
11
12
idf_component_register(SRCS "flash_spiffs.c"
                    INCLUDE_DIRS ".")

# Create a SPIFFS image from the contents of the 'spiffs_image' directory

# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that

# the generated image should be flashed when the entire project is flashed to

# the target with 'idf.py -p PORT flash'.

spiffs_create_partition_image(storage ../spiffs_image FLASH_IN_PROJECT)
2.3 码里挂载文件系统

然后在代码里挂载文件系统即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ESP_LOGI(TAG, "Initializing SPIFFS");

esp_vfs_spiffs_conf_t conf = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = false
};

// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_spiffs_register(&conf);

if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return;
}

esp_vfs_spiffs_register用于将SPIFFS注册并挂载到虚拟文件系统(VFS)中,并指定路径前缀。

函数参数中的conf是一个指向esp_vfs_spiffs_conf_t配置结构体的指针。

esp_vfs_spiffs_conf_t参数:

  • base_path: 文件系统关联的文件路径前缀。
  • partition_label: 可选项,要使用的 SPIFFS 分区的标签。如果设置为 NULL,则将使用 subtype=spiffs 的第一个分区。
  • max_files: 可同时打开的最大文件数。
  • format_if_mount_failed: 如果为 true,在挂载失败时将格式化文件系统。

三、案例

下面的示例程序来自:https://github.com/espressif/esp-idf/tree/v5.2.1/examples/storage/spiffsgen

主要功能包括初始化 SPIFFS、读取文件内容以及计算文件的 MD5 哈希值。

app_main 函数中,首先初始化 SPIFFS 文件系统,然后获取文件系统的信息,接着依次调用 read_hello_txtcompute_alice_txt_md5 函数来读取 hello.txt 文件的内容和计算 alice.txt 文件的 MD5 哈希值。最后,取消挂载 SPIFFS 文件系统并结束程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "mbedtls/md5.h"

static const char *TAG = "example";

static void read_hello_txt(void)
{
ESP_LOGI(TAG, "Reading hello.txt");

// Open for reading hello.txt
FILE* f = fopen("/spiffs/hello.txt", "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open hello.txt");
return;
}

char buf[64];
memset(buf, 0, sizeof(buf));
fread(buf, 1, sizeof(buf), f);
fclose(f);

// Display the read contents from the file
ESP_LOGI(TAG, "Read from hello.txt: %s", buf);
}

static void compute_alice_txt_md5(void)
{
ESP_LOGI(TAG, "Computing alice.txt MD5 hash");

// The file alice.txt lives under a subdirectory, though SPIFFS itself is flat
FILE* f = fopen("/spiffs/sub/alice.txt", "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open alice.txt");
return;
}

// Read file and compute the digest chunk by chunk
#define MD5_MAX_LEN 16

char buf[64];
mbedtls_md5_context ctx;
unsigned char digest[MD5_MAX_LEN];

mbedtls_md5_init(&ctx);
mbedtls_md5_starts(&ctx);

size_t read;

do {
read = fread((void*) buf, 1, sizeof(buf), f);
mbedtls_md5_update(&ctx, (unsigned const char*) buf, read);
} while(read == sizeof(buf));

mbedtls_md5_finish(&ctx, digest);

// Create a string of the digest
char digest_str[MD5_MAX_LEN * 2];

for (int i = 0; i < MD5_MAX_LEN; i++) {
sprintf(&digest_str[i * 2], "%02x", (unsigned int)digest[i]);
}

// For reference, MD5 should be deeb71f585cbb3ae5f7976d5127faf2a
ESP_LOGI(TAG, "Computed MD5 hash of alice.txt: %s", digest_str);

fclose(f);
}

void app_main(void)
{
ESP_LOGI(TAG, "Initializing SPIFFS");

esp_vfs_spiffs_conf_t conf = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = false
};

// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_spiffs_register(&conf);

if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return;
}

size_t total = 0, used = 0;
ret = esp_spiffs_info(NULL, &total, &used);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
} else {
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
}

/* The following calls demonstrate reading files from the generated SPIFFS
* image. The images should contain the same files and contents as the spiffs_image directory.
*/

// Read and display the contents of a small text file (hello.txt)
read_hello_txt();

// Compute and display the MD5 hash of a large text file (alice.txt)
compute_alice_txt_md5();

// All done, unmount partition and disable SPIFFS
esp_vfs_spiffs_unregister(NULL);
ESP_LOGI(TAG, "SPIFFS unmounted");
}

效果:

参考链接

  1. https://docs.espressif.com/projects/esp-idf/zh_CN/release-v5.2/esp32/api-reference/storage/spiffs.html

ESP32存储-4.SPIFFS文件系统
https://www.duruofu.xyz/2024/03/06/4.硬件相关/MCU/ESP32/04.ESP32存储器入门/4.4-ESP32存储-SPIFFS文件系统入门/ESP32存储-SPIFFS文件系统/
作者
DuRuofu
发布于
2024年3月6日
更新于
2024年3月6日
许可协议