RT-Thread 配置FAL与EasyFlash


背景

根据相关的需求,有时需要将参数等写入非易失存储设备。于是顺其自然就想到了EasyFlash,而EasyFlash在 RT-Thread 上可以很好地对接FAL,于是思路便是先配置 FAL(Flash Abstraction Layer Flash 抽象层),然后再移植 EasyFlash.

FAL:Flash 抽象层 介绍

FAL (Flash Abstraction Layer) Flash 抽象层,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层,对上层统一了 Flash 及 分区操作的 API (框架图如下所示),并具有以下特性:

  • 支持静态可配置的分区表,并可关联多个 Flash 设备;
  • 分区表支持 自动装载 。避免在多固件项目,分区表被多次定义的问题;
  • 代码精简,对操作系统 无依赖 ,可运行于裸机平台,比如对资源有一定要求的 Bootloader;
  • 统一的操作接口。保证了文件系统、OTA、NVM(例如:EasyFlash) 等对 Flash 有一定依赖的组件,底层 Flash 驱动的可重用性;
  • 自带基于 Finsh/MSH 的测试命令,可以通过 Shell 按字节寻址的方式操作(读写擦) Flash 或分区,方便开发者进行调试、测试;

详细的说明可以参考此仓库: FAL

FAL 在 RT-Thread 的配置

由于使用的是 STM32F407VGT6 的 bsp,在片内外设中打开 FLASH 的驱动

在系统包中打开 FAL 组件,并进入配置

SFUD 驱动暂时不选,后续还是需要打开此驱动来驱动SPI FLASH 的,但在只使用片内 FLASH 的情况下暂时不需要。

此时就基本配置完成了,bsp 中的片内 FLASH 驱动给我们省了很多事,只需要再打开fal_cfg.h文件修改一下分区表就可以了。

FAL 分区

参考官方库中的说明文档,其给出了一个分区表示例:

#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 (目前用于保留功能)

其中,"stm32_onchip" 表示的是整个 stm32 的片内 FLASH,而"norflash0"属于片外 FLASH,然而重点是:

STM32F4 系列的 FLASH 有些特殊

根据数据手册的描述,F4 系列 FLASH 不支持 F1 系列的页擦除,只支持扇区擦除,同时扇区大小又不太一致,数据手册中有这样的描述:

以 512k 为例,它将包含4个16KB 扇区,1个64KB 扇区,3个128KB 扇区,一共是8个扇区。

所以对应的,F4的fal_cfg.h文件中的分区配置是:

分为stm32_onchip_flash_16k,stm32_onchip_flash_64k,stm32_onchip_flash_128k三种设备,然后在分区表中自定义分区即可。

完成后在初始化时添加fal_init();函数

编译下载并运行,可以看到分区信息打印出来

EasyFlash 配置

同样的在工具中启用此组件


配置说明:
- ENV: Environment variables: 是否使能环境变量功能
- Auto update ENV to latest default when current ENV version number is changed.:是否启用环境变量自动更新功能。启动这个功能后,环境变量将在其版本号发生变化时自动更新。
- Setting current ENV version number : 当前环境变量版本号
- LOG: Save logs on flash:日志功能,可以将日志顺序保存至 Flash 中。还可以配合 EasyLogger 完成产品日志的掉电存储。
- IAP: In Application Programming:IAP 在线升级功能,开启后将提供一些 IAP 功能里常用的 API 。
- Erase minimum granularity:擦除的最小粒度,一般 SPI Flash 通常为 4KB,STM32F4 片内 Flash 通常为 128KB。
- Write minimum granularity:写数据的最小粒度,一般 SPI Flash 通常为 1bit,STM32F4 片内 Flash 通常为 8bit,详见具体选项。
- Start addr on flash or partition:EasyFlash 的整个存储区相对于 Flash 或者 分区 的偏移地址,视移植代码而定。
- Enable debug log output:是否使能调试日志输出。开启后将会看到更多调试日志信息。

由于是基于 fal : Flash 抽象层,所以添加移植文件,移植参考文件位于 /ports/ef_fal_port.c

修改文件该宏定义为 EasyFlash 准备使用的分区的分区名即可

我打算使用最后一个 128KB 扇区做测试

问题

测试过程并不顺利,EasyFlash 无法初始化成功,每次都会造成硬件错误

我仔细核对了分区参数,并不觉得有什么问题,只能推断最后一个扇区也用来存代码了,所以无法擦除引起硬件错误。正好可以使用 FAL 组件的功能来验证这一块扇区是否有数据。

截取一段官方文档的说明:


fal 提供了丰富的测试命令,项目只要在 RT-Thread 上开启 Finsh/MSH 功能即可。在做一些基于 Flash 的应用开发、调试时,这些命令会非常实用。它可以准确的写入或者读取指定位置的原始 Flash 数据,快速的验证 Flash 驱动的完整性,甚至可以对 Flash 进行性能测试。

具体功能如下:输入 fal 可以看到完整的命令列表

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.1、指定待操作的 Flash 设备或 Flash 分区

当第一次使用 fal 命令时,直接输入 fal probe 将会显示分区表信息。可以指定待操作的对象为分区表里的某个分区,或者某个 Flash 设备。

分区或者 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.2、擦除数据

先输入 fal erase ,后面跟着待擦除数据的起始地址以及长度。以下命令为:从 0 地址(相对 Flash 或分区)开始擦除 4096 字节数据

注意:根据 Flash 特性,擦除动作将按扇区对齐进行处理。所以,如果擦除操作地址或长度未按照 Flash 的扇区对齐,将会擦除掉与其关联的整个扇区数据。

msh />fal erase 0 4096
Erase data success. Start from 0x00000000, size is 4096.
msh />

3.3、写入数据

先输入 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.4、读取数据

先输入 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 />

运行了测试,发现此分区的前半部分确实已经存有数据了

所以使用片内 FLASH 作为KV存储的计划只能作罢,需要进一步加上片外 FLASH,反正也在计划之内,有时间再来加上。所以实际上还没有体验上 EasyFlash 的使用,只能等加上片外 FLASH 再说。

  • 分享:
评论
还没有评论
    发表评论 说点什么