armink / FlashDB

An ultra-lightweight database that supports key-value and time series data | 一款支持 KV 数据和时序数据的超轻量级数据库
Apache License 2.0
1.7k stars 400 forks source link

是否支持STM32G0B1RCT6 #279

Open wansaiyon opened 4 months ago

wansaiyon commented 4 months ago

您好! 我之前在N32G452,STM32F407,STM32F103上面均移植过FDB,EASYFLASH,可正常用于产品开发,现在MCU换到了STM32G0B1RCT7,移植master分支的FDB,版本2.1.0,读取出现问题 问题描述: 测试fdb/samples下的demo代码,写入粒度配置为64时,CRC错误 捕获

修改写粒度为0,1,8,32均有其它写入错误

配置情况: 1.drv_flash_g0.c文件写粒度配置情况: const struct fal_flash_dev stm32_onchip_flash = { "onchip_flash", STM32_FLASH_START_ADRESS, STM32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase},64}; 2.fdb_cfg.h文件写粒度配置情况:

define FDB_WRITE_GRAN 64

3.fal_cfg.h文件设备及分区配置情况: 只使用了内部BANK2的fdb_tsdb1,fdb_kvdb1进行测试 / flash device table /

define FAL_FLASH_DEV_TABLE \

{ \ &stm32_onchip_flash, \ } / ====================== Partition Configuration ========================== /

define FAL_PART_HAS_TABLE_CFG

ifdef FAL_PART_HAS_TABLE_CFG

/ partition table /

define FAL_PART_TABLE \

{ \ {FAL_PART_MAGIC_WORD, "app", "onchip_flash", 01024, 1201024, 0}, \ {FAL_PART_MAGIC_WORD, "etc", "onchip_flash", 120x1024, 8x1024, 0}, \ {FAL_PART_MAGIC_WORD, "param", "onchip_flash", 128x1024, 8x1024, 0}, \ {FAL_PART_MAGIC_WORD, "fdb_tsdb1", "onchip_flash", 136x1024, 8x1024, 0}, \ {FAL_PART_MAGIC_WORD, "fdb_kvdb1", "onchip_flash", 144x1024, 16x1024, 0}, \ } FLASH驱动验证情况: STM32G0B1RCT7的内部FLASH驱动移植的RTT的drv_flash_g0.c的代码,测试过双BANK(BANK1/BANK2均为128KB)读、写、擦除均正常。

enkiller commented 3 months ago

我在 STM32Gx 系列上也遇到类似问题。我是这样修改的,你可以参考一下

  1. 修改了 write_kv_hdr 函数,在写入 FDB_KV_PRE_WRITE 标记之后,在整条数据的末尾,添加了一个标记
static fdb_err_t write_kv_hdr(fdb_kvdb_t db, uint32_t addr, kv_hdr_data_t kv_hdr, bool isfull)
{
    fdb_err_t result = FDB_NO_ERR;
    /* write the status will by write granularity */
    result = _fdb_write_status((fdb_db_t)db, addr, kv_hdr->status_table, FDB_KV_STATUS_NUM, FDB_KV_PRE_WRITE, false);
    if (result != FDB_NO_ERR) {
        return result;
    }
#if FDB_WRITE_GRAN > 1
    if (isfull != true) {
        /* Writes a end tag */
        uint8_t endtag[(FDB_WRITE_GRAN + 7) / 8];
        memset(endtag, FDB_BYTE_WRITTEN, sizeof(endtag));
        result = _fdb_flash_write((fdb_db_t)db, addr + kv_hdr->len, endtag, sizeof(endtag), false);
        if (result != FDB_NO_ERR) {
            return result;
        }
    }
#endif
    /* write other header data */
    result = _fdb_flash_write((fdb_db_t)db, addr + KV_MAGIC_OFFSET, &kv_hdr->magic, sizeof(struct kv_hdr_data) - KV_MAGIC_OFFSET, false);

    return result;
}
  1. 修改 static fdb_err_t read_kv(fdb_kvdb_t db, fdb_kv_t kv) 函数,如果一个错误的头且处于删除状态,就不输出错误信息
   ...
    /* check CRC32 */
    if (calc_crc32 != kv_hdr.crc32) {
        uint32_t name_len = kv_hdr.name_len > FDB_KV_NAME_MAX ? FDB_KV_NAME_MAX : kv_hdr.name_len;
        kv->crc_is_ok = false;
        result = FDB_READ_ERR;
        if (kv->status == FDB_KV_ERR_HDR) {
            /* Incorrect KV has been removed. skip */
        } else {
            /* try read the KV name, maybe read name has error */
            kv_name_addr = kv->addr.start + KV_HDR_DATA_SIZE;
            _fdb_flash_read((fdb_db_t)db, kv_name_addr, (uint32_t *)kv->name, FDB_WG_ALIGN(name_len));
            FDB_INFO("Error: Read the KV (%.*s@0x%08" PRIX32 ") CRC32 check failed!\n", name_len, kv->name, kv->addr.start);
        }
    } else {
   ...

另外需要注意,STM32Gx 系列 Flash 带 ECC 特性,写入过程中掉电,概率出现 ECC 校验错误,访问错误的数据区域,将触发 NMI 中断

armink commented 3 months ago

@enkiller STM32Gx 是啥特性,和 FDB 支持的其他 Flash 有啥区别?

enkiller commented 3 months ago

@enkiller STM32Gx 是啥特性,和 FDB 支持的其他 Flash 有啥区别?

  1. Gx 系列不支持反复写,已经写入 0xFF 后,无法修改成其他值
  2. 写入 8 字节对齐
  3. 带 ECC 校验,访问 ECC 错误的数据,会产生 NMI 异常。物理层有限制,因此不能完全做到掉电安全。
enkiller commented 3 months ago

@enkiller STM32Gx 是啥特性,和 FDB 支持的其他 Flash 有啥区别?

  1. Gx 系列不支持反复写,已经写入 0xFF 后,无法修改成其他值
  2. 写入 8 字节对齐
  3. 带 ECC 校验,访问 ECC 错误的数据,会产生 NMI 异常。物理层有限制,因此不能完全做到掉电安全。
armink commented 3 months ago

@enkiller STM32Gx 是啥特性,和 FDB 支持的其他 Flash 有啥区别?

  1. Gx 系列不支持反复写,已经写入 0xFF 后,无法修改成其他值
  2. 写入 8 字节对齐
  3. 带 ECC 校验,访问 ECC 错误的数据,会产生 NMI 异常。物理层有限制,因此不能完全做到掉电安全。

明白了,第一个问题可否在驱动层完善下,比如:写之前先读取一下,如果发现读取回来的是 FF ,写入的也是 FF ,就跳过当前写入动作

enkiller commented 3 months ago

我在 write_kv_hdr 函数加入数据结束标志,是防止当前数据写入掉电,下次写入时,从结束标志后开始写。防止下一条数据也写入失败