【开源分享】EasyFlash,一款开源的轻量级嵌入式Flash存储器库

请添加图片描述


1. EasyFlash简介

EasyFlash是一款开源的轻量级嵌入式Flash存储器库,方便开发者更加轻松的实现基于Flash存储器的常见应用开发。非常适合智能家居、可穿戴、工控、医疗、物联网等需要断电存储功能的产品,资源占用极低,支持各种 MCU 片上存储器。该库主要包括 三大实用功能 :

  • ENV 快速保存产品参数,支持 写平衡(磨损平衡) 及 掉电保护 功能
    EasyFlash 不仅能够实现对产品的 设定参数 或 运行日志 等信息的掉电保存功能,还封装了简洁的 增加、删除、修改及查询 方法, 降低了开发者对产品参数的处理难度,也保证了产品在后期升级时拥有更好的扩展性。让 Flash 变为 NoSQL(非关系型数据库)模型的小型键值(Key-Value)存储数据库。

  • IAP 在线升级再也不是难事儿
    该库封装了 IAP(In-Application Programming) 功能常用的接口,支持 CRC32 校验,同时支持 Bootloader 及 Application 的升级。

  • Log 无需文件系统,日志可直接存储在 Flash 上
    非常适合应用在小型的不带文件系统的产品中,方便开发人员快速定位、查找系统发生崩溃或死机的原因。同时配合 EasyLogger (一款开源的超轻量级、高性能 C 日志库,它提供与 EasyFlash 的无缝接口)一起使用,轻松实现 C 日志的Flash存储功能。


1.1 V4.0 NG 模式

EasyFlash V4.0 版本中的 ENV 功能被命名为 NG (Next Generation) 模式,这是一个完全重构的新版本,具有以下新特性:

  • 更小的资源占用,内存占用 几乎为 0 ;(V4.0 以前版本会使用额外的 RAM 空间进行缓存)
  • ENV 的值类型支持 任意类型 、任意长度,相当于直接 memcpy 变量至 flash ;(V4.0 之前只支持存储字符串)
  • ENV 操作效率比以前的模式高,充分利用剩余空闲区域,擦除次数及操作时间显著降低;
  • 原生支持 磨损平衡、掉电保护功能 (V4.0 之前需要占用额外的 Flash 扇区);
  • ENV 支持 增量升级 ,固件升级后 ENV 也支持升级;
  • 支持大数据存储模式,长度无限制,数据可在多个 Flash 扇区上顺序存储。像脚本程序、音频等占用 Flash 超过 1 个扇区的资源也都可以存入 ENV(即将在 V4.2 支持);
  • 支持 数据加密 ,提升存储的安全性,物联网时代的必备功能(即将在 V4.3 支持);
  • 支持 数据压缩 ,减低 Flash 占用(即将在 V4.4 支持);

1.2 资源占用

最低要求: ROM: 6K bytes RAM: 0.1K bytes


2. 移植与集成实例

2.1 STM32F103 & FW25QXX上集成

2.1.1 准备工作

1. 硬件资源确认
  • STM32F103C8T6 Flash 规格:
    • 总容量:64KB(0x08000000 ~ 0x0800FFFF)
    • 页大小:1KB(部分型号为2KB,需根据数据手册确认)
    • 擦写次数:约10万次
2. 软件依赖
  • 开发环境:Keil MDK/STM32CubeIDE + HAL库 或标准外设库
  • EasyFlash源码:GitHub仓库
  • 确保已集成 EasyLogger(可选,用于调试输出)

2.1.2 移植步骤

1. 添加源码到工程
  • 下载 EasyFlash 源码,将以下文件加入工程:

    • easylogger/inc/(头文件)
    • easylogger/src/(源文件,包括 ef_port.c、ef_utils.c 等)
    • 注意:需根据需求启用 EF_USING_ENV(环境变量)或 EF_USING_LOG(日志存储)。
  • 在工程中配置头文件路径:

