RT-Thread的FAL
分区表组件
1、FAL
介绍
FAL
(Flash Abstraction Layer) Flash 抽象层,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层,对上层统一了 Flash 及 分区操作的 API (框架图如下所示),并具有以下特性:
1.1 FAL
目录
名称 | 说明 |
---|---|
inc | 头文件目录 |
src | 源代码目录 |
samples | 例程目录 |
1.2 FAL API
1.2.1 查找 Flash 设备
const struct fal_flash_dev *fal_flash_device_find(const char *name)
参数 | 描述 |
---|---|
name | Flash 设备名称 |
return | 如果查询成功,将返回 Flash 设备对象,查找失败==> NULL |
1.2.2 查找 Flash 分区
const struct fal_partition *fal_partition_find(const char *name)
参数 | 描述 |
---|---|
name | Flash分区名称 |
return | 如果查询成功,将返回 Flash 分区对象, 查找失败==> NULL |
1.2.3 获取分区表
const struct fal_partition *fal_get_partition_table(size_t *len)
参数 | 描述 |
---|---|
len | 分区表的长度 |
return | 分区表 |
1.2.4 临时设置分区表
FAL
初始化时会自动装载默认分区表。使用该设置将临时修改分区表,重启后会 丢失 该设置
void fal_set_partition_table_temp(struct fal_partition *table, size_t len)
参数 | 描述 |
---|---|
table | 分区表 |
len | 分区表的长度 |
1.2.5 从分区读取数据
int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
参数 | 描述 |
---|---|
part | 分区对象 |
addr | 相对分区的偏移地址 |
buf | 存放待读取数据的缓冲区 |
size | 待读取数据的大小 |
return | 返回实际读取的数据大小 |
1.2.6 从分区写入数据
int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
参数 | 描述 |
---|---|
part | 分区对象 |
addr | 相对分区的偏移地址 |
buf | 存放待写入数据的缓冲区 |
size | 待写入数据的大小 |
return | 返回实际写入的数据大小 |
1.2.7 擦除分区数据
int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
参数 | 描述 |
---|---|
part | 分区对象 |
addr | 相对分区的偏移地址 |
size | 擦除区域的大小 |
return | 返回实际擦除的区域大小 |
1.2.8 擦除整个分区数据
int fal_partition_erase_all(const struct fal_partition *part)
参数 | 描述 |
---|---|
part | 分区对象 |
return | 返回实际擦除的区域大小 |
1.2.9 打印分区表
void fal_show_part_table(void)
1.2.10 创建块设备
该函数可以根据指定的分区名称,创建对应的块设备,以便于在指定的分区上挂载文件系统
struct rt_device *fal_blk_device_create(const char *parition_name)
参数 | 描述 |
---|---|
parition_name | 分区名称 |
return | 创建成功,则返回对应的块设备,失败返回空 |
1.2.11 创建 MTD Nor Flash
设备
该函数可以根据指定的分区名称,创建对应的 MTD Nor Flash 设备,以便于在指定的分区上挂载文件系统
struct rt_device *fal_mtd_nor_device_create(const char *parition_name)
参数 | 描述 |
---|---|
parition_name | 分区名称 |
return | 创建成功,则返回对应的 MTD Nor Flash 设备,失败返回空 |
1.2.12 创建字符设备
该函数可以根据指定的分区名称,创建对应的字符设备,以便于通过 deivice 接口或 devfs 接口操作分区,开启了 POSIX 后,还可以通过 oepn/read/write 函数操作分区。
struct rt_device *fal_char_device_create(const char *parition_name)
参数 | 描述 |
---|---|
parition_name | 分区名称 |
return | 创建成功,则返回对应的字符设备,失败返回空 |
2、使用 定义 FAL
使用 FAL
的基本步骤如下所示:
- 打开
FAL
:从 Env 中打开 fal 软件包并下载到工程。 FAL
移植:定义 flash 设备、定义 flash 设备表、定义 flash 分区表。以下主要对步骤 2 展开讲解。- 调用
fal_init()
初始化该库:移植完成后,可在应用层调用,如在 main 函数中调用。
2.1 定义 flash 设备
在定义 Flash 设备表前,需要先定义 Flash 设备。可以是片内 flash, 也可以是片外基于 SFUD 的 spi flash:
片内 spi flash
: fal_flash_sfud_port.c
片外flash
: fal_flash_stm32f_port.c
- 定义具体的 Flash 设备对象,用户需要根据自己的 Flash 情况分别实现
init
、read
、write
、erase
这些操作函数:
2.1.1 初始化&读写&擦除
-
-
static int init(void)//可选 的初始化操作
-
static int read(long offset, uint8_t *buf, size_t size)//读取操作
-
参数 描述 offset 读取数据的 Flash 偏移地址 buf 存放待读取数据的缓冲区 size 待读取数据的大小 return 返回实际读取的数据大小
-
-
static int write(long offset, const uint8_t *buf, size_t size) //写入操作。
-
参数 描述 offset 写入数据的 Flash 偏移地址 buf 存放待写入数据的缓冲区 size 待写入数据的大小 return 返回实际写入的数据大小
-
-
static int erase(long offset, size_t size) :擦除操作。
-
参数 描述 offset 擦除区域的 Flash 偏移地址 size 擦除区域的大小 return 返回实际擦除的区域大小
-
-
用户需要根据自己的 Flash 情况分别实现这些操作函数。在文件最底部定义了具体的 Flash 设备对象 ,如下示例定义了 stm32f2 片上 flash:stm32f2_onchip_flash
const struct fal_flash_dev stm32f2_onchip_flash =
{
.name = "stm32_onchip",
.addr = 0x08000000,
.len = 1024*1024,
.blk_size = 128*1024,
.ops = {init, read, write, erase},
.write_gran = 8
};
/*
"stm32_onchip":` Flash 设备的名字。
0x08000000: 对 Flash 操作的起始地址。
1024*1024: Flash 的总大小(1MB)。
128*1024: Flash 块/扇区大小(因为 STM32F2 各块大小不均匀,所以擦除粒度为最大块的大小:128K)。
{init, read, write, erase} :Flash 的操作函数。 如果没有 init 初始化过程,第一个操作函数位置可以置空。
8 : 设置写粒度,单位 bit, 0 表示未生效(默认值为 0 ),该成员是 fal 版本大于 0.4.0 的新增成员。各个 flash 写入粒度不尽相同,可通过
*/
该成员进行设置,以下列举几种常见 Flash 写粒度:
nor flash: 1 bit
stm32f4: 8 bit
stm32f1: 32 bit
stm32l4: 64 bit
2.2 定义设备表
Flash 设备表定义在
fal_cfg.h
头文件中,定义分区表前需 新建fal_cfg.h
文件 ,请将该文件统一放在对应 BSP 或工程目录的 port 文件夹下,并将该头文件路径加入到工程
参考 fal_cfg.h
/*
* 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 <rtconfig.h>
#include <board.h>
#define NOR_FLASH_DEV_NAME "norflash0"
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32f2_onchip_flash;
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&stm32f2_onchip_flash, \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "bl", "stm32_onchip", 0, 64*1024, 0}, \
{FAL_PART_MAGIC_WORD, "app", "stm32_onchip", 64*1024, 704*1024, 0}, \
{FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME, 0, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "download", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
eg
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32f2_onchip_flash;
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE
{
&stm32f2_onchip_flash,
&nor_flash0,
}
- Flash 设备表中,有两个 Flash 对象,一个为 STM32F2 的片内 Flash ,一个为片外的 Nor Flash。
2.3 定义flash
分区表
分区表也定义在
fal_cfg.h
头文件中。Flash 分区基于 Flash 设备,每个 Flash 设备又可以有 N 个分区,这些分区的集合就是分区表。在配置分区表前,务必保证已定义好 Flash 设备 及 设备表。
eg
#define NOR_FLASH_DEV_NAME "norflash0"
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "bl", "stm32_onchip", 0, 64*1024, 0}, \
{FAL_PART_MAGIC_WORD, "app", "stm32_onchip", 64*1024, 704*1024, 0}, \
{FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME, 0, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "download", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
分区名 | Flash 设备名 | 偏移地址 | 大小 | 说明 |
---|---|---|---|---|
“bl” | “stm32_onchip” | 0 | 64KB | 引导程序 |
“app” | “stm32_onchip” | 64*1024 | 704KB | 应用程序 |
“easyflash” | “norflash0” | 0 | 1MB | EasyFlash 参数存储 |
“download” | “norflash0” | 1024*1024 | 1MB | OTA 下载区 |
用户需要修改的分区参数包括:分区名称、关联的 Flash 设备名、偏移地址(相对 Flash 设备内部)、大小,需要注意以下几点:
- 分区名保证 不能重复;
- 关联的 Flash 设备 务必已经在 Flash 设备表中定义好 ,并且 名称一致 ,否则会出现无法找到 Flash 设备的错误;
- 分区的起始地址和大小 不能超过 Flash 设备的地址范围 ,否则会导致包初始化错误;
注意:每个分区定义时,除了填写上面介绍的参数属性外,需在前面增加
FAL_PART_MAGIC_WORD
属性,末尾增加0
(目前用于保留功能)
3、MSH测试命令
fal 提供了丰富的测试命令,项目只要在 RT-Thread 上开启 MSH 功能即可。在做一些基于 Flash 的应用开发、调试时,这些命令会非常实用。它可以准确的写入或者读取指定位置的原始 Flash 数据,快速的验证 Flash 驱动的完整性,甚至可以对 Flash 进行性能测试。
在RT-Thread操作系统中,MSH是Finsh shell命令行工具的一部分,它允许用户通过命令行操作完成功能测试。MSH模式是Finsh shell的一种模式,用户可以通过启用特定的宏来使用MSH模式。在MSH模式下,用户可以导出自定义命令,这些命令可以直接在FinSH中执行
- RT-Thread命令行中 msh
命令 | 作用 |
---|---|
fal | 看到完整的命令列表 |
fal probe | 指定待操作的Flash设备或Flash分区 |
fal erase | 擦除数据 |
fal write | 写入数据 |
fal read | 读取数据 |
fal bench | 性能测试 |
3.1完整的命令列表
msh />fal
Usage:
fal probe [dev_name|part_name] - probe flash device or partition by given name
fal read addr size - read 'size' bytes starting at 'addr'
fal write addr data1 ... dataN - write some bytes 'data' starting at 'addr'
fal erase addr size - erase 'size' bytes starting at 'addr'
fal bench <blk_size> - benchmark test with per block size
msh />
3.2 指定待操作的Flash设备/Flash分区
当第一次使用 fal 命令时,直接输入
fal probe
将会显示分区表信息。可以指定待操作的对象为分区表里的某个分区,或者某个 Flash 设备
msh />fal probe
No flash device or partition was probed.
Usage: fal probe [dev_name|part_name] - probe flash device or partition by given name.
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name | flash_dev | offset | length |
[I/FAL] -------------------------------------------------------------
[I/FAL] | bl | stm32_onchip | 0x00000000 | 0x00010000 |
[I/FAL] | app | stm32_onchip | 0x00010000 | 0x000b0000 |
[I/FAL] | ef | norflash0 | 0x00000000 | 0x00100000 |
[I/FAL] | download | norflash0 | 0x00100000 | 0x00100000 |
[I/FAL] =============================================================
msh />
msh />fal probe download
Probed a flash partition | download | flash_dev: norflash0 | offset: 1048576 | len: 1048576 |.
msh />
3.3 擦除数据
- 先输入
fal erase
,后面跟着待擦除数据的起始地址以及长度。以下命令为:从 0 地址(相对 Flash 或分区)开始擦除 4096 字节数据
注意:根据 Flash 特性,擦除动作将按扇区对齐进行处理。所以,如果擦除操作地址或长度未按照 Flash 的扇区对齐,将会擦除掉与其关联的整个扇区数据。
msh />fal erase 0 4096
Erase data success. Start from 0x00000000, size is 4096.
msh />
3.4 写入数据
- 先输入
fal write
,后面跟着 N 个待写入的数据,并以空格隔开。以下命令为:从地址 8 的位置依次开始写入 1、2、3、4 、 5 这 5 个字节数据
msh />fal write 8 1 2 3 4 5
Write data success. Start from 0x00000008, size is 5.
Write data: 1 2 3 4 5 .
msh />
3.5 读取数据
- 先输入
fal read
,后面跟着待读取数据的起始地址以及长度。以下命令为:从 0 地址开始读取 64 字节数据
msh />fal read 0 64
Read data success. Start from 0x00000000, size is 64. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000000] FF FF FF FF FF FF FF FF 01 02 03 04 05 FF FF FF
[00000010] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
[00000020] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
[00000030] FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
msh />
3.6 性能测试
-
性能测试将会测试 Flash 的擦除、写入及读取速度,同时将会测试写入及读取数据的准确性,保证整个 Flash 或整个分区的 写入与读取 数据的一致性。
先输入
fal bench
,后面跟着待测试 Flash 的扇区大小(请查看对应的 Flash 手册,SPI Nor Flash 一般为 4096)。由于性能测试将会让整个 Flash 或者整个分区的数据丢失,所以命令最后必须跟yes
。
msh />fal bench 4096 yes
Erasing 1048576 bytes data, waiting...
Erase benchmark success, total time: 2.674S.
Writing 1048576 bytes data, waiting...
Write benchmark success, total time: 7.107S.
Reading 1048576 bytes data, waiting...
Read benchmark success, total time: 2.716S.
msh />
4、常见问题
- 使用 FAL 时,无法找到
fal_cfg.h
头文件
fal_cfg.h
为 fal 软件包的配置文件,需要用户手动新建,并定义相关的分区表信息。请将该文件统一放在 BSP 的 port 文件夹下或工程目录的 port 文件夹下(若没有则新建 port 文件夹),并将该头文件路径加入到工程。