CH32V203C8T6裸机移植FlashDB

参考:

[FlashDB]基于GD32纯代码裸机移植FlashDB数据库——四、移植Fal

FlashDB官方移植指南

《CH32FV2x_V3xRM_V1-7》第32 章 闪存及用户选择字(FLASH)

感谢开源项目和其他作者的分享,本文为CH32V203C8T6裸机移植FlashDB (使用片内Flash)的学习过程记录。

0. FlashDB简介

FlashDB 是一款超轻量级的嵌入式数据库,专注于提供嵌入式产品的数据存储方案。与传统的基于文件系统的数据库不同,FlashDB 结合了 Flash 的特性,具有较强的性能及可靠性。并在保证极低的资源占用前提下,尽可能延长 Flash 使用寿命。

FlashDB 提供两种数据库模式:

  • 键值数据库 :是一种非关系数据库,它将数据存储为键值(Key-Value)对集合,其中键作为唯一标识符。KVDB 操作简洁,可扩展性强。
  • 时序数据库 :时间序列数据库 (Time Series Database , 简称 TSDB),它将数据按照 时间顺序存储 。TSDB 数据具有时间戳,数据存储量大,插入及查询性能高。

1. 移植FAL

新建MounRiver工程,并新建文件夹,添加fal源码到工程中(这里因为是裸机移植,并没有添加src文件夹中的fal_rtt.c)。这里我参考了fal_flash_stm32f1_port.c新建fal_flash_ch32v20x_port.c文件。

在这里插入图片描述

定义 flash 设备

如下,我使用了ch32v203c8t6内部flash的56KB-64KB这8KB的空间。

// fal_flash_ch32v20x_port.c

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

#define PAGE_SIZE (256u)

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;

static void HAL_FeedDog(void)
{
}

static void HAL_Flash_UnLock(void)
{
#if (SystemCoreClock > 96000000)
    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
    USART_Printf_Init(115200);
#endif
    __disable_irq();

    FLASH_Unlock();
}

static void HAL_Flash_Lock(void)
{
    FLASH_Lock();

#if (SystemCoreClock > 96000000)
    RCC->CFGR0 &= ~(uint32_t)RCC_HPRE_DIV2;
    USART_Printf_Init(115200);
#endif
    __enable_irq();
}

static void HAL_Flash_UnLock_Fast(void)
{
#if (SystemCoreClock > 96000000)
    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
    USART_Printf_Init(115200);
#endif
    __disable_irq();

    FLASH_Unlock_Fast();
}

static void HAL_Flash_Lock_Fast(void)
{
    FLASH_Lock_Fast();

#if (SystemCoreClock > 96000000)
    RCC->CFGR0 &= ~(uint32_t)RCC_HPRE_DIV2;
    USART_Printf_Init(115200);
#endif
    __enable_irq();
}

/**
 * @description: 在通用地址空间内进行直接寻址,
 *          任何8/16/32位数据的读操作都能访问闪存模块的内容并得到相应的数据
 * @param {long} offset
 * @param {uint8_t} *buf
 * @param {size_t} size
 * @return {*}
 */
static int read(long offset, uint8_t *buf, size_t size)
{
    size_t i;
    uint32_t addr = ch32v20x_onchip_flash.addr + offset;

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

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

    return size;
}

/**
 * @description:
 * @param {long} offset
 * @param {uint8_t} *buf
 * @param {size_t} size
 * @return {*}
 */
static int write(long offset, const uint8_t *buf, size_t size)
{
    size_t i;
    uint32_t addr = ch32v20x_onchip_flash.addr + offset;

    __attribute__((aligned(4))) uint32_t write_data;
    __attribute__((aligned(4))) uint32_t read_data;

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

    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);

    HAL_Flash_UnLock();

    for (i = 0; i < size; i += 4, buf += 4, addr += 4)
    {
        memcpy(&write_data, buf, 4); // 用以保证HAL_FLASH_Program的write_data是内存首地址对齐
        FLASH_ProgramWord(addr, write_data);
        read_data = *(uint32_t *)addr;
        /* You can add your code under here. */
        if (read_data != write_data)
        {
            HAL_Flash_Lock();
            return -1;
        }
        else
        {
            // FLash操作可能非常耗时,如果有看门狗需要喂狗,以下代码由用户实现
            HAL_FeedDog();
        }
    }

    HAL_Flash_Lock();

    on_ic_write_cnt++;
    return size;
}

/**
 * @description:FLASH_ErasePage_Fast
 *              Erases a specified FLASH page (1page = 256Byte)
 * @param {long} offset
 * @param {size_t} size
 * @return {*}
 */
