一、驱动层:SFUD(Serial Flash Universal Driver) 是一款开源的串行 SPI Flash 通用驱动库
二、中间层:FAL(FLASH ABSTRACTION LAYER))FLASH 抽象层
三、应用层:FlashDB(FlashDB 是一款超轻量级的嵌入式数据库)
后记1:FlashDB嵌入式数据库之TSDB数据存储解析
FAL:Flash 抽象层
FAL:Flash 抽象层的使用
- 首先拉一段官网的简介先认识一下
官方链接: http://packages.rt-thread.org/detail.html?package=fal.
FAL (Flash Abstraction Layer) Flash 抽象层,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层,对上层统一了 Flash 及 分区操作的 API (框架图如下所示),并具有以下特性:
支持静态可配置的分区表,并可关联多个 Flash 设备;
分区表支持 自动装载 。避免在多固件项目,分区表被多次定义的问题;
代码精简,对操作系统 无依赖 ,可运行于裸机平台,比如对资源有一定要求的 Bootloader;
统一的操作接口。保证了文件系统、OTA、NVM(例如:EasyFlash) 等对 Flash 有一定依赖的组件,底层 Flash 驱动的可重用性;
自带基于 Finsh/MSH 的测试命令,可以通过 Shell 按字节寻址的方式操作(读写擦) Flash 或分区,方便开发者进行调试、测试;
FAL framework
还是很好理解的,就是一个中间层,把Flash硬件设备理想化未可操作的对象,这样就不需要管理下层的操作对象是SPI-FLASH还是EEPROM或者片内FLASH了
移植
-
fal的移植是建立在SFUD的底层驱动上的,所以如果没还没移植好SFUD,看上一篇文章
-
一样先下源码。Gitee仓库:https://gitee.com/RT-Thread-Mirror/fal/blob/master/docs/fal_api.md.
-
导入工程之后是这样样子的
-
注意一下,因为我使用的是SPI-FLASH所以使用fal_flash_sfud_port.c这个.C文件,如果是片内flash请选其他啊,不过一般这个用的多吧
-
跟着套路先改fal_cfg.h文件
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#define FAL_DEBUG 1 //启动打印
#define FAL_PART_HAS_TABLE_CFG //启动设备表
#define FAL_USING_SFUD_PORT //使用sfud通用串行flash
/* ===================== Flash device Configuration ========================= */
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", "norflash0", 0, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", "norflash0", 1024*1024, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
- 中间层的主要作用就是把,底层的物理接口抽象化,这里就是把W25Q64抽象成了2个对象,这里称位分区表
- FAL_PART_TABLE就是我们定义的分区表了,后期的擦,读,写都是针对分区表来操作的
- 自己搞了一个demo试了下
/**
* fal demo for the first flash device test.
*
*/
#define FAL_DEMO_TEST_BUFFER_SIZE 128
static uint8_t fal_demo_test_buf[FAL_DEMO_TEST_BUFFER_SIZE];
static void fal_demo(char* partition_name, uint8_t *data,size_t size)
{
int i,result;
const struct fal_partition *demo_partition;
//获取分区表指针
demo_partition = fal_partition_find(partition_name);
//擦除测试
result = fal_partition_erase( demo_partition, //分区表名称,所以分区表一定不能重复了
0, //擦除的起始地址
size //擦除的字节长度
); //返回接收的实际数量
if ( result >= 0 ) {
printf("Fal Erase The partition \"fdb_tsdb1\" is success...\n");
} else {
printf("Fal Erase The partition \"fdb_tsdb1\" is false!!!\n");
}
//写入前赋下初始值
for(i=0;i<size;i++)
data[i] = i;
//写入测试
result = fal_partition_write(demo_partition, //分区表名称,所以分区表一定不能重复了
0, //在分区表中的地址便宜,注意是分区表
data, //接收地址
size //接收长度
); //返回接收的实际数量
if ( result >= 0 ) {
printf("Fal write The partition \"fdb_tsdb1\" is success...\n");
} else {
printf("Fal write The partition \"fdb_tsdb1\" is false!!!\n");
}
//读取测试
result = fal_partition_read(demo_partition, //分区表名称,所以分区表一定不能重复了
0, //在分区表中的地址便宜,注意是分区表
data, //接收地址
size //接收长度
); //返回接收的实际数量
if ( result >= 0 ) {
printf("Fal Read The partition \"fdb_tsdb1\" is success...\n");
} else {
printf("Fal Read The partition \"fdb_tsdb1\" is false!!!\n");
}
- 这里偷懒了,日志打印的不是很全啊
总结
1.关键就是分区表,只要搞清楚了分区表,其他的就都清楚了
2.我们是单独使用的fal中间层,没有和Rt-Thread一起使用,没问题可以的
3.介绍了三部曲之二的中间层,接着是上层应用了FlashDB嵌入式数据库.