虚拟文件系统

概述

本章主要描述虚拟文件系统(VFS)的类型、使用场景、使用方法等。

VFS 底层实现包含 FatFS 与 LittleFS:

  • FatFS 优势:兼容性、跨平台支持、开发便捷性

  • LittleFS 优势:掉电恢复、闪存寿命优化、低资源消耗

用户可通过使用 VFS 忽略不同文件系统之间的使用差异,专注于开发需求。

VFS 提供了 fopen、fclose、fwrite、fread 等 通用文件操作接口键值对(KV)接口Flash 转换层(FTL)接口 基于通用文件操作实现。

VFS 的架构如下图所示:

VFS 初始化

Flash 中的 VFS 存在两块独立的区域:

  • VFS1 区域为配置存放分区,默认设置为 LittleFS(支持掉电保护功能)

  • VFS2 区域是给用户预留的分区,默认不分配 Flash 空间,用户可以根据需要自行修改配置。

备注

  • VFS 挂载至 Flash 时,若挂载失败,会检测 Flash 是否处于空白状态(全 0xFF)。若是,将执行 Flash 编程操作以初始化 VFS。

  • 为确保合理使用 FatFS,参考 配置工程(menuconfig) 进入 CONFIG VFS 配置,选择 Enable VFS FATFS 且勾选需要使能的功能模块。

  • 若想使用只读 FatFS,在选择 Enable VFS FATFS 后勾选 FATFS Read Only,可以在 VFS 层防止文件系统被篡改。

  • 若想使用 exFAT,在选择 Enable VFS FATFS 后勾选 FATFS Support EXFAT

VFS 用法

Flash 中的 VFS

如果需要适当调整 VFS 位置,可以参考 Flash 布局修改,对 VFS1VFS2 区域进行调整。

小心

  • VFS1 区域必须存在,且其大小必须大于等于 128KB。

  • 最多可配置两个 VFS 区域。

备注

当保存和运行固件的 flash 上 VFS 分区容量不足时,可通过标准 SPI 接口外接第二块 Flash 以扩展存储空间。后续文档统一以 Secondary Flash 指代该外接 Flash。

SD 卡中的 VFS

不支持。

APP 固件中的 VFS

如果文件系统中的内容有升级的需求,比如语音方案中替换提示音和语音包,VFS 对此提供了更方便的配置功能。详细步骤如下:

  1. 准备只读文件并将其转换成 FAT 格式的二进制文件,具体方法请参考 VFS 二进制文件生成

  2. 将生成的二进制文件命名为 fatfs.bin,并放置于 {SDK}\amebadplus_gcc_project 目录下。

  3. 参考 配置工程(menuconfig) 进入 CONFIG VFS 配置,选择 Enable VFS FATFSFATFS within APP Image

  4. 重新编译应用程序固件。

应用程序固件 (km0_km4_app.bin) 将包含一个 FAT 格式的只读 VFS 区域,该区域将在启动过程中自动挂载。

启动后,出现日志 VFS-FAT Init Success,即表明 FAT 文件系统已成功挂载。

后续需要更新 FAT 文件系统内容时,通过 OTA 的方式可以跟随固件一起更新。

关于文件的使用方法,请参考 通用文件操作KV 操作

备注

  • 为了优化文件系统的有效空间利用率,目前仅支持 FAT 格式。

  • 为了防止破坏 OTA 区域,包含文件系统的固件大小不能超过 flash 布局修改 中的 应用程序分区 大小。

  • 此功能只能在 flash 上使用。

  • APP 固件中的 VFS 与 VFS1 和 VFS2 分区相互独立。

通用文件操作

VFS 中常用的通用文件操作接口如下表所示:

API

参数

描述

fopen

  • const char * filename

  • const char * mode

以指定模式打开指定文件

fclose

  • FILE * stream

关闭文件流

fread

  • void * ptr

  • size_t size

  • size_t count

  • FILE * stream

从文件流中读取数据到指定缓冲区

fwrite

  • const void * ptr

  • size_t size

  • size_t count

  • FILE * stream

将缓冲区数据写入文件流

fseek

  • FILE * stream

  • long int offset

  • int origin

设置文件流的读写位置到指定偏移量

rewind

  • FILE * stream

