STM32G473VET6 FlashDB数据库移植(裸机、片内Flash)

STM32G473VET6 FlashDB数据库移植(裸机、片内Flash)

此文档也适用于STM32G070

源码下载

此处使用FlashDB官方最新源码

FlashDB: 一款支持 KV 数据和时序数据的超轻量级数据库 (gitee.com)

克隆源码后目录如下

红框中几个为移植必要文件与参考

image-20230725110414245

根据FlashDB官方文档可知,FlashDB底层依赖于RT-Thread的FAL组件,所以需要先移植FAL

FlashDB源码中port目录下即为FAL组件源码

移植参考文档

移植 (gitee.io)

image-20230725110641611

开始移植

添加FAL组件源码

准备一个HAL库STM32G473工程,配置好LOG打印串口把printf重定向至串口,细节此处略过

添加FAL与FlashDB源码至准备好的工程

如下图所示,目录可自行更改无需与本文档一致,此处仅为演示所用

image-20230725111552113

红框中为FAL源码部分,位于FlashDB源码的port/fal目录下的inc与src文件夹中,此处我把头文件与源文件存放在了一个文件夹中

同时复制一份官方原源码中的移植参考代码重命名后放入此文件夹中,参考代码目录如下图

代码位于port/fal/samples/porting目录下

image-20230725112018654

添加FlashDB源码

添加过程同上,需添加文件如下

image-20230725112600465

以上文件位于FlashDB源码的inc与src目录下。

所有文件添加完成后keil目录如下,不要忘记添加头文件路径,此处详细过程省略。

image-20230725112911798

移植FAL

移植FAL很简单,仅需实现对flash的读写擦除三个函数即可,可根据参考例程修改。

此次移植修改如下

STM32G473VE的Flash为512k,根据数据手册可知,此flash为双bank每个bank有128个页每页2k单次擦除最小为一页所以写入是要注意bank与页的计算

同时需注意G473与G070的flash写最小粒度皆为双字

image-20230725113424294

修改后代码如下(fal_flash_stm32_port.c)

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

#include <string.h>
#include <fal.h>
#include <stm32g4xx_hal.h>

#define PAGE_SIZE     FLASH_PAGE_SIZE


/*
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.
*/

static uint32_t GetPage(uint32_t Addr)
{
    uint32_t page = 0;
    page = (Addr-FLASH_BASE) / FLASH_PAGE_SIZE;
    return page;
}

static int init(void)
{
    /* do nothing now */
    return 1;
}


static int ef_err_port_cnt = 0;
int on_ic_read_cnt  = 0;
int on_ic_write_cnt = 0;

void feed_dog(void)
{

}

static int read(long offset, uint8_t *buf, size_t size)
{

    size_t i;
    uint32_t addr = stm32_onchip_flash.addr + offset;

    if( addr%8 != 0)
        ef_err_port_cnt++;

    for (i = 0; i < size; i++, addr++, buf++)
    {
        *buf = *(uint8_t *) addr;
    }
    on_ic_read_cnt++;
    return size;
}


static int write(long offset, const uint8_t *buf, size_t size)
{
    size_t   i;
    uint32_t addr = stm32_onchip_flash.addr + offset;

    __ALIGN_BEGIN uint64_t write_data __ALIGN_END;
    __ALIGN_BEGIN uint64_t read_data  __ALIGN_END;

    if(addr%8 != 0)
        ef_err_port_cnt++;

    /*
        if((int)buf%4 != 0)
            ef_err_port_cnt++;
    */

    HAL_FLASH_Unlock();
    for (i = 0; i < size; i += 8, buf += 8, addr += 8) {
        memcpy(&write_data, buf, 8); //用以保证HAL_FLASH_Program的第三个参数是内存首地址对齐
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, write_data);
        read_data = *(uint64_t *)addr;
        if (read_data != write_data) {
            HAL_FLASH_Lock();
            return -1;
        }
        else {
            feed_dog();
        }
    }
    HAL_FLASH_Lock();


    on_ic_write_cnt++;
    return size;
}


