LittleFS移植实践

  • 前言
  • 相关资料链接
  • 先吐为快
  • 移植的要点
    • 块设备接口
      • 对struct lfs_config的说明
    • read 接口解读
    • prog接口解读
    • erase接口解读
    • 关于动态内存

前言

LittleFS是ARM mbedOS的官方推荐文件系统,具有轻量级、掉电安全的特性。

相关资料链接

  • 开源项目:https://github.com/ARMmbed/littlefs
  • 文档:开源项目中的README.md就是对应的文档

先吐为快

本着不吐不快的原则,先就个人对LittleFS的使用及移植进行单方面的吐槽,不喜请跳过。

  • 文档很有限,讲解得也不太透彻。
  • 读性能很优秀,连续写性能也不错,但随机写性能有点糟糕。
  • 对于SPI-FLASH文件的close和seek有可能会非常慢

移植的要点

  • 对struct lfs_config进行填充
  • 使用lfs_mount挂载

示例如下:

/*** @brief Mount LFS*/
static int my_lfs_mount(void)
{int err = 0;// Check if block device availableif (hal_blk_probe() < 0) {LFS_ERROR("ERROR: %s, %d\r\n", __func__, __LINE__);err = -1;goto ERR_EXIT;}memset(&config, 0, sizeof(config));config.read  = blk_device_read;config.prog  = blk_device_prog;config.erase = blk_device_erase;config.sync  = blk_device_sync;config.read_size   = hal_blk_get_readsize();config.prog_size   = hal_blk_get_progsize();config.block_size  = hal_blk_get_erasesize();config.block_count = hal_blk_get_blockcnt();config.lookahead = ROUND_UP(config.block_count, 32);// 需要使用的内存数量 = lookahead/8;// 因此,此处需要限制最大数量,避免消耗过多内存if (config.lookahead > MAX_LFS_LOOKAHEAD) {config.lookahead = MAX_LFS_LOOKAHEAD;}LFS_PRINTF("block_count -> %d\r\n", config.block_count);LFS_PRINTF("lookahead -> %d\r\n", config.lookahead);memset(&the_lfs, 0, sizeof(the_lfs));err = lfs_mount(&the_lfs, &config);LFS_PRINTF("mount -> %d\r\n", err);ERR_EXIT:return err;
}

块设备接口

实际移植的时候,会发现最核心的就是对块设备的接口封装。
关键是LittleFS对这个部分的说明及注释实际上并不十分详细,这里加以补充说明。

对struct lfs_config的说明

  • context 用于传递信息给块设备,便于块设备驱动进行特定的处理,比如:告诉块设备驱动具体哪个范围用于文件系统。这个内容的数据结构由块设备驱动来定义。
  • read 读块接口,用于从块内读取一个块数据
  • prog 写块接口,用于将一段数据写入到块中,这个块必须是已经被擦除的
  • erase 擦块接口,用于擦除一个块
  • sync 同步,有的块设备有缓存需要进行同步操作才能将缓存里的内容写出
  • read_size 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。
  • prog_size 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是read_size的整数倍,但值太大会带来更多的内存消耗。
  • block_size 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是prog_size的整数倍。
  • block_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
  • lookahead 块分配时的预测深度(分配块时每次步进多少个块),这个数值必须为32的整数倍,如1024表示每次预测1024个block。这个值对于内存消耗影响不大,因为它对应的lookahead_buffer 中使用1bit代表一个block。
  • read_buffer 可选参数,用于静态分配读缓存,这个缓存的大小应该等于read_size
  • prog_buffer 可选参数,用于静态分配写缓存,这个缓存的大小应该等于prog_size
  • lookahead_buffer 可选参数,用于静态分配预测缓存,这个缓存的大小应该等于预测深度lookahead/8,因为每个bit表示一个块。
  • file_buffer 可选参数,用于静态分配的文件缓存,这个缓存的大小必须等于prog_size,如果使能了这个参数,则同一时刻只能打开1个文件。

read 接口解读

int (*read)(const struct lfs_config *c, lfs_block_t block,lfs_off_t off, void *buffer, lfs_size_t size);

参数

  • block 逻辑块编号,从0开始
  • off 块内偏移,lfs在调用read接口时,传入的off值一定能被read_size整除
  • buffer 读出数据的输出缓冲区
  • size 要读出的数据字节数,lfs在调用read接口时,一定不会存在跨越块的情况。

返回值

  • 0 成功
  • <0 错误码

prog接口解读

int (*prog)(const struct lfs_config *c, lfs_block_t block,lfs_off_t off, const void *buffer, lfs_size_t size);

参数

  • block 逻辑块编号,从0开始
  • off 块内偏移,lfs在调用prog接口时,传入的off值一定能被prog_size整除
  • buffer 要写入的数据
  • size 要写入的数据字节数,lfs在调用prog接口时,一定不会存在跨越块的情况。

返回值

  • 0 成功
  • <0 错误码

erase接口解读

int (*erase)(const struct lfs_config *c, lfs_block_t block);

参数

  • block 逻辑块编号,从0开始

返回值

  • 0 成功
  • <0 错误码

关于动态内存

由于嵌入式系统并不一定都支持heap,LittleFS提供了一个编译开关用于不支持heap的系统:

