我的编程空间,编程开发者的网络收藏夹
学习永远不晚

初学littlefs文件系统

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

初学littlefs文件系统

概述

一个为微控制器设计的小故障安全文件系统。

  • 掉电恢复能力: 设计用于处理随机电源故障。所有文件操作都有很强的写时拷贝保证,如果断电,文件系统将恢复到上一次已知的良好状态。

  • 动态磨损均衡: 设计考虑到闪存,并提供动态块磨损均衡。此外,littlefs可以检测坏块并在它们周围工作。

  • 有限RAM/ROM: 被设计为使用少量内存。RAM的使用是严格限制的,这意味着RAM的使用不会随着文件系统的增长而改变。文件系统不包含无界递归,动态内存仅限于可静态提供的可配置缓冲区。

在lfs.h的评论中可以找到详细的文档(或者至少是目前可用的尽可能多的细节)。 littlefs采用了一种配置结构,定义了文件系统的运行方式。配置结构为文件系统提供了块设备操作和维度、可调整的参数(用于在性能上权衡内存使用情况)以及可选的静态缓冲区(如果用户希望避免动态内存)。 littlefs的状态存储在lfs\t类型中,由用户分配,允许同时使用多个文件系统。使用lfs\u t和configuration struct,用户可以格式化块设备或挂载文件系统。 挂载后,littlefs提供了一整套类似POSIX的文件和目录功能,但文件系统结构的分配必须由用户提供。 所有POSIX操作,比如remove和rename,都是原子的,即使在断电的情况下也是如此。此外,在对文件调用sync或close之前,文件更新实际上不会提交到文件系统。

littlefs文件系统下载地址

Tags · littlefs-project/littlefs · GitHub

下载最新的即可。

源码下载下来后,只需要其中的4个文件:lfs.c、lfs.h、lfs_util.c、lfs_util.h,其他文件都是用于测试的Demo例程,调试过程中需要参考的话可以了解一下。

移植步骤

将lfs.c、lfs.h、lfs_util.c、lfs_util.h这4个文件放到一个新建的文件夹,并将其添加到工程中;sos_lfs.c这个文件是我对lfs.c接口二次封装生成的文件,这个文件根据你自己喜好命名,适配即可。

2、适配lfs_util.h

lfs_util.h中需要修改申请内存的方式,如果你代码中对malloc有修改过,就需要修改为你动态申请内存的方式

原版

我的系统移植了FreeRTOS系统,动态申请内存是在FreeRTOS的总内存中申请,所以我需要修改此内存申请的方式

 3、适配lfs_config结构体的内容

lfs_config结构体
结构体成员变量    说明
void *context用于给底层块设备传参,比如:要写入的文件信息、位置、大小、是否有坏块等。该参数的数据结构由底层块设备驱动来定义。如果不需要传参的话可以不赋值
int (*read)块设备读取函数指针
int (*prog)块设备写入函数指针,写入前必须保证该写入块已经被擦除过
int (*erase)块设备擦除函数指针
int (*sync)块设备同步函数指针,若块设备不需要同步操作,可以直接返回成功
lfs_size_t read_size最小读取字节数,所有的读取操作字节数必须是它的整数倍
lfs_size_t prog_size最小写入字节数,所有的写入操作字节数必须是它的整数倍
lfs_size_t block_size擦除块操作的字节数,该选项不影响 RAM 消耗,可以比物理擦除尺寸大,但是每个文件至少占用一个块,必须是读取和写入操作字节数的整数倍
lfs_size_t block_count设备上可擦除块的数量,block_size x block_count = 块设备容量
int32_t block_cycleslittlefs 系统删除元数据日志并将元数据移动到另一个块之前的擦除周期数。建议取值范围为 100 ~ 1000,较大数值有较好的性能但是会导致磨损分布不一致,若取值 -1 的话,即为禁用块级磨损均衡
lfs_size_t cache_size块缓存大小,每个缓存都会在 RAM 中缓冲一部分块数据,littlefs 系统需要一个读取缓存、一个写入缓存,每个文件还需要一个额外的缓存。更大的缓存可以通过存储更多的数据并降低磁盘访问数量等手段来提高性能
lfs_size_t lookahead_size先行缓冲大小,更大的先行缓冲可以提高分配操作中可被发现的块数量。即分配块时每次分配多少个块,16就表示每次分配16个块。先行缓冲以 bit 位形式来存储,故 RAM 中的一个字节对应8个块。该值必须是8的整数倍
int (*lock)块设备加锁函数指针,需定义 LFS_THREADSAFE 宏才可用,若不需要多线程操作可不赋值
int (*unlock)块设备解锁函数指针,需定义 LFS_THREADSAFE 宏才可用,若不需要多线程操作可不赋值
void *read_buffer可选参数。读取静态缓冲区指针。若目标MCU不支持动态分配堆内存的话,就需要定义这个参数,用于在栈内分配静态变量
void *prog_buffer可选参数。写入静态缓冲区指针。若目标MCU不支持动态分配堆内存的话,就需要定义这个参数,用于在栈内分配静态变量
void *lookahead_buffer可选参数。先行分配静态缓冲区指针,需要32bit对齐。若目标MCU不支持动态分配堆内存的话,就需要定义这个参数,用于在栈内分配静态变量

