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

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

1. 设计思路

  • 芯片:STM32F103ZET6

  • 软件:STM32CubeHAL

  • Flash Page Size:2K

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

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

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

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

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

2. 实现代码

一共有3个文件,flash_wear_leveling.h、flash_wear_leveling.c和example.c,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擦除,
 * 当然你需要先调用flash_init()函数设置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]);
}

上一篇:国产哈希算法WJLHA1.0.1的JAVA源码,是否强过MD5、SHA、SM3?欢迎来测!


下一篇:【JAVA】IO FileInputStream 读取二进制文件