文章目录
- 一、前言
- 二、FatFs、FlashDB 、EasyFlash 区别
- 2.1 FlashDB
- 2.2 EasyFlash
- 2.3 FATFS
- 三、FatFs、FlashDB、EasyFlash 区使用环境
- 3.1 FlashDB:
- 3.2 FATFS:
- 3.3 EasyFlash:
- 四、FlashDB移植
- 4.1 项目 GITEE 地址
- 4.2 项目目录
- 4.3 移植的目录树
- 4.4 MDK keil 添加文件
- 4.5 添加头文件
- 4.6 编写测试函数
- 4.7 根据自己的芯片修改参数
- 五、下载程序看一下
一、前言
最近项目用到了,
Flash
的存储,早就听过 armink 大神 开源的 EsayFlash ,于是乎就决定移植到新的项目上,发现 EasyFlash 升级到了 5.0.0 版本后因 API 接口与之前不完全兼容,故重新命名为 FlashDB,有很多种框架,FatFs,FlashDB, EasyFlash 等等。最终这个项目选择了FLASHDB
,因为 FlashDB的查询比EasyFlash快 ,FatFs 是针对大文件系统的那种项目。下面简单说一下 FlashDB 的移植。还有这三个的区别和使用环境
二、FatFs、FlashDB 、EasyFlash 区别
2.1 FlashDB
- FlashDB 是一个轻量级的嵌入式数据库系统,专门设计用于嵌入式系统中的数据存储和管理。
- 它允许在嵌入式系统中进行数据库风格的数据存储、检索和管理,例如表、索引、查询等。
- FlashDB 更适用于需要对数据进行结构化管理、复杂查询和事务处理的应用场景。
2.2 EasyFlash
- EasyFlash 是一个用于嵌入式系统的存储解决方案,旨在简化嵌入式系统中的 Flash 存储管理。
- 它提供了易于使用的 API,使开发人员能够轻松地在嵌入式系统中进行 Flash 存储的读写操作。
- EasyFlash 的主要功能是提供了一种简单的接口来管理 Flash 存储,而不涉及复杂的数据库功能。
2.3 FATFS
- FATFS 是一个用于嵌入式系统的文件系统,实现了 FAT 文件系统标准,用于管理嵌入式系统中的文件存储。
- 它允许嵌入式系统像操作硬盘或闪存设备一样操作文件系统,包括读写文件、创建目录等。
- FATFS 提供了一种通用的文件存储解决方案,适用于需要在嵌入式系统中进行文件级别的存储和管理的应用场景。
三、FatFs、FlashDB、EasyFlash 区使用环境
选择使用 FlashDB、FATFS 和 EasyFlash 取决于您的嵌入式系统的特定需求和应用场景
3.1 FlashDB:
- 适用环境:FlashDB 适用于需要对数据进行结构化存储、复杂查询和事务处理的嵌入式应用环境。
- 示例应用:例如,当您的嵌入式系统需要存储大量结构化数据,并且需要执行复杂的查询操作时,比如 IoT 设备中的传感器数据存储和分析,或者嵌入式控制器中的配置参数管理,FlashDB 可能是一个合适的选择。
3.2 FATFS:
- 适用环境:FATFS 适用于需要简单的文件存储和管理的嵌入式应用环境。
- 示例应用:如果您的嵌入式系统主要需要存储和管理文件,比如日志文件、配置文件、固件升级文件等,FATFS 是一个常见的选择。例如,嵌入式设备中的 SD 卡存储、USB 存储、固态硬盘等可以使用 FATFS 进行文件系统管理。
3.3 EasyFlash:
- 适用环境:EasyFlash 适用于需要轻量级、易于集成的嵌入式 Flash 存储管理的环境。
- 示例应用:如果您的嵌入式系统需要直接在 Flash 存储中读写数据,但不需要数据库的复杂功能,EasyFlash 可能是一个更适合的选择。例如,嵌入式设备中的配置参数存储、日志记录、用户数据存储等可以使用 EasyFlash。
总的来说,FlashDB 适用于需要数据库功能的应用,FATFS 适用于需要文件系统管理的应用,而 EasyFlash 则适用于需要直接 Flash 存储管理的应用。选择合适的解决方案需要综合考虑系统的存储需求、性能要求、复杂度和资源限制等因素。
四、FlashDB移植
4.1 项目 GITEE 地址
https://gitee.com/Armink/FlashDB?_from=gitee_search
4.2 项目目录
demos : 一些常用的开发实例工程
docs : 相关文档
inc : fdb
相关的头文件
port : fal
相关的文件(.c和.h都在里面)
samples : 开发实例工程用到的实例函数
src : fdb
相关的 .c 文件
tests : 这个是一些高治疗的模板,可以参考
4.3 移植的目录树
├─FAL #FAL相关文件
│ ├─inc #FAL相关的头文件
│ │ fal.h
│ │ fal_cfg.h
│ │ fal_def.h
│ │
│ └─src #FAL相关的.C文件
│ fal.c
│ fal_flash.c
│ fal_flash_stm32f1_port.c
│ fal_partition.c
│ fal_rtt.c
│
└─FlashDB #FLASHDB相关的文件
│ ├─inc #FLASHDB相关的头文件
│ │ fdb_cfg.h
│ │ fdb_def.h
│ │ fdb_low_lvl.h
│ │ flashdb.h
│ │
│ └─src #FLASH相关的.C文件
│ fdb.c
│ fdb_file.c
│ fdb_kvdb.c
│ fdb_tsdb.c
│ fdb_utils.c
│
└─samples # 这个是一些实例程序
kvdb_basic_sample.c
kvdb_type_blob_sample.c
kvdb_type_string_sample.c
tsdb_sample.c
把相关的文件 移植到工程里面
4.4 MDK keil 添加文件
4.5 添加头文件
4.6 编写测试函数
#define FDB_LOG_TAG "[main]"
static uint32_t boot_count = 0;
static time_t boot_time[10] = {0, 1, 2, 3};
/* default KV nodes */
static struct fdb_default_kv_node default_kv_table[] = {
{"username", "armink", 0}, /* string KV */
{"password", "123456", 0}, /* string KV */
{"boot_count", &boot_count, sizeof(boot_count)}, /* int type KV */
{"boot_time", &boot_time, sizeof(boot_time)}, /* int array type KV */
};
/* KVDB object */
static struct fdb_kvdb kvdb = { 0 };
/* TSDB object */
struct fdb_tsdb tsdb = { 0 };
/* counts for simulated timestamp */
static int counts = 0;
extern void kvdb_basic_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_string_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_blob_sample(fdb_kvdb_t kvdb);
extern void tsdb_sample(fdb_tsdb_t tsdb);
static void lock(fdb_db_t db)
{
__disable_irq();
}
static void unlock(fdb_db_t db)
{
__enable_irq();
}
static fdb_time_t get_time(void)
{
/* Using the counts instead of timestamp.
* Please change this function to return RTC time.
*/
return ++counts;
}
int FlashdbDemo()
{
fdb_err_t result;
#ifdef FDB_USING_KVDB
{ /* KVDB Sample */
struct fdb_default_kv default_kv;
default_kv.kvs = default_kv_table;
default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);
/* set the lock and unlock function if you want */
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, (void *)lock);
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, (void *)unlock);
/* Key-Value database initialization
*
* &kvdb: database object
* "env": database name
* "fdb_kvdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
* Please change to YOUR partition name.
* &default_kv: The default KV nodes. It will auto add to KVDB when first initialize successfully.
* NULL: The user data if you need, now is empty.
*/
result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, NULL);
if (result != FDB_NO_ERR) {
return -1;
}
/* run basic KV samples */
kvdb_basic_sample(&kvdb);
/* run string KV samples */
kvdb_type_string_sample(&kvdb);
/* run blob KV samples */
kvdb_type_blob_sample(&kvdb);
}
#endif /* FDB_USING_KVDB */
#ifdef FDB_USING_TSDB
{ /* TSDB Sample */
/* set the lock and unlock function if you want */
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, (void *)lock);
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, (void *)unlock);
/* Time series database initialization
*
* &tsdb: database object
* "log": database name
* "fdb_tsdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
* Please change to YOUR partition name.
* get_time: The get current timestamp function.
* 128: maximum length of each log
* NULL: The user data if you need, now is empty.
*/
result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, NULL);
/* read last saved time for simulated timestamp */
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);
if (result != FDB_NO_ERR) {
return -1;
}
/* run TSDB sample */
tsdb_sample(&tsdb);
}
#endif /* FDB_USING_TSDB */
return 0;
}
mian
函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
FlashdbDemo();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
4.7 根据自己的芯片修改参数
-
fal_flash_stm32f1_port.c
文件修改扇区大小 使用的是**
STM32VET6
** ,所以是 2048#if defined(STM32F103xE) #define PAGE_SIZE 2048 #else #define PAGE_SIZE 2048 #endif /* STM32F1会因容量不同而不同 小容量和中容量产品主存储块128KB以下, 每页1KB。 大容量和互联型产品主存储块256KB以上, 每页2KB。 GD32 会因容量不同而不同 1. Low-density Products Flash容量从 16KB到 32KB的产品 2. Medium-density Products Flash容量从 64KB到 128KB的产品 全是1K 3. High-density Products Flash容量从256KB到 512KB的产品 全是2K 4. XL-density Products Flash容量从768KB到3072KB的产品 <512K 是2K >512K 是4K 雅特力 全是2K STM32F4 STM32F4的flash页尺寸不一样,低地址16KB,高地址32KB或128KB. */
设备的信息
STM32F103VET6:是512k的flash ,blk_size 这个是擦除扇区的大小,ops这里是flash操作的,初始化、获取、写入、擦除的回调函数,
/* "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 stm32f2/f4: 8 bit stm32f1: 32 bit stm32l4: 64 bit */ //1.定义 flash 设备 const struct fal_flash_dev stm32_onchip_flash = { .name = "stm32_onchip", .addr = 0x08000000, .len = 512*1024, .blk_size = 2*1024, .ops = {init, read, write, erase}, .write_gran = 32 };
-
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_ #define FAL_DEBUG 1 #define FAL_PART_HAS_TABLE_CFG /* ===================== Flash device Configuration ========================= */ extern const struct fal_flash_dev stm32_onchip_flash; /* flash device table */ #define FAL_FLASH_DEV_TABLE \ { \ &stm32_onchip_flash, \ } /* ====================== Partition Configuration ========================== */ #ifdef FAL_PART_HAS_TABLE_CFG /* partition table */ #define FAL_PART_TABLE \ { \ {FAL_PART_MAGIC_WORD, "fdb_tsdb1", "stm32_onchip", 104*1024, 8*1024, 0}, \ {FAL_PART_MAGIC_WORD, "fdb_kvdb1", "stm32_onchip", 112*1024, 16*1024, 0}, \ } #endif /* FAL_PART_HAS_TABLE_CFG */ #endif /* _FAL_CFG_H_ */
这里需要定义 FAL_PART_HAS_TABLE_CFG 不然这个列表会出错
FAL_DEBUG : 需要打印log信息就是
1
, 不需要改成0
**fdb_kvdb1 : **这个是扇区名字,在上面的测试程序中,所使用的扇区名字就是这个
**stm32_onchip : **这个是设备的名字
104*1024 :这个是扇区的起始地址
**8*1024 : **这个是扇区的大小
FAL_PART_MAGIC_WORD
属性,末尾增加0
(目前用于保留功能)注意!!! 这里的起始地址和扇区大小要严格计算一下,不要和程序地址重合,也不要超过
FLASH
的大小,不然会导致 死机 -
fdb_cfg.h
配置* only support 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1)/ 64(stm32f7)/ 128(stm32h5) */ #define FDB_WRITE_GRAN 32/* @note you must define it for a value */
原来的程序FDB_WRITE_GRAN 是空的,填写自己芯片的类型
五、下载程序看一下
- 分区表已经初始化成功
- 测试程序也运行了。
- 资源下载地址
Stm32FlashDb 工程
文章是自己总结而记录,有些知识点没说明白的,请各位看官多多提意见,多多交流,欢迎大家留言
如果技术交流可以加以下群,方便沟通
QQ群:370278903
点击链接加入群聊【蜡笔小芯的嵌入式交流群】