下面是我的lfs_config配置表

3.1、block_count我用了宏定义,这个大小根据你分配内存大小给定,我分配的littlefs的内存大小是2600K,所以INTERNALFLASH_LFS_MAXSIZE是650,其中cache_size的大小和block_size、read_size的大小成比例,否则运行lfs的时候就会出现错误的问题

3.2、在单线程的情况下lock和unlock可以不适配,多线程的时候,建议适配,因为会出现抢占资源,导致不必要的错误。

3.3、.read、.prog、.erase 、.sync  、.lock 、.unlock 适配

注:因为flash中有存放了你的程序,不是整块芯片都用作littlefs文件系统,所以INTERNALFLASH_STARTADDR是我内存已经规划好相应的地址,需要偏移了指定大小的地址之后才开始被littlefs使用的;

.read

 .prog

.erase

 .sync

.lock

 .unlock

4、测试接口是否适配OK?

1、lfs初始化

2、测试函数接口

void lfs_test(void){    int err;    printf("*****************内部文件系统测试*********************\r\n");// mount the filesystemerr = lfs_mount(&lfs_sosInternalFlash, &intCfg);    // reformat if we can't mount the filesystem// this should only happen on the first bootif(err){        printf("err2=%d\r\n", err);    lfs_format(&lfs_sosInternalFlash, &intCfg);    lfs_mount(&lfs_sosInternalFlash, &intCfg);    }    // read current count    uint32_t boot_count1 = 0;    lfs_file_open(&lfs_sosInternalFlash, &lfs_file_internalFlash, "boot_count1", LFS_O_RDWR | LFS_O_CREAT);    lfs_file_read(&lfs_sosInternalFlash, &lfs_file_internalFlash, &boot_count1, sizeof(boot_count1));    printf("ID:%d\r\n", lfs_file_internalFlash.id);    // update boot count    boot_count1 += 1;    lfs_file_rewind(&lfs_sosInternalFlash, &lfs_file_internalFlash);    lfs_file_write(&lfs_sosInternalFlash, &lfs_file_internalFlash, &boot_count1, sizeof(boot_count1));    // remember the storage is not updated until the file is closed successfully    lfs_file_close(&lfs_sosInternalFlash, &lfs_file_internalFlash);    uint32_t txt1 = 0;    lfs_file_open(&lfs_sosInternalFlash, &lfs_file_internalFlash, "txt1", LFS_O_RDWR | LFS_O_CREAT);    lfs_file_read(&lfs_sosInternalFlash, &lfs_file_internalFlash, &txt1, sizeof(txt1));    printf("ID:%d\r\n", lfs_file_internalFlash.id);    // update boot count    txt1 += 1;    lfs_file_rewind(&lfs_sosInternalFlash, &lfs_file_internalFlash);    lfs_file_write(&lfs_sosInternalFlash, &lfs_file_internalFlash, &txt1, sizeof(txt1));    // remember the storage is not updated until the file is closed successfully    lfs_file_close(&lfs_sosInternalFlash, &lfs_file_internalFlash);    // release any resources we were using    lfs_unmount(&lfs_sosInternalFlash);    // print the boot count    printf("boot_count1: %d\r\n", boot_count1);    printf("txt1: %d\r\n", txt1);    printf("\r\n");    printf("*****************外部文件系统测试*********************\r\n");    // mount the filesystem    err = lfs_mount(&lfs_sosExternalFlash, &extCfg);// reformat if we can't mount the filesystem// this should only happen on the first bootif(err){        printf("err1=%d\r\n", err);        lfs_format(&lfs_sosExternalFlash, &extCfg);lfs_mount(&lfs_sosExternalFlash, &extCfg);}// read current countuint32_t boot_count2 = 0;lfs_file_open(&lfs_sosExternalFlash, &lfs_file_externalFlash, "boot_count2", LFS_O_RDWR | LFS_O_CREAT);lfs_file_read(&lfs_sosExternalFlash, &lfs_file_externalFlash, &boot_count2, sizeof(boot_count2));    printf("ID:%d\r\n", lfs_file_externalFlash.id);// update boot countboot_count2 += 1;lfs_file_rewind(&lfs_sosExternalFlash, &lfs_file_externalFlash);lfs_file_write(&lfs_sosExternalFlash, &lfs_file_externalFlash, &boot_count2, sizeof(boot_count2));// remember the storage is not updated until the file is closed successfullylfs_file_close(&lfs_sosExternalFlash, &lfs_file_externalFlash);        uint32_t txt2 = 0;    lfs_file_open(&lfs_sosExternalFlash, &lfs_file_externalFlash, "txt2", LFS_O_RDWR | LFS_O_CREAT);    lfs_file_read(&lfs_sosExternalFlash, &lfs_file_externalFlash, &txt2, sizeof(txt2));    printf("ID:%d\r\n", lfs_file_externalFlash.id);    // update boot count    txt2 += 1;    lfs_file_rewind(&lfs_sosExternalFlash, &lfs_file_externalFlash);    lfs_file_write(&lfs_sosExternalFlash, &lfs_file_externalFlash, &txt2, sizeof(txt2));    // remember the storage is not updated until the file is closed successfully    lfs_file_close(&lfs_sosExternalFlash, &lfs_file_externalFlash);// release any resources we were usinglfs_unmount(&lfs_sosExternalFlash);// print the boot countprintf("boot_count2: %d\r\n", boot_count2);    printf("txt2: %d\r\n", txt2);    printf("\r\n");}

 测试通过,读写和擦除都正常,littlefs算移植完成

5、注意事项

1、在创建文件的时候,如果该文件已经创建过了,你再次创建同样的名字,没有加LFS_O_EXCL属性,文件同样会创建成功,但是不会返回文件已存在的错误码,创建的次数越多,后面文件系统内存会出现泄漏,最后导致写入文件都会报内存不足的问题,需要注意

2、内外文件系统需要自己注意函数的调用,不要混乱使用。

3、lfs_config配置表看自己的需要的大小适配,不过如果配置不对,很容易报错,推荐用的我的配置表。

4、挂载文件系统时候,如果没有实现read、erase和write的操作,会出现错误码:-84;

5、没有挂载成功,调用卸载函数会导致代码卡死。

6、总结

这篇文件断断续续写的,有不足的地方希望一起探讨,后续有新的发现和注意事项,我会持续更新。

来源地址:https://blog.csdn.net/weixin_45270358/article/details/126306342

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

初学littlefs文件系统

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

操作系统文件系统缓存,从初学者到专家的进阶指南

操作系统文件系统缓存是操作系统中用于临时存储文件数据的内存区域。它可以提高文件系统性能,减少磁盘I/O操作。文件系统缓存通常由两部分组成:页面缓存和元数据缓存。页面缓存用于存储文件数据,元数据缓存用于存储文件系统元数据,如文件名称、大小、修改时间等。
操作系统文件系统缓存,从初学者到专家的进阶指南
2024-02-27

初学linux系统管理3

在多台linux主机上执行相同的命令By tianjing on 2011 年 06 月 05 日有时候我们需要在若干台linux主机上执行相同的命令,或者安装相同的软件,可以使用如下两种方法:实验环境,有9台RHEL5.5_x64的主机,
2023-01-31

Ubuntu配置文件系统如何初始化

这篇文章主要介绍Ubuntu配置文件系统如何初始化,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Ubuntu 配置文件系统初始化/etc/timezone 时区/etc/inetd.conf 超级进程Ubuntu 配
2023-06-17

JPA persistence.xml 文件初学者指南

JPA (Java Persistence API) 是Java中用于对象关系映射(ORM)的规范。在使用JPA时,需要使用一个名为persistence.xml的配置文件来配置JPA的相关参数和实体映射。以下是一个persistence.
2023-09-15

Ubuntu如何配置文件系统环境初始化

小编给大家分享一下Ubuntu如何配置文件系统环境初始化,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Ubuntu配置文件系统初始化/etc/timezone 时区 /etc/inetd.conf 超级进程Ubuntu配
2023-06-16

适合Linux系统初学的redhat系列有哪些

本篇文章给大家分享的是有关适合Linux系统初学的redhat系列有哪些,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。  Linux系统作为非常受欢迎的技术,其发行版本也是非常
2023-06-05

初中学历能报名系统分析师吗?

  系统分析师属于计算机软考高级的一种,报考系统分析师不需要学历的要求,也就是说,不管是初中学历,还是小学学历,都是可以报考的。只是,报考计算机软考,一次只能报考一个级别。  初中学历能报名系统分析师。系统分析师报考对于学历、年龄、工作年限以及专业都是没有限制的,只需要达到相应的技术水平就可以报考。需要注意的是,报考计
初中学历能报名系统分析师吗?
2024-04-19

初中学历能报名系统分析师吗

  可以。系统分析师报名不设学历与资历条件、年龄以及专业等要求限制,只要达到相应的技术水平就可以报考,考生可根据自己的技术水平选择软考合适的级别与资格进行报考。  软考系统分析师报名没有学历要求,所以初中学历也可以报考。根据《计算机技术与软件专业技术资格考试暂行规定》第八条相关规定:凡遵守中华人民共和国宪法和各项法律,
初中学历能报名系统分析师吗
2024-04-18

Python之文件及文件系统

open() 方法:Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。注意:使用 open() 方法一定要保证关闭文件对象,即调用 cl
2023-01-31

编程热搜

目录