STM32F1 使用easyflash操作片内flash

STM32F1 使用easyflash操作片内flash

  • 简介
    • https://github.com/armink/EasyFlash
    • 移植文件
    • 配置文件
      • 根据flash配置`ef_cfg.h`文件
      • ef_port.c文件配置
    • 测试

简介

easyflash版本:4.10

https://github.com/armink/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存储功能。

移植文件

复制下面的文件到工程中

easyflash/src/easyflash.c
easyflash/src/ef_env.c
easyflash/src/ef_utils.c
easyflash/port/ef_port.c
EasyFlash-4.1.0\easyflash\inc中的头文件

配置文件

根据flash配置ef_cfg.h文件

#define EF_ENV_VER_NUM    (0)        /* @note you must define it for a value, such as 0 */
 
/* MCU Endian Configuration, default is Little Endian Order.*/
/* #define EF_BIG_ENDIAN  */         

#endif /* EF_USING_ENV */

/* using IAP function */
/* #define EF_USING_IAP */

/* using save log function */
/* #define EF_USING_LOG */

/* The minimum size of flash erasure. May be a flash sector size. */
#define EF_ERASE_MIN_SIZE   (2048)      /* @note you must define it for a value */
/*FLASH_PAGE_SIZE 为0x800, 就是2048*/
/* the flash write granularity, unit: bit
 * only support 1(nor flash)/ 8(stm32f4)/ 32(stm32f1) */
#define EF_WRITE_GRAN   (32)          /* @note you must define it for a value */

/*
 *
 * 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 */
#define EF_START_ADDR   (64 * EF_ERASE_MIN_SIZE + 0x08000000)          /* @note you must define it for a value */

/* ENV area size. It's at least one empty sector for GC. So it's definition must more then or equal 2 flash sector size. */
#define ENV_AREA_SIZE   (2 * EF_ERASE_MIN_SIZE)          /* @note you must define it for a value if you used ENV */

/* saved log area size */
#define LOG_AREA_SIZE   (10 * EF_ERASE_MIN_SIZE)          /* @note you must define it for a value if you used log */

/* print debug information of flash */
#define PRINT_DEBUG

ef_port.c文件配置

主要实现一下几个函数的接口

ef_port_init(如果使用FAL, 则需要配置,本例程不需要配置)
ef_port_read
ef_port_erase
ef_port_write

1.添加头文件, 在最上面添加#include "main.h"
完善default_env_set

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

2.添加读函数

EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {
    EfErrCode result = EF_NO_ERR;

    /* You can add your code under here. */
    uint8_t *buf_8 = (uint8_t *)buf;
    size_t i;
    for (i = 0; i < size; i++, addr++, buf_8++)
    {
    	*buf_8 = *(uint8_t *) addr;
    }
    return result;
}

3.添加擦除函数

EfErrCode ef_port_erase(uint32_t addr, size_t size) {
    EfErrCode result = EF_NO_ERR;

    /* make sure the start address is a multiple of EF_ERASE_MIN_SIZE */
    EF_ASSERT(addr % EF_ERASE_MIN_SIZE == 0);

    /* You can add your code under here. */
    HAL_FLASH_Unlock();

    /* 擦除FLASH*/
    FLASH_EraseInitTypeDef FlashSet;
    FlashSet.TypeErase = FLASH_TYPEERASE_PAGES;
    FlashSet.PageAddress = addr;
    FlashSet.NbPages = (size + EF_ERASE_MIN_SIZE -1)/ EF_ERASE_MIN_SIZE;

    /*设置PageError,调用擦除函数*/
    uint32_t PageError = 0;
    HAL_FLASHEx_Erase(&FlashSet, &PageError);

    HAL_FLASH_Lock();
    return result;
}

4.添加读函数

EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
    EfErrCode result = EF_NO_ERR;
    
    /* You can add your code under here. */
    size_t i;
    uint32_t read_data;

    HAL_FLASH_Unlock();
    for (i = 0; i < size; i += 4, buf++, addr += 4)
    {
    	/* write data */
    	HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, *buf);
    	read_data = *(uint32_t *)addr;
    	/* check data */
    	if (read_data != *buf)
    	{
    		result = EF_WRITE_ERR;
    		break;
    	}
    }
    HAL_FLASH_Lock();

    return result;
}

测试

 /* USER CODE BEGIN 2 */

  int i = 0;
  typedef struct {
	  uint16_t lux;
	  uint16_t arc;
  }lux_arc_t;

  lux_arc_t lux_arc[5];

  for (i = 0; i < 5; ++i)
  {
	  lux_arc[i].arc = i + 120;
	  lux_arc[i].lux = 10 * i + 134;
  }

  unsigned int Reboot_Time = 0;
  char str[30] = "hello word";
  char ptr[30];
  if(easyflash_init() == EF_NO_ERR)                         // 初始化成功
  {
	  ef_get_env_blob("boot_times", &Reboot_Time, 8, NULL);  // 读出reboot_time的值
  }
  Reboot_Time++;                                            // reboot_time的值加1

/*存储结构体也可以*/
  ef_set_env_blob("stop_in_bootloader", lux_arc, 5 * sizeof(lux_arc_t));
  ef_set_env_blob("iap_need_copy_app", str, strlen(str));
  ef_set_env_blob("iap_copy_app_size", "我是中国人", strlen("我是中国人"));
  memset(str, 0, sizeof(str));
  memset(lux_arc, 0, sizeof(lux_arc));
  ef_set_env_blob("boot_times", &Reboot_Time, 8);            // 保存reboot_time的值
  ef_get_env_blob("iap_need_copy_app", ptr, 30, NULL);
  ef_get_env_blob("iap_copy_app_size", str, 30, NULL);
  ef_get_env_blob("stop_in_bootloader", lux_arc, 5 * sizeof(lux_arc_t), NULL);
  snprintf(buf, 128, "Reboot_Time is %d, %s, %s, arc:%d, lux:%d\r\n",Reboot_Time,
		  ptr, str, lux_arc[2].arc, lux_arc[2].lux);                // 打印reboot_time的值
  HAL_UART_Transmit(&huart1, (uint8_t*)buf, strlen(buf), 10);
  /* USER CODE END 2 */

你可能感兴趣的:(stm32,stm32)