static int erase(long offset, size_t size)
{
    uint32_t addr = stm32_onchip_flash.addr + offset;

    HAL_StatusTypeDef flash_status;
    size_t erase_pages, i;
    uint32_t PAGEError = 0;

    erase_pages = size / PAGE_SIZE;//页数量
    if (size % PAGE_SIZE != 0) {
        erase_pages++;
    }

    FLASH_EraseInitTypeDef EraseInitStruct;
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.NbPages     = 1;  //一次擦出一个扇区, 以执行一次喂狗,防止超时
    HAL_FLASH_Unlock();
    for (i = 0; i < erase_pages; i++) {
        if(addr + (FLASH_PAGE_SIZE * i)<=0x0803ffff) {//判断当前页所处bank
            EraseInitStruct.Banks = FLASH_BANK_1;
        } else {
            EraseInitStruct.Banks = FLASH_BANK_2;
        }
        EraseInitStruct.Page = GetPage(addr + (FLASH_PAGE_SIZE * i));//计算当前所处页
        flash_status = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
        if (flash_status != HAL_OK) {
            HAL_FLASH_Lock();
            return -1;
        }
        else {
            //FLash操作可能非常耗时,如果有看门狗需要喂狗,以下代码由用户实现
            feed_dog();
        }
    }
    HAL_FLASH_Lock();

    return size;
}


/*
  "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 = 64
};



修改配置头文件(fal_cfg.h)

头文件无需做很大修改,配置一下分区表即可,分区表具体设置细节可参考FlashDB官方文档

image-20230725114307933

此处修改完成后如下

/*
 * 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_kvdb1",    "stm32_onchip",   230*1024, 16*1024, 0},  \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

若无需打印LOG信息可把宏#define FAL_DEBUG 1进行注释

FlashDB移植

因为FlashDB依赖于FAL,所以移植完成FAL之后FlashDB的移植工作基本就算完成90%了,

下面仅需修改一下FlashDB的配置文件即可完成移植

修改fdb_cfg.h

把宏#define FDB_USING_TSDB进行注释,因为FlashDB的TSDB还不支持双字写入粒度的flash

添加宏#define FDB_USING_FAL_MODE

修改宏#define FDB_WRITE_GRAN为64(双字写入粒度)

修改完成后如下

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

/**
 * @file
 * @brief configuration file
 */

#ifndef _FDB_CFG_H_
#define _FDB_CFG_H_

#define FDB_USING_FAL_MODE

/* using KVDB feature */
#define FDB_USING_KVDB

#ifdef FDB_USING_KVDB
/* Auto update KV to latest default when current KVDB version number is changed. @see fdb_kvdb.ver_num */
/* #define FDB_KV_AUTO_UPDATE */
#endif

/* using TSDB (Time series database) feature */
//#define FDB_USING_TSDB

/* the flash write granularity, unit: bit
 * only support 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1) */
#define FDB_WRITE_GRAN                 64

/* MCU Endian Configuration, default is Little Endian Order. */
/* #define FDB_BIG_ENDIAN  */

/* log print macro. default EF_PRINT macro is printf() */
/* #define FDB_PRINT(...)              my_printf(__VA_ARGS__) */

/* print debug information */
#define FDB_DEBUG_ENABLE

#endif /* _FDB_CFG_H_ */

测试

跑一跑FlashDB的demo,demo可从FlashDB源码例程里面复制(懒得自己写了)

void kvdb_basic_sample(fdb_kvdb_t kvdb)
{
    struct fdb_blob blob;
    uint8_t boot_count = 0;

    debug_print("==================== kvdb_basic_sample ====================\n");

    { /* GET the KV value */
        /* get the "boot_count" KV value */
        fdb_kv_get_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
        /* the blob.saved.len is more than 0 when get the value successful */
        if (blob.saved.len > 0) {
            debug_print("get the 'boot_count' value is %d\n", boot_count);
        } else {
            debug_print("get the 'boot_count' failed\n");
        }
    }

    { /* CHANGE the KV value */
        /* increase the boot count */
        boot_count += 10;
        /* change the "boot_count" KV's value */
        fdb_kv_set_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
        debug_print("set the 'boot_count' value to %d\n", boot_count);
    }

    debug_print("===========================================================\n");
}

QQ录屏20230725135529

可以看到FAL分区信息正常,FlashDB每次复位之后键对应的值都会+10,存储成功,移植完成。

EMD

完整工程
STM32G473VET6-HAL库-裸机移植FAL-FlashDB测试工程资源-CSDN文库

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kongbai_w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值