将文件流的读写位置重置到文件开头

fgetpos

  • FILE * stream

  • fpos_t * p

获取当前文件流的读写位置并保存到指定的位置

fsetpos

  • FILE * stream

  • fpos_t * p

设置文件流的读写位置为指定的位置

fflush

  • FILE * stream

刷新文件流的输出缓冲区

remove

  • const char * filename

删除指定文件,使其不可访问

rename

  • const char * oldname

  • const char * newname

将文件从旧路径重命名为新路径

feof

  • FILE * stream

检测文件流是否已到达末尾

ferror

  • FILE * stream

检测文件流是否发生错误

ftell

  • FILE * stream

返回当前文件流的读写位置

ftruncate

  • FILE * stream

  • off_t length

将文件截断至指定长度

opendir

  • const char * name

打开目录

readdir

  • DIR * pdir

读取目录内容

closedir

  • DIR * dirp

关闭已打开的目录

rmdir

  • const char * path

删除空目录

mkdir

  • const char * pathname

  • mode_t mode

创建新目录

access

  • const char * pathname

  • int mode

检查文件的可访问性

stat

  • const char * path

  • struct stat * buf

获取文件元数据

用户可以参考 VFS 示例 测试通用文件操作是如何工作的。测试日志应包含如下关键信息:

[example_vfs_thread] fwrite succeeded !!!
[example_vfs_thread] fread succeeded !!!
[example_vfs_thread] remove file succeeded !!!

备注

fseek 接口的返回值与标准接口不同。如果成功,将返回当前文件指针相对于文件开头的偏移量。

KV 操作

我们同时提供了简单的键值对(KV)接口,这些接口位于 kv.c

用户可以参考 KV 示例 测试 KV 接口是如何工作的。测试日志应包含如下关键信息:

rt_kv_set success, write 28 letters.
rt_kv_get success, read 28 letters.
rt_kv_delete success.

备注

KV 接口操作都在 VFS1 分区的文件系统 KV 目录中进行。key-value 中的 key 对应文件名,value 对应文件内容。

FTL

基于 VFS 提供了 FTL 接口层:

  • Flash 转换层(Flash Translation Layer,FTL)是专为 BT 设计的系统软件层,旨在优化 Flash 存储器作为数据存储介质的易用性。

  • FTL 通过将上层逻辑地址请求转换为 VFS 的文件读写操作,既提升 Flash 存储器的读写性能,又继承 VFS 的磨损均衡、垃圾回收等高级管理功能。

FTL 的架构如下图所示:

../../_images/vfs_ftl_architecture.svg

典型 BLE 应用

  • 蓝牙 Host 协议栈默认使用 344 字节 FTL。

  • SDK 默认维护 4 条 BLE 连接信息,每条连接需要 216 字节 FTL,BLE 连接数量可以通过 RTK_BLE_GAP_MAX_LINKS 设置。

典型 BLE Mesh 应用

需在 Host 协议栈和 BLE 连接占用的 FTL 基础上叠加 Mesh 专需空间:

  1. Mesh device

    • Mesh 协议栈默认使用 1752 字节 FTL。

    • 默认支持包含 20 个节点的 Mesh 网络,每个节点需 16 字节 RPL 空间,RPL 数量可以通过 bt_mesh_rpl_num 设置。

  2. Mesh provisioner

    • Mesh 协议栈默认使用 1280 字节 FTL。

    • 默认支持 20 个节点配网,每个节点需要 20 字节 Device key 和 16 字节 RPL,Device key 数量可以通过 bt_mesh_dev_key_num 设置,RPL 数量可以通过 bt_mesh_rpl_num 设置。

  3. 通用配置

    • Mesh 应用默认分配 3000 字节 FTL。

    • 如果根据节点数量计算出的 FTL 大于 3000 字节,需要额外通过 bt_mesh_flash_size 设置 Mesh 应用使用的 FTL 大小。

下表列出了三种典型的 BLE 应用场景和所需的 FTL 大小:

场景

计算

FTL 大小

3 条 BLE 连接, 不使用 Mesh

344 + 216 * 3 = 992

992 字节

4 条 BLE 连接, Mesh device(Mesh 网络中包含 50 个节点)

