片上flash使用文件系统笔记

电子说

1.3w人已加入

描述

由于之前需要使用片上的flash多余的部分来搭建文件系统,但是没有找到使用片上的教程,都是利用片外的flash教程。后来发现能直接使用fal软件包作为flash设备抽象层,向上可以提供文件系统的接口,向下可以驱动片内的flash。这里放上之前使用的笔记。

1.简介

littlefs 在 RT-Thread 上运行的层级关系图如下所示:

DFS

开发者使用的是 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命令。

DFS

2.2 fal具体配置

DFS

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软件包源码到本地工程目录,如下图所示:

DFS

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下面的软件版本后续可能会升级覆盖,我们不在packagesfal-latest目录下直接进行移植修改,而是在packages目录外新建一个文件夹ports专门保存软件包的移植文件信息。

(如果不担心升级覆盖问题,跳过2.5和2.6直接看2.9,再回来看2.7和2.8)
新建与packages软件包同级的移植文件目录ports,将packagesfal-latestsamplesporting目录下的fal_cfg.h文件复制一份到portsfal目录下,将packagesfal-latestSConscript复制一份到portsfal目录下,将packagesSConscript复制一份到ports目录下,复制文件后的目录结构如下图所示:

DFS

(注:图片里多了fal_flash_sfud_port.c文件,是原博客图片,但是我们不需要驱动外置的flash)

2.6 修改sconscript文件

由于portsfal目录及下面的文件名有变化,所以需要修改编译脚本portsfalSConscript,主要是修改文件目录及文件名,修改后的编译脚本如下:(直接覆盖,其实不改这个SConscript文件也没啥问题,强迫症建议覆盖)

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,需要接下来继续更改文件。

.buildkeilObjrt-thread.axf: Error: L6218E: Undefined symbol nor_flash0 (referred from fal_flash.o).
.buildkeilObjrt-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”内添加下面语句

config BSP_USING_ON_CHIP_FLASH
bool "Enable On-Chip Flash"
default n

添加完,进入menuconfig选中该项,并保存退出。

2.8 修改drv_flash_f4.c文件

STM32f427片内Flash驱动,RT-Thread已经在librariesHAL_Drivers drv_flashdrv_flash_f4.c目录下提供了,同时还通过条件宏提供了向FAL注册fal_flash_dev设备表项的代码。但还需我们自己添加一部分代码(个人觉得应该是rtt 官方留白,让我们自定义分区基地址和大小),如下图:

DFS

#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 (641024 )
#define FLASH_SIZE_GRANULARITY_64K (64
1024 )
#define FLASH_SIZE_GRANULARITY_128K (896*1024)

为什么这样添加分区基地址和大小?

先看下面的图

DFS

因此我们现在这样是在使用扇区12到23,又由于STM32F42x的这几个扇区有16K,64K,128K大小的。所以使用fal时,必须把他们看成3个不同的flash设备进行管理,这也是上文所说flash设备表的作用。

2.9 覆盖(或新建)fal_cfg.h

新建一个下面代码块内容的fal_cfg.h文件在packagesfal-latestinc 内

/*

  • 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.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 框架。

DFS

使用默认配置

3.2 配置 littlefs

在 RT-Thread online packages → system packages → Littlefs: A high-integrity embedded file system 中打开 littlefs。

DFS

注意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”分区所在的扇区的大小。

DFS

所以基本确定disk block size应该填128*1024,即131072。

其他配置我觉得默认配置问题不大。比如下面这个注释的描述。

// 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 设备。

DFS

使用pkgs —update更新软件包和scons —target=mdk5

3.4 创建 MTD 设备并挂载文件系统

fal 组件并没有加入自动初始化的代码,所以我们需要在 main 函数中初始化 fal,并使用 fal 提供的 API 来创建一个 MTD 设备。创建 MTD 设备后,就可以将 littlefs 挂载到刚刚生成的 MTD 设备上了。
在 main.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 参考

文件系统语句都是通用的,都是基于POSIX 标准的

3.5.2 问题

需要注意:我这一直有个问题,就是只能使用mkdir 创建2条路径,创建第3条就会出错。如下:

DFS

暂未解决,因为创建二三十个.txt .c也没出错,就先这样吧。

3.5.3 格式化

文档里讲的不清楚。
littlefs的格式化语句

1.程序里面写的

/* 定义要使用的分区名字 /
#define FS_PARTITION_NAME "filesystem"
/
格式化文件系统 */
dfs_mkfs("lfs", FS_PARTITION_NAME);

2.Finsh组件
mkfs -t lfs filesystem

DFS

文档里漏了

3.5.4 官方例程

DFS

4.实验

4.1 分区实验

看从0x0800 0000开始是否影响原程序
(是影响的,所以建议从扇区12开始。当然也可以看.map文件来知道程序所占ROM内存大小,来算从第几个扇区开始是安全的,不过这样就需要自己不按照我上文讲的那样配置设备表和分区表)

DFS

DFS

DFS

再步进一次,擦除所有扇区,即原来的程序也被擦除,导致hard_fault。匿名上位机保持上一张图片的状态

DFS

DFS

4.2 fal指令实验

FAL为便于用户调试,也提供了finsh命令fal,包括fal probe / read / write / erase / bench等命令

DFS

通过使用随机的人为数据给“写入函数”,读取出“读取函数”的值,来验证是否复位后还保存着数据
(是能继续存储的,所以fal确实是操作着掉电不丢失数据的东西)

DFS

DFS

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分