STM32内部Flash使用磨损均衡算法(Erase Leveling)

STM32内部Flash使用磨损均衡算法(Erase Leveling)

STM32内部Flash的写寿命大约是1万次,假如我们在其Flash中存储数据,每天100次写操作,100天后Flash就无法继续可靠使用了,本文采取了一种非常简单的方法,将Flash的使用寿命延长了1024倍(仅限本文试验环境下)。

1. 设计思路

本实验以一页Flash的操作为例。我们按照特定格式将数据一条一条的写进Flash,在写入新的数据前将旧数据清零,保证Flash中有效数据的唯一性,直到本页写满后,才将本页擦除,故极大的延长了Flash的使用寿命。

  • 芯片:STM32F103ZET6

  • 软件:STM32CubeHAL

  • Flash Page Size:2K

  • 使用Flash的一页Page60(0x0801E000 ~ 0x0801E800(不包含))进行磨损均衡算法试验

  • 数据帧格式:|0x5A|data1|data2|0xA5|

  • 本实验Flash存储模型如下:

flash earse leveling

  • 首先将Page60擦除,擦除后Page60页中的数据全为1。
  • 每次写入数据时,会顺次寻找数值FF(未写入数据的),找到后写入数据,同时将先前的有效数据置为0,若未找到FF,则表明数据已写满,将擦除整页,从头开始写
  • 每次读出数据时,会顺次寻找数值5A(有效数据),然后读出4个字节,若未找到数值5A,则返回错误码0

2. 实现代码

一共有3个文件:

  • flash_wear_leveling.h和flash_wear_leveling.c是磨损均衡算法的实现
  • example.c是使用举例。

直接访问我的Gist获取最新代码

  • flash_wear_leveling.h
#ifndef __FLASH_H__
#define __FLASH_H__

#include "stm32f1xx_hal.h"

#define FLASH_START_ADDRESS 0x0801E000
#define PAGE_SIZE               (uint32_t)FLASH_PAGE_SIZE  /* Page size */

#define WT_GET_NEW_ADDR (1<<0)
#define WT_GET_USED_ADDR (1<<1)

typedef union
{
	uint32_t data;
	uint8_t buff[4];
}flash_pack_u;

typedef struct
{
	uint32_t flash_start_address;
	uint32_t current_addr;
	uint32_t new_addr;
	uint16_t page_size;
	flash_pack_u buff;
}flasher_t;

#define newFlasher(start_address,page_size){ \
		start_address,start_address,start_address,page_size,{0} \
}

typedef union
{
	uint8_t data[2];
	uint16_t data16;
}writer_u;

void flash_init(void);
void easer_flash(void);
void find_new_entry(void);
uint32_t find_used_entry(void);
void write_word_to_flash(writer_u writer);

#endif

  • flash_wear_leveling.c

#include <drv_flash.h>
extern void FLASH_PageErase(uint32_t PageAddress);

static Flasher flasher = newFlasher(FLASH_START_ADDRESS,PAGE_SIZE);

void easer_flash(void)
{
	/* -1- Unlock the Flash Bank Program Erase controller */
	  HAL_FLASH_Unlock();

	  /* -2- Clear All pending flags */
	  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR);

	  /* -3- erase the FLASH pages */
	  FLASH_PageErase(FLASH_START_ADDRESS);
	  FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
	  CLEAR_BIT(FLASH->CR, FLASH_CR_PER);

	  /* -5- Lock the Flash Bank Program Erase controller */
	  HAL_FLASH_Lock();
}


void find_new_entry(void)
{
	while(flasher.current_addr < flasher.flash_start_address+flasher.page_size)
	{
		flasher.buff.data = read_word_from_flash(flasher.current_addr);
		if(flasher.buff.buff[0] == 0xFF)
		{
			flasher.new_addr = flasher.current_addr;
			return;
		}

		flasher.current_addr += 4;
	}

	if(flasher.current_addr >= flasher.flash_start_address+flasher.page_size)
	{
		easer_flash();
		flasher.current_addr = flasher.flash_start_address;
		flasher.new_addr = flasher.flash_start_address;
	}
}

uint32_t find_used_entry(void)
{
	while(flasher.current_addr < flasher.flash_start_address+flasher.page_size)
	{
		flasher.buff.data = read_word_from_flash(flasher.current_addr);
		if(flasher.buff.buff[0] == 0x5A)
		{
			return flasher.buff.data;
		}

		flasher.current_addr += 4;
	}
	return 0;
}

void write_word_to_flash(writer_u writer)
{
	flash_pack_u buf;
	buf.buff[0] = 0x5A;
	buf.buff[1] = writer.data[0];
	buf.buff[2] = writer.data[1];
	buf.buff[3] = 0xA5;

	find_new_entry();

	HAL_FLASH_Unlock();

	if(flasher.new_addr-4 >= flasher.flash_start_address)
	{
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,flasher.new_addr-4,0x00);
	}
	HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,flasher.new_addr,buf.data);

	HAL_FLASH_Lock();
}

  • example.c

/*
 * 首先确保你要操作的的Flash区域是刚擦除过的(全为1),为实现这个目的,你可以只调用easer_flash()函数,将特定的flash page擦除,
 * 数据帧格式为 |0x5A | data1 | data2 | 0xA5|
 * 每次写入数据时,会顺次寻找数值FF(未写入数据的),找到后写入数据,同时将先前的有效数据置为0,若未找到FF,则表明数据已写满,将擦除整页,从头开始写
 * 每次读出数据时,会顺次寻找数值5A(有效数据),然后读出4个字节,若未找到数值5A,则返回错误码0
 * 
 */

int main()
{
  // write data into flash
  writer_u writer;
  writer.data[0] = 0x11;
  writer.data[1] = 0x22;
  write_word_to_flash(writer);

  // then read it from flash and print it
  flash_pack_u flash_pack;
  flash_pack.data = find_used_entry();
  usart1_printf("%x  %x\n",flash_pack.buff[1]);
  usart1_printf("%x  %x\n",flash_pack.buff[2]);
}

  • 16
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值