找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1132

积分

0

好友

164

主题
发表于 14 小时前 | 查看: 2| 回复: 0

一、开发环境

  • 开发板:STM32F407ZG
  • RT-Thread版本:V4.1.0

二、EasyFlash软件包介绍

EasyFlash是一款开源的轻量级嵌入式Flash存储器库,旨在简化基于Flash存储器的应用开发。它特别适用于智能家居、可穿戴设备、工控、医疗及物联网等需要断电存储功能的场景,具有资源占用低、支持多种MCU片上存储器的特点。

该库主要集成了三大核心功能:

  1. ENV(环境变量):快速保存产品参数,支持写平衡(磨损平衡)掉电保护。它不仅能够可靠地保存系统设定参数或运行日志,还提供了简洁的增、删、改、查接口,极大地降低了对产品参数的管理复杂度,并为产品后期升级提供了良好的扩展性。可以说,它将Flash变成了一个类似NoSQL(非关系型数据库)模型的轻量级键值(Key-Value)存储数据库

  2. IAP(在应用编程):封装了IAP功能常用的接口,支持CRC32校验,可同时用于Bootloader和Application的固件升级,让在线升级变得简单可靠。在嵌入式开发中,数据传输的完整性和可靠性至关重要,这涉及到诸如网络/系统层面的校验思想。

  3. Log(日志存储):无需文件系统支持,即可直接将日志顺序存储到Flash中。这对于不带文件系统的小型设备非常实用,能帮助开发者快速定位系统崩溃或死机的原因。它可以与EasyLogger(一个超轻量级、高性能的C日志库)无缝配合,轻松实现日志的Flash存储功能。

三、移植概述

本文基于RT-Thread进行EasyFlash的移植。EasyFlash主要适配以下两种底层Flash驱动方案:

  • FAL (Flash抽象层)
  • SFUD (串行Flash通用驱动库)

如果你的项目已使用上述驱动之一,那么移植过程将非常简便。若未使用,请参考EasyFlash官方提供的移植文档。官方仓库中也提供了丰富的Demo可供参考。

本例将基于FAL (Flash抽象层)进行移植,并使用STM32的片上Flash。

四、详细配置步骤

4.1 FAL配置与测试

首先,需要在RT-Thread Env工具或Menuconfig中启用FAL组件。

  1. 开启FAL软件包。
    开启FAL配置
    开启FAL调试日志
  2. 开启片上Flash驱动。
    开启片上Flash
  3. 修改fal_cfg.h文件。此文件通常位于\board\ports目录下。关键修改是为EasyFlash指定专用的存储分区。
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#ifdef BSP_USING_SPI_FLASH_LITTLEFS
...
#else
#define FAL_PART_TABLE                                                                                                 \
{                                                                                                                      \
    {FAL_PART_MAGIC_WROD, "easyflash",        "onchip_flash_128k", 1* 128 * 1024 , 2* 128 * 1024, 0}, \
}
// 注意:2*128*1024 定义了ENV存储区大小。必须至少包含一个空闲扇区用于垃圾回收(GC),因此其大小必须大于或等于2个Flash扇区。
#endif
#endif /* FAL_PART_HAS_TABLE_CFG */

4.2 EasyFlash (V4.1.0) 配置

在配置工具中开启EasyFlash软件包。
开启EasyFlash

主要配置项说明:

  1. ENV: 使能环境变量功能。
    1.1 Auto update ENV: 环境变量版本号改变时自动更新。
    1.2 ENV version number: 设置当前环境变量版本号。
  2. LOG: 使能日志存储功能,可将日志保存至Flash。
  3. IAP: 使能在线升级功能。
  4. Erase granularity: 擦除最小粒度,STM32F4片内Flash通常为128KB。
  5. Write granularity: 写入最小粒度,STM32F4通常为8bit。
  6. Start addr: EasyFlash存储区的起始偏移地址。
  7. Debug log: 使能调试日志输出。

修改ef_fal_port.c文件,确保分区名称与fal_cfg.h中定义的一致:

/* EasyFlash partition name on FAL partition table */
#define FAL_EF_PART_NAME    "easyflash"

五、测试代码与验证

以下测试代码演示了如何使用EasyFlash进行不同类型环境变量的读写操作,并在RT-Thread这个实时操作系统中运行。

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <stdlib.h>
#include <fal.h>
#include <easyflash.h>

/* defined the LED0 pin: PC3 */
#define LED0_PIN    GET_PIN(C, 3)

