当前位置: 首页 > news >正文

FlashDB移植

1.源码

FlashDB: 一款支持 KV 数据和时序数据的超轻量级数据库

移植指南:

开发 - 移植 - 《FlashDB v2.1 使用教程》 - 书栈网 · BookStack

2.文件结构

文件介绍
demos各种demo
docs文档
incflashDB头文件
portfal/inc: fal抽象层的头文件 fal/porting: 各种类型flash接口读写配置 fal/src: fal的抽象层
sampleskvdb tsdb例子
srcflashDB源码
tests测试
zephyrlinux推出的实时系统

inc文件

fdb_cfg_template.h: 这个实际需要修改为fdb_cfg.h, 用于配置flashDB(一般去例程里面拿配置好的文件)

fdb_def.h: flashDB的定义

fdb_low_lvl.h: 对接底层flash的读写函数的头文件, 函数定义在: fdb_untils.c

flashdb.h: kvdb和tsdb的API函数

port文件

fal/inc

fal_def.h: fal_flash_dev_t : 用于对接flash的一些操作

struct fal_flash_dev
{
    char name[FAL_DEV_NAME_MAX];	//flash的名字:norflash(stm32的flash)

    /* flash device start address and len  */
    uint32_t addr;		//flash操作的起始地址(stm32 norflash的起始地址0x0800000), spiflash为 0x00
    size_t len;			//整个flash的大小: stm32内部flash整个大小, spiflash: 整个flash的大小
    /* the block size in the flash for erase minimum granularity */
    size_t blk_size;	//擦除块/扇区大小: stm32各个系列不同

    struct
    {
        int (*init)(void);
        int (*read)(long offset, uint8_t *buf, size_t size);
        int (*write)(long offset, const uint8_t *buf, size_t size);
        int (*erase)(long offset, size_t size);
    } ops;		//对接flash的操作函数

    /* write minimum granularity, unit: bit. 
       1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1)/ 64(stm32l4)
       0 will not take effect. */
    size_t write_gran;	//写的最小字节, stm32f2/f4为一个字节, f1四个字节
};

 定义fal分区

struct fal_partition
{
    uint32_t magic_word;	//魔术字: 固定为 FAL_PART_MAGIC_WORD

    /* partition name */
    char name[FAL_DEV_NAME_MAX];			// 定义的分区名
    /* flash device name for partition */
    char flash_name[FAL_DEV_NAME_MAX];		// flash名字(struct fal_flash_dev中定义的名字)

    /* partition offset address on flash device */
    long offset;			//分区名的起始地址
    size_t len;				//分区的长度

    uint32_t reserved;		//保留
};
{                                                                                     \
    {FAL_PART_MAGIC_WORD, "fdb_kvdb1",  NOR_FLASH_DEV_NAME,          0, 16*1024, 0},  \
    {FAL_PART_MAGIC_WORD, "fdb_tsdb1",  NOR_FLASH_DEV_NAME, 16*1024   , 16*1024, 0}, \
}

fal.h: flash抽象层读写,擦除一些函数声明

fal/porting

fal_cfg.h: 定义flash设备表,以及flashDB的分区表

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &stm32f2_onchip_flash,                                           \
    &nor_flash0,                                                     \
}
/* ====================== Partition Configuration ========================== */
#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}, \
}

fal_flash_sfud_port.c: 这个是对接spiflash的, 这个需要SFUD库

fal_flash_stm32f1_port.c: 定义和f1内部flash相关的读写配置, 以及flash设备定义

fal_flash_stm32f2_port.c

fal_flash_stm32f4_port.c

fal_flash_stm32l4_port.c

fal/src

fal_flash.c:

fal_flash_init: 对接ops操作函数
fal_flash_device_find: 通过名字查找flash设备

fal_partition.c

static const struct fal_partition partition_table_def[] = FAL_PART_TABLE;  //定义分区表
static const struct fal_partition *partition_table = NULL;		//这个在初始化事会指向partition_table_def

// 保存flash设备的名字,操作函数ops,配置信息
static struct part_flash_info part_flash_cache[sizeof(partition_table_def) / sizeof(partition_table_def[0])] = { 0 };
fal_show_part_table: 显示分区信息
check_and_update_part_cache: 检查更新分区, part_flash_cache也就是更新这个数组
fal_partition_init: 分区初始化
fal_partition_find: 通过分区名查找分区表
flash_device_find_by_part: 通过分区查找flash设备
fal_get_partition_table: 获取首个分区, 以及分区数量
fal_set_partition_table_temp: 此设置将临时修改分区表,重启后该设置将丢失
fal_partition_read: 对某个分区读
fal_partition_write: 对某个分区写
fal_partition_erase: 对某个分区擦除
fal_partition_erase_all: 擦除整个分区

fal_rtt.c

这个和rt-thread对块设备读写函数, 可以忽视,除非使用rt-thread的驱动

fal.c

fal_init: 初始化flash设备,以及分区表初始化

fal_init_check: 检查是否初始化成功

src

fdb_file.c: 这个对接的是与文件操作相关

fdb_kvdb.c: kvdb相关的操作

fdb_tsdb.c: tsdb相关操作

fdb_utils.c: flashDB抽象层的读写函数

fdb.c: flashDB初始化

移植

1. 在工程目录下新增flashDB目录

