文章目录
前言
编写目的
本文档旨在为开发者介绍Littlef’s文件系统相关配置使用指南。通过本文档,开发者可以了解系统支持的文件系统类型、文件系统的挂载与使用方法、文件操作接口以及文件系统相关的配置选项,帮助开发者在嵌入式环境中高效、安全地使用文件系统功能,实现数据的持久化存储和管理。
术语和缩写词
术语和缩写词 | 解释 |
---|---|
文件系统 | 用于组织和存储数据的方法,管理文件的创建、读取、写入、删除等操作,提供数据持久化存储能力 |
littlefs | 为闪存设计的轻量级文件系统,具有掉电保护和磨损均衡功能,适用于资源受限的嵌入式设备 |
fatfs | 一种广泛使用的文件系统格式,兼容性好,支持长文件名,适用于SD卡、U盘等可移动存储设备 |
方案选择
Zephyr 操作系统支持 fatfs 和 littlefs,因为 SPINAND 存在坏块,而 littlefs 支持坏块管理,所以选择 littlefs 作为外部NAND-Flash文件系统。
一、Littlefs介绍
二、Littlefs搭建步骤
Littlefs系统原函数文件路径:zephyr/subsys/fs/littlefs_fs.c
该文件作用说明:
- LittleFS 文件系统驱动原函数实现
- 双存储后端支持
- 设备树驱动的自动挂载(若设备树启动:autonount属性)
- 内存管理和线程安全
- 通过 SYS_INIT 在系统启动时自动初始化(注册文件系统框架)
1.设备树构建
/ {
fstab {
compatible = "zephyr,fstab";
lfs1: lfs1 {
compatible = "zephyr,fstab,littlefs"; //标识符
read-size = <1>; // 数据块读取的最小大小,所有读取都将是此值的倍数
prog-size = <16>; // 数据块写入的最小大小,所有写入都将是此值的倍数
cache-size = <256>; //缓存的大小,必须是 flash page size 的倍数
lookahead-size = <32>; //lookahead 缓冲区大小,必须是8的倍数
block-cycles = <512>; //用于动态磨损均衡,将数据移动到另一个块之前的擦除次数
partition = <&lfs1_partition>; //挂载分区
mount-point = "/lfs1"; //挂载点
automount; //启用自动挂载(自动:littlefs_fs.c挂载。手动:fs_mount函数挂载)
};
};
};
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
/* Use second half of flash for the filesystem. */
lfs1_partition: partition@100000 {
label = "storage";
reg = <0x100000 DT_SIZE_K(1024)>;
};
};
};
易错点:若重复挂载会返回错误
可使用**fs_statvfs()**检查后再挂载。
2.自动挂载流程(二选一)
2.1设备树启用自动挂载
fstab {
compatible = "zephyr,fstab";
lfs1: lfs1 {
.......
automount; // 启用自动挂载
.......
};
};
2.2 在 littlefs_fs.c 中,设备树宏会被展开
//匹配设备树:
#define DT_DRV_COMPAT zephyr_fstab_littlefs
// DT_INST_FOREACH_STATUS_OKAY(DEFINE_FS) 展开为:
#define DEFINE_FS(inst) \
static struct fs_littlefs fs_data_0 = { \
.cfg = { \
.read_size = 1, \
.prog_size = 16, \
.cache_size = 256, \
.lookahead_size = 32, \
.read_buffer = read_buffer_0, \
.prog_buffer = prog_buffer_0, \
.lookahead_buffer = lookahead_buffer_0, \
}, \
}; \
struct fs_mount_t z_fsmp_lfs1 = { \
.type = FS_LITTLEFS, \
.mnt_point = "/lfs1", \
.fs_data = &fs_data_0, \
.storage_dev = (void *)0, \
.flags = FS_MOUNT_FLAG_AUTOMOUNT, \
};
2.3 模块注册初始化
// 文件系统初始化优先级:CONFIG_FILE_SYSTEM_INIT_PRIORITY
// littlefs_fs.c 中的 SYS_INIT 宏
SYS_INIT(littlefs_init, POST_KERNEL, CONFIG_FILE_SYSTEM_INIT_PRIORITY);
// 系统启动时自动调用 littlefs_init()
2.4 初始化阶段
2.4.1注册Littlefs文件系统到总文件系统
// 注册 LittleFS 文件系统驱动
int rc = fs_register(FS_LITTLEFS, &littlefs_fs);
if (rc != 0) {
LOG_ERR("Failed to register LittleFS driver: %d", rc);
return rc;
}
2.4.2 检查自动挂载标志
if ((mp->flags & FS_MOUNT_FLAG_AUTOMOUNT) != 0) {
// 执行自动挂载
int rc = fs_mount(mp);
if (rc < 0) {
LOG_ERR("Automount %s failed: %d", mp->mnt_point, rc);
} else {
LOG_INF("Automount %s succeeded", mp->mnt_point);
}
}
// 如果没有 automount 标志,直接返回,不执行挂载
2.5 挂载函数调用
int fs_mount(struct fs_mount_t *mp)
{
......
// 检查是否已经挂载
if (mp->fs != NULL) {
return -EBUSY; // 已经挂载
}
// 调用文件系统特定的挂载函数
int rc = fs->mount(mp);
if (rc == 0) {
// 5. 挂载成功,更新挂载点信息
mp->fs = fs;
mp->mountp_len = strlen(mp->mnt_point);
}
.......
}
3.手动挂载流程(二选一)
3.1设备树注释自动挂载
fstab {
compatible = "zephyr,fstab";
lfs1: lfs1 {
.......
//automount; //注释关闭掉
.......
};
};
3.2 外部声明挂载结构
// 在应用程序中声明外部挂载结构
FS_FSTAB_DECLARE_ENTRY(FS_PARTITION_NODE);
// 展开为:extern struct fs_mount_t z_fsmp_lfs1;
3.3 基础方式挂载
#include <zephyr/fs/fs.h>
#include <zephyr/fs/littlefs.h>
void basic_mount_example(void)
{
// 1. 获取挂载结构指针
struct fs_mount_t *mp = &FS_FSTAB_ENTRY(FS_PARTITION_NODE);
// 2. 执行挂载
int rc = fs_mount(mp);
if (rc < 0) {
printk("Mount failed: %d\n", rc);
return;
}
printk("Mount succeeded at %s\n", mp->mnt_point);
}
4. 基础应用
简化版Demo:
/*
* 最简 LittleFS 测试
*/
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/fs/fs.h>
#include <zephyr/fs/littlefs.h>
int main(void)
{
struct fs_file_t file;
char buffer[64];
int res;
printk("Simple LittleFS Test\n");
// 挂载文件系统
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
static struct fs_mount_t lfs_mount = {
.type = FS_LITTLEFS,
.fs_data = &storage,
.storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),
.mnt_point = "/lfs",
};
res = fs_mount(&lfs_mount);
if (res != 0) {
printk("Mount failed: %d\n", res);
return 0;
}
printk("Mounted successfully\n");
// 写入文件
fs_file_t_init(&file);
res = fs_open(&file, "/lfs/hello.txt", FS_O_CREATE | FS_O_WRITE);
if (res == 0) {
fs_write(&file, "Hello LittleFS!", 15);
fs_close(&file);
printk("File written\n");
}
// 读取文件
res = fs_open(&file, "/lfs/hello.txt", FS_O_READ);
if (res == 0) {
res = fs_read(&file, buffer, sizeof(buffer) - 1);
if (res > 0) {
buffer[res] = '\0';
printk("Read: %s\n", buffer);
}
fs_close(&file);
}
// 卸载
fs_unmount(&lfs_mount);
printk("Test completed\n");
return 0;
}
更完善Demo请参考官方Littlefs例程:Littlefs_demo
总结
无论使用自动挂载还是使用手动挂载,Littlefs_Moudle都会在启动阶段进行初始化。手动挂载具有搭配(条件挂载、错误处理、状态检测、性能监控的优势),提供了更大的灵活性和控制力,具体可通过Shell进行测试与体验。