static int erase(long offset, size_t size)
{
    uint32_t addr = ch32v20x_onchip_flash.addr + offset;

    //    uint8_t flash_status;
    size_t erase_pages, i;

    // 计算要擦除的page
    erase_pages = size / PAGE_SIZE;
    if (size % PAGE_SIZE != 0)
    {
        erase_pages++;
    }

    uint32_t page_address;

    HAL_Flash_UnLock_Fast();

    // 一次擦出一个扇区, 以执行一次喂狗,防止超时
    for (i = 0; i < erase_pages; i++)
    {
        page_address = addr + (PAGE_SIZE * i);
        FLASH_ErasePage_Fast(page_address);

        // if (flash_status != HAL_OK)
        // {
        //     HAL_FLASH_FastLock();
        //     return -1;
        // }
        // else
        // {
        // FLash操作可能非常耗时,如果有看门狗需要喂狗,以下代码由用户实现
        // HAL_FeedDog();
        // }
    }
    HAL_Flash_Lock_Fast();

    return size;
}

/*
    "ch32v20x_onchip_flash" : Flash 设备的名字。
    0x0800E000: 对 Flash 操作的起始地址。(ch32v203c8t6的Flash空间的56KB-64KB)
    1024 * 8:Flash 的总大小(8KB)。
    256:Flash 块/扇区大小(ch32v20x使用快速编程采用页操作方式,经过特定序列解锁后,可执行单次最少256 字节擦除,
        所以擦除粒度为最大块的大小:256B)。
    {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
    ch32v20x使用标准编程方式,CPU 可以单次2 字节方式执行编程,但这里我用FLASH_ProgramWord()函数,4字节方式即32bit
 */

// 1.定义 flash 设备
const struct fal_flash_dev ch32v20x_onchip_flash =
    {
        .name = "ch32v20x_onchip_flash",
        .addr = 0x0800E000,
        .len = 1024 * 8,
        .blk_size = PAGE_SIZE,
        .ops = {init, read, write, erase},
        .write_gran = 32
    };

定义 flash 设备表定义 flash 分区表

\\ fal_cfg.h

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <ch32v20x.h>

#define FAL_DEBUG       1

#define FAL_PART_HAS_TABLE_CFG

/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev ch32v20x_onchip_flash;

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &ch32v20x_onchip_flash,                                                                                \
}

/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WORD,       "KVDB",     "ch32v20x_onchip_flash",        0,  4*1024, 0}, \
    {FAL_PART_MAGIC_WORD,       "TSDB",     "ch32v20x_onchip_flash",   4*1024,  4*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

FAL移植测试

修改main.c如下:

#include "debug.h"

#include "fal.h"

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);

    printf("This is FlashDB use ch32v20x_onchip_flash example\r\n");

    fal_init();

    while(1)
    {
    }
}

如下添加-print-memory-usage即可查看编译结果的空间占用情况。

在这里插入图片描述

在默认配置下移植FAL的空间占用如下:

在这里插入图片描述

2. 移植FlashDB

添加FlashDB源码到工程中如下:

在这里插入图片描述

修改 fdb_cfg.h文件

宏定义flash写粒度(位于Line42

在这里插入图片描述

测试FlashDB

添加samples文件夹。

在这里插入图片描述

修改main.c

// main.c

#include "debug.h"

#include "fal.h"
#include "flashdb.h"

#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", "yzy", 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;
}

uint8_t flashdb_test_kvdb(void)
{ /* KVDB Sample */

	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);
	/* 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, "KVDB", "KVDB", &default_kv, NULL);

	if (result != FDB_NO_ERR) {
		return -1;
//		printf("\r\n FDB_NO_ERR = SET !!! \r\n");
	}

	/* 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);
	return 0;
}
uint8_t flashdb_test_tsdb(void)
{ /* TSDB Sample */
	fdb_err_t result;
	/* 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, "TSDB", "TSDB", 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;
//		printf("\r\n FDB_NO_ERR = SET !!! \r\n");
	}

	/* run TSDB sample */
	tsdb_sample(&tsdb);
	return 0;
}

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);

    printf("This is FlashDB use ch32v20x_onchip_flash example\r\n");

    fal_init();

    /* kvdb?? */
	flashdb_test_kvdb();
	/* tsdb?? */
	flashdb_test_tsdb();

    while (1)
    {
    }
}

空间占用如下:
在这里插入图片描述

正常的话效果如下:

在这里插入图片描述

但有时候会有这些写入错误出现,待解决。。。

在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值