【RT-Thread】FAL软件包的使用:FLASH分区管理


什么是分区管理

FLASH分区管理是怎么一回事呢?我们可以以个人电脑来做类比,我们的电脑通常都分有很多个盘符:

这些都是我们硬盘的分区,我这里装了两块硬盘,512GB的机械硬盘+128GB的固态硬盘,共分C~H六个分区,我这里的C盘和H盘是固态硬盘,其它盘符是机械硬盘:

分区名 存储设备名 偏移地址 大小 说明
“C盘” “固态硬盘” ~ 66GB 系统盘
“D盘” “机械硬盘” ~ 50GB 资料盘
“E盘” “机械硬盘” ~ 139GB 资料盘
“F盘” “机械硬盘” ~ 139GB 资料盘
“G盘” “机械硬盘” ~ 137GB 资料盘
“H盘” “固态硬盘” ~ 51GB 软件安装+常用资料

分区是为了方便我们对我们的资料进行管理,各个分区互不影响,比如格式化某个分区只会删除这个分区的内容而不会影响其它分区及整个硬盘等。

同样的,在我们的STM32上也是可以进行分区管理的,这篇笔记我们来使用RT-Thread的FAL软件包来对我STM32片内FLASH及片外FLASH的分区管理。

FAL软件包介绍

FAL (Flash Abstraction Layer) Flash 抽象层,是 RT-Thread 的一个软件包,是对 Flash 及基于 Flash的分区进行管理、操作的抽象层,对上层统一了 Flash 及分区操作的 API ,并具有以下特性:

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

FAL软件包使用

本笔记主要对潘多拉开发板的FAL例程进行一次梳理,所以部分表述来自于教程文档。我们这个实验建立如下分区表:

分区名 FLASH设备名 偏移地址 大小 说明
“c_partition” “stm32_onchip” 0 384KB c分区
“d_partition” “stm32_onchip” 384 * 1024 128KB d分区
“e_partition” “norflash0” 0 512KB e分区
“f_partition” “norflash0” 512 * 1024 1024KB f分区
“g_partition” “norflash0” (512 + 1024) * 1024 512KB g分区
“h_partition” “norflash0” (512 + 1024 + 512) * 1024 1024KB h分区

1、移植接口文件说明

FAL软件包的目录如下,其中samples文件夹下为移植接口文件:

其中fal_cfg.h 为fal 配置文件(Flash 设备配置和分区表配置) :

fal 是 Flash 抽象层,要操作 Flash 设备必然要将 Flash 的读、写、擦接口对接到 fal 抽象层中。在 fal中,使用 struct fal_flash_dev 结构体来让用户注册该 Flash 设备的操作接口。fal_flash_dev 结构体定义如下所示:

fal_flash_stm32f2_port.c为片内FLASH接口文件,这得根据实际芯片进行修改,主要是封装读、写、擦除函数,例如:

这和我们之前分享的: STM32内部FLASH读写操作详解(附代码) 步骤差不多。片内 Flash 对接说明 :

Flash 设备名称为 onchip_flash,设备容量为 512K,最小擦除单元为 2K,无初始化接口。

fal_flash_sfud_port.c为片外FLASH接口文件,这使用SFUD 万能 SPI Flash 通用驱动库来驱动。 片外 Nor Flash 对接说明 :

Flash 设备名称为 nor_flash,设备容量为 16M,最小擦除单元为 4K。这里使用的 read、 write、 erase接口最终调用 SFUD 框架中的接口,无需用户进行驱动开发

关于可SFUD 万能 SPI Flash 通用驱动库的介绍可查阅Mculove666的文章:SFUD | 一个简洁实用的开源项目,帮你轻松搞定SPI Flash

2、fal软件包API接口说明

这里主要列举出本实验需要用到的API说明,其它几个未用到的fal接口函数声明在fal.h文件中。

2.1 查找 Flash 设备

const struct fal_flash_dev *fal_flash_device_find(const char *name)
参数 描述
name Flash 设备名称
return 如果查找成功,将返回 Flash 设备对象,查找失败返回 NULL

2.2 查找 Flash 分区

