EasyFlash
感谢作者的分享https://github.com/armink/EasyFlash
EasyFlash是一款开源的轻量级嵌入式Flash存储器库,方便开发者更加轻松的实现基于Flash存储器的常见应用开发
三大实用功能
- ENV快速保存产品参数(key-value),支持 写平衡(磨损平衡) 及 掉电保护 功能
EasyFlash不仅能够实现对产品的 设定参数 或 运行日志 等信息的掉电保存功能,还封装了简洁的 增加、删除、修改及查询 方法, 降低了开发者对产品参数的处理难度,也保证了产品在后期升级时拥有更好的扩展性。让Flash变为NoSQL(非关系型数据库)模型的小型键值(Key-Value)存储数据库。
- IAP 在线升级再也不是难事儿
该库封装了IAP(In-Application Programming)功能常用的接口,支持CRC32校验,同时支持Bootloader及Application的升级。
- Log 无需文件系统,日志可直接存储在Flash上
移植
下载源码
https://github.com/armink/EasyFlash
https://gitee.com/Armink/EasyFlash
复制源码
添加源码至工程
配置文件参考stm32f103中的配置文件和接口文件
添加头文件
…\middle\easyflash\inc
修改配置文件
#ifndef EF_CFG_H_
#define EF_CFG_H_
#include "n32l40x.h"
/* 使用 ENV 功能 默认NG using ENV function, default is NG (Next Generation) mode start from V4.0 */
#define EF_USING_ENV
/* 使用 IAP 功能 using IAP function */
//#define EF_USING_IAP
/* using save log function */
/* #define EF_USING_LOG */
/* stm32 的扇区大小 page size for stm32 flash */
#if defined(STM32F10X_LD) || defined(STM32F10X_LD_VL) || defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)
#define PAGE_SIZE 1024
#else
#define PAGE_SIZE 2048 //N32L406=>2K
#endif
/* 最小的擦除大小 the minimum size of flash erasure */
#define EF_ERASE_MIN_SIZE PAGE_SIZE /* it is one page for STM3210x */
/* 闪存写入粒度,单位:位 the flash write granularity, unit: bit
* only support 1(nor flash)/ 8(stm32f4)/ 32(stm32f1)/ 64(stm32l4) */
#define EF_WRITE_GRAN 32
/* The size of read_env and continue_ff_addr function used*/
#define EF_READ_BUF_SIZE 32 /* @default 32, 较大的数字可以提高alloc_env的首次速度,但需要更多的堆栈空间Larger numbers can improve first-time speed of alloc_env but require more stack space*/
/*
*
* This all Backup Area Flash storage index. All used flash area configure is under here.
* |----------------------------| Storage Size
* | Environment variables area | ENV area size @see ENV_AREA_SIZE
* |----------------------------|
* | Saved log area | Log area size @see LOG_AREA_SIZE
* |----------------------------|
* |(IAP)Downloaded application | IAP already downloaded application, unfixed size
* |----------------------------|
*
* @note all area sizes must be aligned with EF_ERASE_MIN_SIZE
*
* The EasyFlash add the NG (Next Generation) mode start from V4.0. All old mode before V4.0, called LEGACY mode.
*
* - NG (Next Generation) mode is default mode from V4.0. It's easy to settings, only defined the ENV_AREA_SIZE.
* - The LEGACY mode has been DEPRECATED. It is NOT RECOMMENDED to continue using.
* Beacuse it will use ram to buffer the ENV and spend more flash erase times.
* If you want use it please using the V3.X version.
*/
/* 备份区域起始地址 backup area start address N32L406MB 128K 24K*/
#define EF_START_ADDR (FLASH_BASE + 100 * 1024) /* from the chip position: 100KB */
/* ENV区域大小。GC至少有一个空扇区。因此,它的定义必须大于或等于2个闪存扇区大小 ENV area size. It's at least one empty sector for GC. So it's definination must more then or equal 2 flash sector size. */
#define ENV_AREA_SIZE (10 * EF_ERASE_MIN_SIZE) /* 8K */
/* saved log area size */
/* #define LOG_AREA_SIZE (10 * EF_ERASE_MIN_SIZE)*/ /* 20K */
/* 输出调试信息 print debug information of flash */
#define PRINT_DEBUG //自定义调试答应函数
#endif /* EF_CFG_H_ */
实现接口文件
本实验是基于国民技术的N32L406
#include <easyflash.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "elog.h"/* 默认的环境变量设置default environment variables set for user */
static const ef_env default_env_set[] = {
{"iap_need_copy_app","0"},
{"iap_copy_app_size","0"},
{"stop_in_bootloader","0"},
{"device_id","1"},
{"boot_times","0"},
};
/**
* Flash port for hardware initialize.
*
* @param default_env default ENV set for user
* @param default_env_size default ENV size
*
* @return result
*/
EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size) {
EfErrCode result = EF_NO_ERR;
*default_env = default_env_set;
*default_env_size = sizeof(default_env_set) / sizeof(default_env_set[0]);
//时钟初始化
if(FLASH_HSICLOCK_DISABLE == FLASH_ClockInit())
{
printf("HSI oscillator not yet ready\r\n");
while(1);
}
return result;
}
/**
* Read data from flash.
* @note This operation's units is word.
*
* @param addr flash address
* @param buf buffer to store read data
* @param size read bytes size这里大小是字节
*
* @return result
*/
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {
EfErrCode result = EF_NO_ERR;
uint8_t *buf_8 = (uint8_t *)buf;
size_t i;
/*copy from flash to ram */
for (i = 0; i < size; i++, addr ++, buf_8++) {
*buf_8 = *(uint8_t *) addr;
}
return result;
}
/**
* Erase data on flash.
* @note This operation is irreversible.
* @note This operation's units is different which on many chips.
*
* @param addr flash address flash地址
* @param size erase bytes size 这里大小是字节
*
* @return result
*/
EfErrCode ef_port_erase(uint32_t addr, size_t size) {
EfErrCode result = EF_NO_ERR;
// FLASH_Status flash_status;
// size_t erase_pages, i;
//
// /* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */
// EF_ASSERT(addr % EF_ERASE_MIN_SIZE == 0);
//
// /* calculate pages */
// erase_pages = size / PAGE_SIZE;
// if (size % PAGE_SIZE != 0) {
// erase_pages++;
// }
// /* start erase */
// FLASH_Unlock();
// FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
// for (i = 0; i < erase_pages; i++) {
// flash_status = FLASH_ErasePage(addr + (PAGE_SIZE * i));
// if (flash_status != FLASH_COMPLETE) {
// result = EF_ERASE_ERR;
// break;
// }
// }
// FLASH_Lock();
/* 解锁*/
FLASH_Unlock();
/* 擦除 */
if (FLASH_COMPL != FLASH_EraseOnePage(addr))
{
while(1)
{
printf("Flash EraseOnePage Error. Please Deal With This Error Promptly\r\n");
}
}
//加锁
FLASH_Lock();
return result;
}
/**
* Write data to flash.
* @note This operation's units is word.
* @note This operation must after erase. @see flash_erase.
*
* @param addr flash address
* @param buf the write data buffer
* @param size write bytes size
*
* @return result
*/
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
EfErrCode result = EF_NO_ERR;
size_t i;
uint32_t read_data;
// FLASH_Unlock();
// FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
// for (i = 0; i < size; i += 4, buf++, addr += 4) {
// /* write data */
// FLASH_ProgramWord(addr, *buf);
// read_data = *(uint32_t *)addr;
// /* check data */
// if (read_data != *buf) {
// result = EF_WRITE_ERR;
// break;
// }
// }
// FLASH_Lock();
/* 解锁*/
FLASH_Unlock();
/* Program */
for (uint32_t Counter_Num = 0; Counter_Num < size; Counter_Num += 4,buf++)
{
if (FLASH_COMPL != FLASH_ProgramWord(addr + Counter_Num, *buf))
{
while(1)
{
printf("Flash ProgramWord Error. Please Deal With This Error Promptly\r\n");
}
}
}
/* Locks the FLASH Program Erase Controller */
FLASH_Lock();
return result;
}
/**
* lock the ENV ram cache
*/
void ef_port_env_lock(void) {
__disable_irq();
}
/**
* unlock the ENV ram cache
*/
void ef_port_env_unlock(void) {
__enable_irq();
}
static char log_buf[128];
/**
* This function is print flash debug info.
*
* @param file the file which has call this function
* @param line the line number which has call this function
* @param format output format
* @param ... args
*
*/
void ef_log_debug(const char *file, const long line, const char *format, ...) {
#ifdef PRINT_DEBUG
va_list args;
/* args point to the first variable parameter */
va_start(args, format);
/* must use vprintf to print */
vsprintf(log_buf, format, args);
log_d("[easyflash]:%s", log_buf);
// printf("\r");
va_end(args);
#endif
}
/**
* This function is print flash routine info.
*
* @param format output format
* @param ... args
*/
void ef_log_info(const char *format, ...) {
va_list args;
/* args point to the first variable parameter */
va_start(args, format);
/* must use vprintf to print */
vsprintf(log_buf, format, args);
log_i("[easyflash]:%s", log_buf);
// printf("\r");
va_end(args);
}
/**
* This function is print flash non-package info.
*
* @param format output format
* @param ... args
*/
void ef_print(const char *format, ...) {
va_list args;
/* args point to the first variable parameter */
va_start(args, format);
/* must use vprintf to print */
vsprintf(log_buf, format, args);
log_v("%s\r\n", log_buf);
va_end(args);
}
添加测试代码
这里的第一步就是初始化easyflash_init
void easyflash_demo(void)
{
if (easyflash_init() == EF_NO_ERR)
{
uint32_t i_boot_times = NULL;
char *c_old_boot_times, c_new_boot_times[11] = {0};
/* 从Env获取启动次数(boot_times) */
c_old_boot_times = ef_get_env("boot_times");
assert_param(c_old_boot_times);
i_boot_times = atol(c_old_boot_times);
/* 启动次数 +1 */
i_boot_times ++;
log_v("The system now boot %d times\n\r", i_boot_times);
/* 格式化一个字符串 */
sprintf(c_new_boot_times,"%d", i_boot_times);
/* 设置启动次数*/
ef_set_env("boot_times", c_new_boot_times);
//保存
ef_save_env();
}
}
磨损平衡)
blob 数据类型的保存和读取测试
/**blob 数据类型的保存和读取测试*/
char buff[10];
memset(buff,0,10);
if(i_boot_times&1)
{
int save_len;
ef_get_env_blob("blob",buff,10,&save_len);
elog_hexdump("blob ",10,buff,10);
}
else{
for(int i=0;i<10;i++)
{
buff[i]=i_boot_times&0xff;
}
ef_set_env_blob("blob",buff,10);
}
标签:N32L406MB,FLASH,EasyFlash,EF,flash,value,times,env,size
From: https://blog.csdn.net/u010261063/article/details/140827152