2. 将源码下的inc和src复制到flashDB目录, 将fdb_cfg_template.h删除, 找到demos中fdb_cfg.h的这个文件替换

3. 新建一个port文件夹, 将源码目录下的port/fal的inc和src复制到port文件夹下, 将demos中对应的fal_cfg.h复制到目录下

这个文件很重要, 用于配置flashDB的分区

/*
 * Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#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",   256*1024, 256*1024, 0},  \
    {FAL_PART_MAGIC_WORD,  "fdb_kvdb1",    "stm32_onchip",   512*1024, 256*1024, 0},  \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

4.我用的是stm32f4, 就将fal_flash_stm32f4.c复制进来(如何是spiflash, 将fal_flash_sfud_port.c复制进来,同时移植SFUD库来驱动spiflash)

配置打印

  1. 默认情况下, 整个库是通过printf来打印的, 因此需要实现int fputc(int ch, FILE *f), 在.裸机和freertos中都是printf打印.

void print_char(char ch)
{
    rt_kprintf("%c",ch);
}
int fputc(int ch, FILE *f)
{
    
    if (ch == '\n') {
        print_char('\r');
    }

    print_char(ch);

    return ch;
}

2.  我这里用的是rt-thread, 因此只需要开启fal_def.h中的关于rtthread的配置

#define __RTTHREAD__

#ifdef __RTTHREAD__ /* for RT-Thread platform */
#include <rtthread.h>
#define FAL_PRINTF      rt_kprintf
#define FAL_MALLOC      rt_malloc
#define FAL_CALLOC      rt_calloc
#define FAL_REALLOC     rt_realloc
#define FAL_FREE        rt_free
#endif

如何使用可以看port/fal/samples下的四个例程

kvdb_basic_sample.c: 用于设置和获取初始化配置的kv

kvdb_type_blob_sample.c: blob对象的kv的设置与读取

kvdb_type_string_sample.c: string对象的kv设置与读取

tsdb_sample.c: 时间的kv


#include "stm32f4xx_hal.h"
#include "LED/led.h"
#include "board.h"
#include "rtthread.h" 
#include "usart/usart.h"

#include <flashdb.h>

void SystemClock_Config(void);
static void Error_Handler(void);

//void print_char(char ch)
//{
//    rt_kprintf("%c",ch);
//}
//int fputc(int ch, FILE *f)
//{
//    
//    if (ch == '\n') {
//        print_char('\r');
//    }

//    print_char(ch);

//    return ch;
//}
int boot_count = 0;
int boot_time = 0;
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 };

static void lock(fdb_db_t db)
{
    __disable_irq();
}

static void unlock(fdb_db_t db)
{
    __enable_irq();
}
static int counts = 0;
static fdb_time_t get_time(void)
{
    /* Using the counts instead of timestamp.
     * Please change this function to return RTC time.
     */
    return ++counts;
}

int main(void)
{
    HAL_Init();
    /* Configure the system clock to 168 MHz */
    SystemClock_Config();
    

    MX_GPIO_Init();
    
    fdb_err_t result;
    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);

    result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, NULL);
    if (result != FDB_NO_ERR) {
        return -1;
    }
    
    while (1)
    {
        rt_thread_delay(1000);
    }
}





void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;
  
  /* Enable Power Control clock */
  __HAL_RCC_PWR_CLK_ENABLE();
  
  /* The voltage scaling allows optimizing the power consumption when the device is 
     clocked below the maximum system frequency, to update the voltage scaling value 
     regarding system frequency refer to product datasheet.  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  
  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 
     clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;  
  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }

  /* STM32F405x/407x/415x/417x Revision Z and upper devices: prefetch is supported  */
  if (HAL_GetREVID() >= 0x1001)
  {
    /* Enable the Flash prefetch */
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
  }
}

static void Error_Handler(void)
{
  /* User may add here some code to deal with this error */
  while(1)
  {
  }
}

相关文章:

  • Redis 热key问题怎么解决?
  • 计算机毕业设计指南
  • 开发指南111-关闭所有打开的子窗口
  • Spring 中有哪些设计模式?
  • python入门之从安装python及vscode开始
  • 功耗日志抓取需求
  • (六)安卓开发中的Activity的启动、关闭和生命周期详解
  • 目录遍历(Directory traversal)漏洞总结
  • keepalived高可用介绍
  • VLAN(虚拟局域网)
  • 机器学习之数据预处理(一):缺失值处理和异常值识别的几种常用方法
  • ER-图,详情和画法
  • Windows操作系统安全配置(一)
  • 关于计算机网络的一些疑问
  • 新一代AI架构实践:数字大脑AI+智能调度MCP+领域执行APP的黄金金字塔体系
  • 批量将 Markdown 转换为 Word/PDF 等其它格式
  • react和vue在开发使用的语法上面有什么区别?
  • 自动微分模块
  • SpringSecurity框架入门
  • (自用)WebSocket创建流程
  • 系统网站建设公司/小网站怎么搜关键词
  • 洛阳网站建设哪家便宜/百度关键词收录
  • 新广告法 做网站的/域名交易平台
  • 网页设计师考试报名/网站优化推广seo
  • 用discuz做的门户网站/谷歌广告推广
  • 北京住房和城乡建设局门户网站/搜索优化指的是什么