const struct fal_partition *fal_partition_find(const char *name)
参数 描述
name Flash 分区名称
return 如果查找成功,将返回 Flash 分区对象,查找失败返回 NULL

2.3 获取分区表

const struct fal_partition *fal_get_partition_table(size_t *len)
参数 描述
len 分区表的长度
return 分区表

2.4 从分区读取数据

int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
参数 描述
part 分区对象
addr 相对分区的偏移地址
buf 存放待读取数据的缓冲区
size 待读取数据的大小
return 返回实际读取的数据大小

2.5 往分区写入数据

int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
参数 描述
part 分区对象
addr 相对分区的偏移地址
buf 存放待写入数据的缓冲区
size 待写入数据的大小
return 返回实际写入的数据大小

2.6 擦除分区数据

int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
参数 描述
part 分区对象
addr 相对分区的偏移地址
size 擦除区域的大小
return 返回实际擦除的区域大小

2.7 擦除整个分区数据

int fal_partition_erase_all(const struct fal_partition *part)
参数 描述
part 分区对象
return 返回实际擦除的区域大小

3、fal测试函数说明

移植完成后,调用 fal_init() 初始化该库。测试程序主函数:

对d分区与f分区进行读写测试。

(1)擦除分区测试:

/* 擦除整个分区 */
   ret = fal_partition_erase_all(partition);
   if (ret < 0)
   {
       LOG_E("Partition (%s) erase failed!", partition->name);
       ret = -1;
       return ret;
   }
   LOG_I("Erase (%s) partition finish!", partiton_name);

   /* 读出分区数据并校验 */
   for (i = 0; i < partition->len;)
   {
       rt_memset(buf, 0x00, BUF_SIZE);

       len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);

       ret = fal_partition_read(partition, i, buf, len);
       if (ret < 0)
       {
           LOG_E("Partition (%s) read failed!", partition->name);
           ret = -1;
           return ret;
       }

       for(j = 0; j < len; j++)
       {
           if (buf[j] != 0xFF)
           {
               LOG_E("The erase operation did not really succeed!");
               ret = -1;
               return ret;
           }
       }
       i += len;
   }

擦除成功则分区内容会变成0xFF

(2)读写测试

/* 往分区写0x00 */
for (i = 0; i < partition->len;)
{
    rt_memset(buf, 0x00, BUF_SIZE);

    len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);

    ret = fal_partition_write(partition, i, buf, len);
    if (ret < 0)
    {
        LOG_E("Partition (%s) write failed!", partition->name);
        ret = -1;
        return ret;
    }

    i += len;
}
LOG_I("Write (%s) partition finish! Write size %d(%dK).", partiton_name, i, i/1024);

/* 读取分区数据并校验 */
for (i = 0; i < partition->len;)
{
    rt_memset(buf, 0xFF, BUF_SIZE);

    len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);

    ret = fal_partition_read(partition, i, buf, len);
    if (ret < 0)
    {
        LOG_E("Partition (%s) read failed!", partition->name);
        ret = -1;
        return ret;
    }

    for(j = 0; j < len; j++)
    {
        if (buf[j] != 0x00)
        {
            LOG_E("The write operation did not really succeed!");
            ret = -1;
            return ret;
        }
    }

    i += len;
}

读出来的数据与写入的数据相等则测试成功。

程序运行结果:

使用SHELL命令测试FAL

为了方便用户验证 fal 功能是否正常,以及 Flash 驱动是否正确工作,分区表配置是否合理, RT-Thread为 fal 提供了一套测试命令:

1、探测命令

2、擦除命令

3、写数据命令

4、读数据命令

5、性能测试命令

性能测试将会测试 Flash 的擦除、写入及读取速度,同时将会测试写入及读取数据的准确性,保证整个 Flash 或整个分区的写入与读取数据的一致性。

注意事项:

• 如果要修改分区表,请正确配置起始地址和分区大小,不要有分区重叠。
• 在使用 fal 测试命令的时候,请先使用 fal probe 命令选择一个 Flash 分区。

以上就是本次的分享,欢迎转发!



文章作者: 杂烩君
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 杂烩君 !
  目录