Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
flash
文件系统
笔记
片上flash使用文件系统笔记
发布于 2021-10-03 18:23:49 浏览:5328
订阅该版
[tocm] 由于之前需要使用片上的flash多余的部分来搭建文件系统,但是没有找到使用片上的教程,都是利用片外的flash教程。后来发现能直接使用fal软件包作为flash设备抽象层,向上可以提供文件系统的接口,向下可以驱动片内的flash。这里放上之前使用的笔记。(有些地方为个人猜测,仅供参考) ## 0.目录 ![QQ截图20211003182038.jpg](https://oss-club.rt-thread.org/uploads/20211003/690fb42c2f914d79e477560e156ba350.jpg) ## 1.简介 littlefs 在 RT-Thread 上运行的层级关系图如下所示: ![hierarchical.png](https://oss-club.rt-thread.org/uploads/20211003/61aba39e0119209d1638b9b8b0a63754.png) ![20191022204708916.png](https://oss-club.rt-thread.org/uploads/20211003/668999ba24acc69c04fd5c5ac5bb81fa.png.webp) 开发者使用的是 DFS 框架提供的统一的 POSIX API,DFS 框架会调用 littlefs 的 API,littlefs 会使用 MTD 设备的读写接口,开发者可以使用 RT-Thread 提供的 fal 组件和 SFUD 组件来完成对 FLASH 的读写任务,也可以自己实现 MTD 设备的驱动程序,使 littlefs 可以挂载到更多的存储介质上。 ## 2.FAL MCU Flash移植 ### 2.1 FAL软件包源码获取 打开bsp工程的ENV环境,运行menuconfig命令。 ![image.png](https://oss-club.rt-thread.org/uploads/20211003/dcdd3d9279caafd956782e2c54281872.png) ### 2.2 fal具体配置 ![c05a3f93b199cdf6dbb6be95d5e731fc.png](https://oss-club.rt-thread.org/uploads/20211003/c05a3f93b199cdf6dbb6be95d5e731fc.png) FAL uses SFUD drivers:是用来驱动外置的flash设备,由于我们**只使用内部flash**,所以**不需要选上**。 每个功能的**配置说明**如下: - 开启调试日志输出(默认开启); - 分区表是否在`fal_cfg.h`中定义(默认开启)。**如果关闭此选项**,fal 将会自动去指定 Flash 的指定位置去检索并装载分区表,具体配置详见下面两个选项; - 存放分区表的 Flash 设备; - 分区表的 **结束地址** 位于 Flash 设备上的偏移。fal 将从此地址开始往回进行检索分区表,直接读取到 Flash 顶部。如果不确定分区表具体位置,这里也可以配置为 Flash 的结束地址,fal 将会检索整个 Flash,检索时间可能会增加。 - 启用 FAL 针对 SFUD 的移植文件(默认关闭); - 应输入调用 `rt_sfud_flash_probe` 函数时传入的 FLASH 设备名称(也可以通过 list_device 命令查看 Block Device 的名字获取)。该名称与分区表中的 Flash 名称对应,只有正确设置设备名字,才能完成对 FLASH 的读写操作。 关于分区表,下文还会提及并解释。 ### 2.3 pkgs --update 保存配置退出后,在env环境执行pkgs --update命令,会自动从FAL的github仓库获取FAL软件包源码到本地工程目录,如下图所示: ![77216af43e85a1bbf3ea22d63b6c94d9.png](https://oss-club.rt-thread.org/uploads/20211003/77216af43e85a1bbf3ea22d63b6c94d9.png) ### 2.4 设备表和分区表 FAL组件初始化最重要的是维护两个表:一个是flash设备表;另一个是FAL分区表,两个表的元素分别是前面介绍过的fal_flash_dev结构体地址和fal_partition结构体对象。 - fal_flash_dev设备表主要由底层的Flash驱动(包括MCU片内Flash和SFUD驱动的片外Flash)提供,也即FAL移植的重点就是在Flash驱动层向FAL提供fal_flash_dev设备表,每个flash设备提供设备表中的一个元素。 - fal_partition分区表由用户事先配置在fal_cfg.h头文件中,FAL向上面的用户层提供的分区访问接口函数操作的内存区间就是从fal_partition分区表获取的,最后对分区的访问还是通过Flash驱动提供的接口函数(fal_flash_dev.ops)实现的。 设备表管理不同的flash设备,可以是片内的也可以是片外的。有点像管理不同的硬盘。分区表就是我们电脑上经常说的那个磁盘分区的意思。 ### 2.5 复制文件 考虑到packages下面的软件版本后续可能会升级覆盖,我们不在\packages\fal-latest目录下直接进行移植修改,而是在packages目录外新建一个文件夹ports专门保存软件包的移植文件信息。 **(如果不担心升级覆盖问题,跳过2.5和2.6直接看2.9,再回来看2.7和2.8)** 新建与packages软件包同级的移植文件目录ports,将packages\fal-latest\samples\porting目录下的**fal_cfg.h文件**复制一份到ports\fal目录下,将packages\fal-latest\SConscript复制一份到ports\fal目录下,将packages\SConscript复制一份到ports目录下,复制文件后的目录结构如下图所示: ![20191023200807789.png](https://oss-club.rt-thread.org/uploads/20211003/af35bad453e2fa9469c230094f89f382.png) (注:图片里多了fal_flash_sfud_port.c文件,是原博客图片,但是我们不需要驱动外置的flash) ### 2.6 修改sconscript文件 由于ports\fal目录及下面的文件名有变化,所以需要修改编译脚本ports\fal\SConscript,主要是修改文件目录及文件名,修改后的编译脚本如下:(直接覆盖,其实不改这个SConscript文件也没啥问题,强迫症建议覆盖) ```python from building import * import rtconfig cwd = GetCurrentDir() src = [] CPPPATH = [cwd] LOCAL_CCFLAGS = '' if rtconfig.CROSS_TOOL == 'gcc': LOCAL_CCFLAGS += ' -std=c99' elif rtconfig.CROSS_TOOL == 'keil': LOCAL_CCFLAGS += ' --c99' group = DefineGroup('fal', src, depend = ['PKG_USING_FAL'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS) Return('group') ``` 别忘了执行**scons --target=mdk5**命令,到此直接编译工程会出现error,需要接下来继续更改文件。 ``` .\build\keil\Obj\rt-thread.axf: Error: L6218E: Undefined symbol nor_flash0 (referred from fal_flash.o). .\build\keil\Obj\rt-thread.axf: Error: L6218E: Undefined symbol stm32f2_onchip_flash (referred from fal_flash.o). ``` ### 2.7 修改Kconfig 在原bsp目录的board/Kconfig中的menu "On-chip Peripheral Drivers"内添加下面语句 ```python config BSP_USING_ON_CHIP_FLASH bool "Enable On-Chip Flash" default n ``` 添加完,进入menuconfig选中该项,并保存退出。 ### 2.8 修改drv_flash_f4.c文件 STM32f427片内Flash驱动,RT-Thread已经在libraries\HAL_Drivers \drv_flash\drv_flash_f4.c目录下提供了,同时还通过条件宏提供了向FAL注册fal_flash_dev设备表项的代码。但**还需我们自己添加一部分代码**(个人觉得应该是rtt 官方留白,让我们自定义分区基地址和大小),如下图: ![465b4e0aa432e69e9fb5124731e3b165.png.webp](https://oss-club.rt-thread.org/uploads/20211003/465b4e0aa432e69e9fb5124731e3b165.png.webp) ```c #define STM32_FLASH_START_ADRESS_16K ((uint32_t)0x08100000) #define STM32_FLASH_START_ADRESS_64K ((uint32_t)0x08110000) #define STM32_FLASH_START_ADRESS_128K ((uint32_t)0x08120000) #define FLASH_SIZE_GRANULARITY_16K (64*1024 ) #define FLASH_SIZE_GRANULARITY_64K (64*1024 ) #define FLASH_SIZE_GRANULARITY_128K (896*1024) ``` 为什么这样添加分区基地址和大小? 先看下面的图 ![f23368dd8ca4b24829329f1c0ef45ed0.png.webp](https://oss-club.rt-thread.org/uploads/20211003/f23368dd8ca4b24829329f1c0ef45ed0.png.webp) 因此我们现在这样是在使用扇区12到23,又由于STM32F42x的这几个扇区有16K,64K,128K大小的。所以使用fal时,必须把他们看成3个不同的flash设备进行管理,这也是上文所说flash设备表的作用。 ### 2.9 覆盖(或新建)fal_cfg.h 新建一个下面代码块内容的fal_cfg.h文件在\packages\fal-latest\inc 内 ```c /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-05-17 armink the first version */ #ifndef _FAL_CFG_H_ #define _FAL_CFG_H_ #include
#include
/* ===================== Flash device Configuration ========================= */ extern const struct fal_flash_dev stm32_onchip_flash_16k ; extern const struct fal_flash_dev stm32_onchip_flash_64k ; extern const struct fal_flash_dev stm32_onchip_flash_128k; /* flash device table */ #define FAL_FLASH_DEV_TABLE \ { \ &stm32_onchip_flash_16k, \ &stm32_onchip_flash_64k, \ &stm32_onchip_flash_128k, \ } /* ====================== Partition Configuration ========================== */ #ifdef FAL_PART_HAS_TABLE_CFG /* partition table */ #define FAL_PART_TABLE \ { \ {FAL_PART_MAGIC_WORD, "bl", "onchip_flash_16k" , 0, 64 * 1024, 0}, \ {FAL_PART_MAGIC_WORD, "param", "onchip_flash_64k" , 0, 64 * 1024, 0}, \ {FAL_PART_MAGIC_WORD, "app", "onchip_flash_128k", 0, 128* 1024, 0}, \ {FAL_PART_MAGIC_WORD, "filesystem", "onchip_flash_128k", 128 * 1024, 768* 1024, 0}, \ } #endif /* FAL_PART_HAS_TABLE_CFG */ #endif /* _FAL_CFG_H_ */ ``` 这段代码的意思是使用flash设备stm32_onchip_flash_16k,stm32_onchip_flash_64k,stm32_onchip_flash_128k 创建四个分区,分别名为bl,param,app,filesystem(名字都是随便取的)。后两个分区是分别瓜分了onchip_flash_128k设备内存。 **关于2.8和2.9的一些原理,可以看链接 (**[**FAL:Flash 抽象层**](https://github.com/RT-Thread-packages/fal/blob/master/README_ZH.md#falflash-%E6%8A%BD%E8%B1%A1%E5%B1%82)**)** ** ### 2.x FAL使用示例 **见**博客** **1.4 FAL使用示例 **或者**** **FAL:Flash 抽象层的 3、Finsh/MSH 测试命令 我的部分操作见 4.2 fal指令实验 到此已经移植完fal了 ## 3.搭载 **littlefs 文件系统** littlefs 是 ARM 官方推出的,专为嵌入式系统设计的文件系统,相比传统的文件系统,littlefs 具有以下优点: - 自带**擦写均衡** - 支持掉电保护 - 占用的 RAM/ROM 少 littlefs 自带的擦写均衡和掉电保护使开发者可以放心的将文件系统挂载到 nor flash 上。 ### 3.1 使能DFS框架 打开 env,输入 menuconfig,在 `RT-Thread Components → Device virtual file system` 中打开 DFS 框架。 ![1574ea031e2c6fa654916e9a4a4e85f8.png](https://oss-club.rt-thread.org/uploads/20211003/1574ea031e2c6fa654916e9a4a4e85f8.png) 使用默认配置 ### 3.2 配置 littlefs 在 `RT-Thread online packages → system packages → Littlefs: A high-integrity embedded file system` 中打开 littlefs。 ![1576002a8cb6f82d51b23e6389341389.png](https://oss-club.rt-thread.org/uploads/20211003/1576002a8cb6f82d51b23e6389341389.png) 注意lfs enable wear leveling要改成100,这项意思是 lfs启用损耗均衡 #### 3.2.1 猜测 代码中对于disk block size的注释 ``` // Size of an erasable block. This does not impact ram consumption and // may be larger than the physical erase size. However, non-inlined files // take up at minimum one block. Must be a multiple of the read // and program sizes. Google 翻译 //可擦除块的大小。 这不会影响ram的消耗,并且 //可能大于物理擦除大小。 但是,非内联文件 //至少占用一个街区。 必须是读取的倍数 //和程序大小。 ``` 结合程序调试中mtd_nor->block_size值为0x0002 0000。即128KB,又是"filesystem"分区所在的扇区的大小。 ![05a33d4e513e2cfaea81d3f137465fd2.png.webp](https://oss-club.rt-thread.org/uploads/20211003/05a33d4e513e2cfaea81d3f137465fd2.png.webp) 所以基本确定disk block size应该填128*1024,即131072。 其他配置我觉得默认配置问题不大。比如下面这个注释的描述。 ```c // Minimum size of a block read. All read operations will be a // multiple of this value. lfs_size_t read_size; ``` ### 3.3 使能 MTD 设备 在 `RT-Thread Components → Device Drivers` 中使能 MTD 设备。 ![a46f404c39fd3608994d48f7481ccfd7.png.webp](https://oss-club.rt-thread.org/uploads/20211003/a46f404c39fd3608994d48f7481ccfd7.png.webp) 使用pkgs --update更新软件包和scons --target=mdk5 ### 3.4 创建 MTD 设备并挂载文件系统 fal 组件并没有加入自动初始化的代码,所以我们需要在 main 函数中初始化 fal,并使用 fal 提供的 API 来创建一个 MTD 设备。创建 MTD 设备后,就可以将 littlefs 挂载到刚刚生成的 MTD 设备上了。 在 main.c 文件中添加(覆盖)的代码如下所示: ```c /* 添加 fal 头文件 */ #include
/* 添加文件系统头文件 */ #include
/* 添加 DEBUG 头文件 */ #define DBG_SECTION_NAME "main" #define DBG_LEVEL DBG_INFO #include
/* 定义要使用的分区名字 */ #define FS_PARTITION_NAME "filesystem" int main(void) { struct rt_device *mtd_dev = RT_NULL; /* 初始化 fal */ fal_init(); /* 生成 mtd 设备 */ mtd_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME); if (!mtd_dev) { LOG_E("Can't create a mtd device on '%s' partition.", FS_PARTITION_NAME); } else { /* 挂载 littlefs */ if (dfs_mount(FS_PARTITION_NAME, "/", "lfs", 0, 0) == 0) { LOG_I("Filesystem initialized!"); } else { /* 格式化文件系统 */ dfs_mkfs("lfs", FS_PARTITION_NAME); /* 挂载 littlefs */ if (dfs_mount("filesystem", "/", "lfs", 0, 0) == 0) { LOG_I("Filesystem initialized!"); } else { LOG_E("Failed to initialize filesystem!"); } } } while (1) { rt_thread_mdelay(100); } } ``` 注意这里使用了一个分区"filesystem"。所以上面创建分区必须也有名为"filesystem"的分区。 ### 3.5 使用littlefs 文件系统 #### 3.5.1 参考 链接《[在 STM32F429 上应用文件系统](https://www.rt-thread.org/document/site/application-note/components/dfs/an0012-dfs/)》,《[虚拟文件系统](https://www.rt-thread.org/document/site/programming-manual/filesystem/filesystem/)》 文档后面的指令和讲解 文件系统语句都是通用的,都是基于POSIX 标准的 #### 3.5.2 问题 需要注意:我这一直有个问题,就是只能使用mkdir 创建2条路径,创建第3条就会出错。如下: ![8a7ae54b9f73a08a1c3295747baed188.png.webp](https://oss-club.rt-thread.org/uploads/20211003/8a7ae54b9f73a08a1c3295747baed188.png.webp) 暂未解决,因为创建二三十个.txt .c也没出错,就先这样吧。 知道的怎么回事的,欢迎在我的提问(链接)【[使用片上flash的 littlefs 无法创建多个目录](https://club.rt-thread.org/ask/question/430018.html) 】中解答 #### 3.5.3 格式化 文档里讲的不清楚。 littlefs的格式化语句: **1.程序里面写的** ```c /* 定义要使用的分区名字 */ #define FS_PARTITION_NAME "filesystem" /* 格式化文件系统 */ dfs_mkfs("lfs", FS_PARTITION_NAME); ``` **2.Finsh组件** **mkfs -t lfs filesystem** ![image.png](https://oss-club.rt-thread.org/uploads/20211003/0c03d861ffb99639f4b6b841ad0dec34.png.webp) 文档里漏了 #### 3.5.4 官方例程 ![1029add3f17dd6de946d3bdac7025219.png](https://oss-club.rt-thread.org/uploads/20211003/1029add3f17dd6de946d3bdac7025219.png) ![878a284293067ae36948de2dc1ee8574.png.webp](https://oss-club.rt-thread.org/uploads/20211003/878a284293067ae36948de2dc1ee8574.png.webp) 里面是一些通过程序来实现文件系统的一些功能的例程。对于自己运用函数和文件操作的理解都挺有帮助的。 参考 [filesystem samples package](https://github.com/RT-Thread-packages/filesystem-sample/blob/master/README_ZH.md) ## 4.实验 ### 4.1 分区实验 看从0x0800 0000开始是否影响原程序 (是影响的,所以建议从扇区12开始。当然也可以看.map文件来知道程序所占ROM内存大小,来算从第几个扇区开始是安全的,不过这样就需要自己不按照我上文讲的那样**配置设备表和分区表**) ## ![f4f8ef085bc0763e71e355faf5b124bf.png.webp](https://oss-club.rt-thread.org/uploads/20211003/f4f8ef085bc0763e71e355faf5b124bf.png.webp) ![999ba654a32b929fbd312b13e572d2e6.png.webp](https://oss-club.rt-thread.org/uploads/20211003/999ba654a32b929fbd312b13e572d2e6.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20211003/8a976c5cbca3ea43168ac7ec09c0a66f.png.webp) ![8183881e1d263f5398259ea0e63d2a37.png.webp](https://oss-club.rt-thread.org/uploads/20211003/8183881e1d263f5398259ea0e63d2a37.png.webp) ![7a9bbcd0231a41298236b8967b94c49e.png.webp](https://oss-club.rt-thread.org/uploads/20211003/7a9bbcd0231a41298236b8967b94c49e.png.webp) ![b57e224e2d3d51f6483a8b04880a4229.png.webp](https://oss-club.rt-thread.org/uploads/20211003/b57e224e2d3d51f6483a8b04880a4229.png.webp) 再步进一次,擦除所有扇区,即原来的程序也被擦除,导致hard_fault。匿名上位机保持上一张图片的状态 ![8c1a6612d19e163d0f5eba82a1b8dbae.png.webp](https://oss-club.rt-thread.org/uploads/20211003/8c1a6612d19e163d0f5eba82a1b8dbae.png.webp) 换成 ![54d34e2791a302ac0ca70fd637d05bc7.png.webp](https://oss-club.rt-thread.org/uploads/20211003/54d34e2791a302ac0ca70fd637d05bc7.png.webp) 就没问题 ![6cbe62dc01fd27d00c96bd630b8c2886.png.webp](https://oss-club.rt-thread.org/uploads/20211003/6cbe62dc01fd27d00c96bd630b8c2886.png.webp) ### 4.2 fal指令实验 FAL为便于用户调试,也提供了finsh命令fal,包括fal probe / read / write / erase / bench等命令 ![9b3a4c41e1cfa696c005b07a82b8d0f9.png.webp](https://oss-club.rt-thread.org/uploads/20211003/9b3a4c41e1cfa696c005b07a82b8d0f9.png.webp) 通过使用随机的人为数据给“写入函数”,读取出“读取函数”的值,来验证是否复位后还保存着数据 (是能继续存储的,所以fal确实是操作着掉电不丢失数据的东西) ![436a8eff6dae4037c04e4ebc046e4d75.png.webp](https://oss-club.rt-thread.org/uploads/20211003/436a8eff6dae4037c04e4ebc046e4d75.png.webp) ![bd541c1ff3b962c51862aefd136d8b11.png.webp](https://oss-club.rt-thread.org/uploads/20211003/bd541c1ff3b962c51862aefd136d8b11.png.webp) ## 5.参考 - [https://github.com/RT-Thread-packages/fal/blob/master/README_ZH.md](https://github.com/RT-Thread-packages/fal/blob/master/README_ZH.md) - [https://github.com/RT-Thread-packages/filesystem-sample/blob/master/README_ZH.md](https://github.com/RT-Thread-packages/filesystem-sample/blob/master/README_ZH.md) - [https://www.rt-thread.org/document/site/application-note/components/dfs/an0027-littlefs/#littlefs_1](https://www.rt-thread.org/document/site/application-note/components/dfs/an0027-littlefs/#littlefs_1) - [https://blog.csdn.net/m0_37621078/article/details/102689903](https://blog.csdn.net/m0_37621078/article/details/102689903) - [https://www.rt-thread.org/document/site/application-note/components/dfs/an0012-dfs/](https://www.rt-thread.org/document/site/application-note/components/dfs/an0012-dfs/) - [https://www.rt-thread.org/document/site/programming-manual/filesystem/filesystem/](https://www.rt-thread.org/document/site/programming-manual/filesystem/filesystem/)
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
小号的高速
这家伙很懒,什么也没写!
文章
1
回答
0
被采纳
0
关注TA
发私信
相关文章
1
【文件系统】目录查询
2
文件系统Posix 接口 的close API疑问
3
dfs_mount挂载文件系统路径的路径必须为‘/’才能成功
4
SD卡连续读写文件报错
5
文件系统挂载断言机制
6
文件系统是否支持挂载NFS网络文件系统
7
文件系统挂载失败!!!
8
dfs_filesystem_lookup() 返回NULL
9
webnet 是否可以做全动态网页,使用内存池来加快速度
10
“文件系统装在表”报错
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
1
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部