因为 1752 + 16 * 50 <= 3000, 344 + 216 * 4 + 3000 = 4208

4208 字节

5 条 BLE 连接, Mesh provisioner(可以给 50 个节点配网)

因为 1280 + (20 + 16) * 50 > 3000, 344 + 216 * 5 + 1280 + (20 + 16) * 50 = 4504

4504 字节

备注

打开 BT 时会自动使能 FTL,请参考 BT 应用文档。

代码转换

FatFS 默认不支持 Unicode 与其他编码之间的转换。

修改 ffconf.h 文件中的宏 FF_CODE_PAGE 可开启代码转换功能,开发者需根据目标代码页编号配置 FF_CODE_PAGE

#define FF_CODE_PAGE  999
/* 用于指定目标系统使用的 OEM 代码页
/  不正确的代码页设置会导致文件打开失败
/   437 - U.S.
/   720 - Arabic
/   737 - Greek
/   771 - KBL
/   775 - Baltic
/   850 - Latin 1
/   852 - Latin 2
/   855 - Cyrillic
/   857 - Turkish
/   860 - Portuguese
/   861 - Icelandic
/   862 - Hebrew
/   863 - Canadian French
/   864 - Arabic
/   865 - Nordic
/   866 - Russian
/   869 - Greek 2
/   932 - Japanese (DBCS)
/   936 - Simplified Chinese (DBCS)
/   949 - Korean (DBCS)
/   950 - Traditional Chinese (DBCS)
/   999 - Realtek defined for code size
/     0 - Include all code pages above and configured by f_setcp()
*/

VFS 加密

对于特殊的存储安全需求,用户可通过配置 VFS 的加解密功能实现数据保护。

该功能需要用户参考 VFS 加解密示例 提前准备加解密函数和密钥。

正确运行示例程序后,测试日志应包含如下关键信息:

[example_vfs_encrypt_thread] fwrite succeeded !!!
[example_vfs_encrypt_thread] fread succeeded !!!
[example_vfs_encrypt_thread] remove file succeeded !!!

备注

当启用 VFS 加密功能时,系统会对明文数据进行填充处理,这将导致额外的存储空间开销。

VFS 二进制文件生成

若需预先将数据存放至 Flash 中,可在 PC 端生成 VFS 二进制文件。生成完成后,需根据 Flash 布局将二进制文件下载至 VFS 区域。

  1. 在生成 LittleFS 二进制文件前,需准备一个包含所需文件的目录。例如:

ls -R test

输出示例:

test:
AUDIO KV

test/AUDIO
audio_test.mp3

test/KV
kv_test.txt

在 Flash 中, AUDIOKV 目录作为 LittleFS 目录, test 则相当于文件系统的根目录。

  1. 通过 vfs.py,使用以下命令生成 LittleFS 二进制文件:

cd {SDK}/tools/image_scripts
python vfs.py -t LITTLEFS -s 4096 -c 32 -dir test -out littlefs.bin

参数说明:

-s:

块大小

-c:

块数量

-dir:

目标目录

-out:

输出二进制文件名

输出示例:

littlefs.bin has been successfully generated.
args:
├─ type: LITTLEFS
├─ block_size: 4096
├─ block_count: 32
├─ image_size: 131072
├─ source_directory: test
└─ output_image: littlefs.bin

备注

  • -s 4096 为 LittleFS 默认配置,用户需根据 littlefs_adapter.c 文件中的 lfs_config 中的 block_size 进行适配。

  • -c 32 应根据 Flash 中的 VFS 中提到的 VFS 区域大小来设置。VFS 区域大小等于块大小乘以块数量。

  1. 下载固件至 Flash 中。

参考 固件下载 将二进制文件下载至 Flash 中。Image Tool 的起始地址应为 Flash 中的 VFS 中提到的 VFS Flash 区域的 StartAddr,结束地址应为 EndAddr + 1

Second Flash 中的 VFS

Second Flash 支持两种扩展方式,对比如下:

类型

data flash

normal external flash

配置选项

VFS Second FlashMemory Arch 中的 Second flash

VFS Second Flash

flash读写性能

是否支持使能PSRAM

spi pin脚修改位置

/

vfs_second_nor_flash.h

备注

暂不支持扩展 Nand Flash。