// 例如在Keil中:
- ".\easylogger\inc"
- ".\User\Inc"       // 存放移植接口文件

2. 移植接口实现
2.1 Flash驱动函数

在 ef_port.c 中实现以下接口:

#include "ef_port.h"
#include "stm32f1xx_hal_flash.h"  // 使用HAL库

/* 定义EasyFlash使用的Flash区域 */
#define EF_START_ADDR    0x0800F000  // 假设使用最后4KB(需根据实际Flash大小调整)
#define EF_SIZE          0x00001000  // 4KB

/* 初始化Flash */
EfErrCode ef_port_init(void) {
    // 无需特殊初始化
    return EF_NO_ERR;
}

/* 擦除Flash页 */
EfErrCode ef_port_erase(uint32_t addr, size_t size) {
    HAL_FLASH_Unlock();  // 解锁Flash
    FLASH_EraseInitTypeDef erase;
    erase.TypeErase = FLASH_TYPEERASE_PAGES;
    erase.PageAddress = addr;
    erase.NbPages = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;  // 计算需擦除的页数

    uint32_t pageError;
    if (HAL_FLASHEx_Erase(&erase, &pageError) != HAL_OK) {
        HAL_FLASH_Lock();
        return EF_ERASE_ERR;
    }
    HAL_FLASH_Lock();
    return EF_NO_ERR;
}

/* 写入Flash */
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
    HAL_FLASH_Unlock();
    for (size_t i = 0; i < size; i += 4) {
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i, *buf) != HAL_OK) {
            HAL_FLASH_Lock();
            return EF_WRITE_ERR;
        }
        buf++;
    }
    HAL_FLASH_Lock();
    return EF_NO_ERR;
}

/* 读取Flash */
void ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {
    memcpy(buf, (void*)addr, size);
}

2.2 配置EasyFlash参数

在 ef_cfg.h 中修改配置:

#define EF_START_ADDR            EF_START_ADDR  // 与前述定义一致
#define EF_ERASE_MIN_SIZE        FLASH_PAGE_SIZE  // 擦除最小单位(1KB)
#define EF_WRITE_GRAN            EF_WRITE_GRAN_4BYTE  // STM32F1按4字节写入

3. 初始化与测试
3.1 初始化EasyFlash

在 main.c 中:

#include "easyflash.h"

int main(void) {
    HAL_Init();
    SystemClock_Config();

    /* 初始化EasyFlash */
    if (easyflash_init() == EF_NO_ERR) {
        log_i("EasyFlash init success!");
    }

    /* 测试环境变量读写 */
    ef_set_env("boot_count", "0");
    char *value = ef_get_env("boot_count");
    log_d("boot_count = %s", value);

    while (1) { }
}
3.2 测试输出

通过串口查看日志(需集成EasyLogger):

[I][main.c:25] EasyFlash init success!
[D][main.c:28] boot_count = 0

2.1.3 关键注意事项

1. Flash地址对齐
  • 擦除地址:必须按页对齐(如 0x0800F000)。
  • 写入地址:需按4字节对齐(STM32F1要求)。
2. 存储寿命优化
  • 磨损均衡:若频繁擦写,建议使用多扇区轮换存储。
  • 减少擦除次数:合并多次写操作,避免频繁擦除。
3. 多线程安全

在RTOS中,需在Flash操作前后加锁(如使用互斥量)。


2.1.4 常见问题解决

1. 擦除失败(返回EF_ERASE_ERR)
  • 检查Flash地址是否越界(如超出64KB)。
  • 确认 FLASH_PAGE_SIZE 是否正确(部分STM32F103型号为2KB)。
2. 写入数据异常
  • 确保写入前已擦除对应页。
  • 检查写入地址是否按4字节对齐。
3. EasyFlash初始化失败
  • 确认 ef_port.c 中的驱动函数是否实现完整。
  • 检查 ef_cfg.h 中的参数配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

智驾

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

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

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

打赏作者

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

抵扣说明:

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

余额充值