static void easyflash_test(void)
{
    EfErrCode err;
    char str_value[127]={0};
    int int_val = 0;
    float float_val = 0.0f;

    // 1. 初始化EasyFlash
    err = easyflash_init();
    if (err != EF_NO_ERR)
    {
        rt_kprintf("EasyFlash init err, code is:%d\r\n", err);
        return;
    }
    rt_kprintf("EasyFlash init ok!\r\n");

    rt_kprintf("\r\n******************************\r\n");
    rt_kprintf("ef_print_env 1\r\n");
    ef_print_env(); // 打印当前所有环境变量
    rt_kprintf("\r\n******************************\r\n");

    // 2. 测试字符串类型KV
    const char *kv_str_key = "user_name";
    const char *kv_str_def = "rt-thread";
    char *kv_str_value = RT_NULL;

    if ( (kv_str_value=ef_get_env(kv_str_key)) == NULL)
    {
        rt_kprintf("KV[%s], write: %s\r\n", kv_str_key, kv_str_def);
        ef_set_env_blob(kv_str_key, kv_str_def, rt_strlen(kv_str_def));
    }
    else
    {
        rt_kprintf("read KV[%s]: %s\r\n", kv_str_key, kv_str_value);
    }

    // 3. 测试整数类型KV
    const char *kv_int_key = "device_id";
    int kv_int_def = 123456;
    rt_memset(str_value,0,sizeof(str_value));
    if( ef_get_env_blob(kv_int_key, str_value, sizeof(str_value) , NULL) == 0)
    {
        rt_kprintf("KV[%s], write: %d\r\n", kv_int_key, kv_int_def);
        rt_sprintf(str_value,"%d",kv_int_def);
        ef_set_env_blob(kv_int_key, str_value, rt_strlen(str_value) );
    }
    else
    {
        rt_kprintf("read KV[%s]: %d\r\n", kv_int_key, int_val=atoi(str_value));
        // 修改并重新写入
        int_val += 1;
        rt_kprintf("write KV[%s]: %d\r\n", kv_int_key, int_val);
        rt_memset(str_value,0,sizeof(str_value));
        rt_sprintf(str_value,"%d",int_val);
        ef_set_env_blob(kv_int_key, str_value, rt_strlen(str_value) );
    }

    // 4. 测试浮点类型KV
    const char *kv_float_key = "temperature";
    float kv_float_def = 3.1f;
    rt_memset(str_value,0,sizeof(str_value));
    if (  ef_get_env_blob(kv_float_key, str_value, sizeof(str_value) , NULL) == 0)
    {
        rt_kprintf("KV[%s], write: 3.14\r\n", kv_float_key);
        rt_sprintf(str_value,"%d.%d",((int)(kv_float_def*100))/100,((int)(kv_float_def*100))%100);
        ef_set_env_blob(kv_float_key, str_value, rt_strlen(str_value) );
    }
    else
    {
        float_val=atof(str_value);
        rt_kprintf("read KV[%s]: %d.%d\r\n", kv_float_key,((int)(float_val*100))/100,((int)(float_val*100))%100);
        // 修改并重新写入
        float_val += 0.1f;
        rt_kprintf("write KV[%s]: %d.%d\r\n", kv_float_key,((int)(float_val*100))/100,((int)(float_val*100))%100);
        rt_memset(str_value,0,sizeof(str_value));
        rt_sprintf(str_value,"%d.%d",((int)(float_val*100))/100,((int)(float_val*100))%100);
        ef_set_env_blob(kv_float_key, str_value, rt_strlen(str_value) );
    }

    rt_kprintf("\r\n******************************\r\n");
    rt_kprintf("ef_print_env 2\r\n");
    ef_print_env();
    rt_kprintf("\r\n******************************\r\n");

    rt_kprintf("EasyFlash test ok\r\n");
}

int main(void)
{
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    fal_init(); // 初始化FAL
    easyflash_test(); // 执行测试

    while (1)
    {
        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
}

将代码编译并下载到设备后,首次运行输出如下:
首次运行输出

重启设备后再次运行,可以看到之前存储的环境变量被正确读出,实现了数据的持久化存储,其功能类似于一个轻量的数据库/中间件
重启后运行输出

参考资源




上一篇:Vue 3在线演示文稿应用PPTist:本地部署与外网访问实战指南
下一篇:edusrc教育系统漏洞深度剖析:IDOR越权与用户枚举漏洞实战挖掘
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 17:29 , Processed in 0.132978 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表