LFS_NO_MALLOC
  • 对于支持HEAP的系统,不需要定义LFS_NO_MALLOC,相关的缓存都是通过malloc来申请的。
  • 对于不支持HEAP的系统,则需要定义LFS_NO_MALLOC,相关的缓存都需要手动指定静态内存空间。

如果系统的HEAP是自己实现的而不是使用标准库的malloc/free实现,则需要自己封装动态内存接口,参考lfs_util.h中的如下代码:

// Allocate memory, only used if buffers are not provided to littlefs
static inline void *lfs_malloc(size_t size) {
#ifndef LFS_NO_MALLOCreturn sys_malloc(size);
#else(void)size;return NULL;
#endif
}// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) {
#ifndef LFS_NO_MALLOCsys_free(p);
#else(void)p;
#endif
}

对于不支持HEAP的系统,除了需要定义LFS_NO_MALLOC外,还必须在lfs_mount前将lfs_config参数中的read_buffer/prog_buffer/lookahead_buffer/file_buffer设置为静态内存。并且存在只能同时打开一个文件的限制(单实例)。

若要支持同时打开多个文件,则动态内存(HEAP)是必须的。

LittleFS移植实践相关推荐

  1. Windows下程序向Linux下移植实践

    一.问题的提出 在程序员中有这样一个说法,若一个程序不能移植到Linux下,那这个程序将看不到未来. 由于Linux操作系统源码公开是的,开发库等辅助工具都是源码公开的,这样就减少了程序的不可预知性, ...

  2. Littlefs移植,FLASH用的是W25Q32

    编写SPI FALSH的读写擦除函数 /** * @brief W25Qxx 擦除整个扇区* @retval uint32_t First_Addr : 第几块*/ int32_t W25Qxx_SP ...

  3. linux启动程序镜像构建_启动人员分析功能3个构建块

    linux启动程序镜像构建 A solid foundation to building a scalable People Analytics function. You've got to sta ...

  4. uboot移植新手入门实践

    版权声明:bug实验室原创 https://blog.csdn.net/weixin_43349284/article/details/82958451 u-boot移植新手入门实践视频 前言 视频介 ...

  5. LittleFS - 一个高度完整的嵌入式文件系统

    LittleFS - 一个高度完整的嵌入式文件系统 拥有小巧灵活的文件系统对许多物联网设备至关重要.使用文件系统并将其与正确的存储技术(如外部闪存或SD卡)配对可能很困难.Mbed操作系统使文件系统的 ...

  6. 嵌入式uboot移植之从uboot官方移植

    注:以下内容来自朱老师物联网大讲堂课件 1. 选择合适的官方原版uboot 1.1 官方原版uboot的版本 (1)版本号.刚开始是1.3.4,后来变成2009.08 (2)新版和旧版的差别.uboo ...

  7. 9.触摸屏驱动移植实战

    转自 https://edu.csdn.net/lecturer/505 朱老师物联网大讲堂 <5.linux驱动开发-第9部分-5.9.触摸屏驱动移植实战> 第一部分.章节目录 5.9. ...

  8. Efficient Methods for Natural Language Processing: A Survey自然语言处理有效方法综述

    Efficient Methods for Natural Language Processing: A Survey 关于自然语言处理有效方法的一个综述,近来关于自然语言处理已经取得了非常显著的结果 ...

  9. 【超详细】嵌入式软件学习大纲

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_34981463/article/ ...

最新文章

  1. Java基础之多线程详细分析
  2. exit(0)什么意思php,php – 文件中的exit(1)导致脚本状态码为0
  3. ActiveMQ安装
  4. 【LCT】城市旅行(luogu 4842/金牌导航 LCT-3)
  5. NoClassDefFoundError和ClassNotFoundException之间有什么区别?是由什么导致的?
  6. java的add方法的使用_Java HashSet add()方法与示例
  7. 解决Centos7安装docker源问题
  8. 对Java回调函数的理解
  9. [原创]也学NTFS格式磁盘解析及atapi磁盘读写
  10. 最新仿山楂岛留言源码+公众号吸粉/短视频引流神器
  11. c语言错误c1083是什么意思,fatal error C1083: Cannot open include file: 'stdafx.h': No such file or directo...
  12. Python Counter函数
  13. 树莓派 Raspberry Pi Pico windows7 串口驱动
  14. Android Studio 搭建微信界面
  15. matlab--生成相机校正黑白格网
  16. 养蚕日记软件测试,科学观察养蚕日记(精选3篇)
  17. hiredis初步使用
  18. office2016自定义安装
  19. cordic sinh matlab,利用FPGA进行基本运算及特殊函数定点运算
  20. 黑客爱用的 HOOK 技术大揭秘!

热门文章

  1. 【19考研】计算机/软件等专业调剂信息集合!【完结版】
  2. 开源二维码QR CODE编码/解码(识别)库
  3. python制作京东评论词云图
  4. 为什么 1 字节表示的数值范围是 127 ~ -128
  5. 应用拉氏变换分析线性电路
  6. 调优四剑客的实战演练,福尔摩斯•K带你轻松优化性能
  7. Hadoop3.3.4最新版本安装分布式集群部署
  8. 【yum】常见的yum命令
  9. python barrier_Python多线程Barrier(障碍对象) 雷子
  10. linux mv覆盖目录,linux下利用grep和dd命令恢复被mv命令覆盖的文件内容