您现在的位置是:首页 >学无止境 >基于flash的数据存储算法实现网站首页学无止境

基于flash的数据存储算法实现

dreamczf 2025-07-25 00:01:05
简介基于flash的数据存储算法实现

背景

        项目中总是会遇到存储数据的需求,当成本没有限制时,可以用考虑在项目中使用铁电来实现存储需求,但如果资源有限,成本要求更低,存储数据很少也比较单一的情况下,可以使用flash来实现,MCU内部的flash,或者外部的nor flash都可以。下面介绍一个我在项目中实现的案例。用低功耗单片机实现采集脉冲信号,通过LoRa将数据传输出去,采集的信号需要保存下来,使用了小华的HC32L110芯片,TSSOP20的封装,16个可用管脚,还有一路RS485,具体可以看看《无线传输终端(LoRa DTU)》中的介绍,这块只说说关于数据存储部分。

技术介绍

        铁电存储器(Ferroelectric RAM,FRAM),具有低功耗,读写次数没限制,数据保存十年的特性,非常适合嵌入式场景下,需要存储数据的要求,缺点是,容量小,价格贵。

        Nor Flash,也具有低功耗,读写次数可到十万次,数据也可以长久保存,支持按位写入,但只能将数据1变为0,如果要将0变为需要整个扇区进行擦除操作。

        nand flash,在嵌入式系统基于MCU的开发很少使用,需要MCU管理坏块,需要占用一些资源,存储量也比较大,MCU场景一般没有太多的数据要进行存储。

        当前环境下,MCU内部集成的程序存储器基本都换成了Nor Flash,所以项目中可以使用MCU内部的Nor flash来实现数据的存储。

算法介绍

        基于笑话的HC32L110单片机,内部集成32K的Flash,将最后两个扇区用来存储脉冲总数信息。

  • 累计脉冲数为32位的无符号整数,占用4个字节空间;
  • HC32L110的单个扇区位512个字节;
  • 使用扇区结尾的16个字节,16*8=128个bit位来表示后面128个位置的存储信息,0表示已存储信息,1表示未使用;
  • 每个存储位置为4个字节的无符号整数,4*128=512个字节,超出了单个扇区的大小,所以有效存储个数为124个,124*4+16=512个字节。
  • 使用最后两个扇区来实现数据的交替存储。

序号

字节序

含义

1

0~495

每四个字节表示一个数据,总共124个整数,496个字节

2

496~511

bit位表示位图,0表示数据已写入,1表示数据尚未写入,124个bit位,15.5个字节,取整是16个字节

#define BIT_MAP_ADD		    496
#define BIT_MAP_SIZE		16
#define DATA_SIZE	    	124


typedef union {
	uint32_t u32_byte[BIT_MAP_SIZE/4];
}bit_map_u;

typedef struct {
	uint32_t port;
	bit_map_u bit;
	uint32_t cur;
}bit_map_s;

int32_t bit_map_init(bit_map_s *bit_map);
int32_t bit_map_read(bit_map_s *bit_map,uint32_t addres,uint32_t *p_data);
int32_t bit_map_read_cur(bit_map_s *bit_map,uint32_t *p_data);
int32_t bit_map_write(bit_map_s *bit_map,uint32_t data);
int32_t bit_map_erase(bit_map_s *bit_map);

代码实现:


#include "flash_bit_data.h"
#include <stdio.h>
#include "hal_flash.h"

#define FLASH_ADD_1		0x7A00
#define FLASH_ADD_2		0x7C00
int32_t bit_map_init(bit_map_s *bit_map)
{
	int32_t ret = -1; 
	uint32_t i = 0;
	
	if(bit_map == NULL){
		return ret;
	}
	
	switch(bit_map->port){
	case 0:
		flash_multi_read(FLASH_ADD_1 + BIT_MAP_ADD,bit_map->bit.u32_byte,BIT_MAP_SIZE);
		break;
	
	case 1:
		flash_multi_read(FLASH_ADD_2 + BIT_MAP_ADD,bit_map->bit.u32_byte,BIT_MAP_SIZE);
		break;
	
	default:
		break;
	}
	for(i = 0;i < BIT_MAP_SIZE;i++){
		switch(bit_map->bit.byte[i]){
		case 0xFF:
			bit_map->cur = i*8;
			break;
		
		case 0xFE:
			bit_map->cur = i*8 + 1;
			break;
		
		case 0xFC:
			bit_map->cur = i*8 + 2;
			break;
		
		case 0xF8:
			bit_map->cur = i*8 + 3;
			break;
		
		case 0xF0:
			bit_map->cur = i*8 + 4;
			break;
		
		case 0xE0:
			bit_map->cur = i*8 + 5;
			break;
		
		case 0xC0:
			bit_map->cur = i*8 + 6;
			break;
		
		case 0x80:
			bit_map->cur = i*8 + 7;
			break;
		
		case 0x00:
			bit_map->cur = i*8 + 8;
			break;
		
		default:
			return ret;
		
		}
		if(bit_map->bit.byte[i] != 0){
			break;
		}
	}
	
	ret = 0;
	
	return ret;
}

int32_t bit_map_read(bit_map_s *bit_map,uint32_t addres,uint32_t *p_data)
{
	int32_t ret = -1; 
	uint32_t addr_temp = 0;
	
	if((bit_map == NULL) || (addres >= DATA_SIZE)){
		return ret;
	}
	
	switch(bit_map->port){
	case 0:
		addr_temp = FLASH_ADD_1;
		break;
	
	case 1:
		addr_temp = FLASH_ADD_2;
		break;
	
	default:
		break;
	}
	flash_multi_read(addr_temp + addres*4,p_data,4);
	
	return 0;
}

int32_t bit_map_read_cur(bit_map_s *bit_map,uint32_t *p_data)
{
	int32_t ret = -1; 
	uint32_t addr_temp = 0;
	
	if((bit_map == NULL) || (bit_map->cur >= DATA_SIZE)){
		return ret;
	}
	
	switch(bit_map->port){
	case 0:
		addr_temp = FLASH_ADD_1;
		break;
	
	case 1:
		addr_temp = FLASH_ADD_2;
		break;
	
	default:
		break;
	}
	flash_multi_read(addr_temp + (bit_map->cur - 1)*4,p_data,4);
	
	return 0;
}
int32_t bit_map_write(bit_map_s *bit_map,uint32_t data)
{
	int32_t ret = -1; 
	int32_t i = 0;
	uint32_t addr_temp = 0;
	
	if((bit_map == NULL) || (bit_map->cur >= DATA_SIZE)){
		return ret;
	}
	
	if(bit_map->cur >= DATA_SIZE){
		ret = -2;
		return ret;
	}
	
	switch(bit_map->port){
	case 0:
		addr_temp = FLASH_ADD_1;
		break;
	
	case 1:
		addr_temp = FLASH_ADD_2;
		break;
	
	default:
		break;
	}
	i = bit_map->cur%8;
	bit_map->bit.byte[bit_map->cur/8] = (~(1<<i)) & bit_map->bit.byte[bit_map->cur/8];
	flash_multi_bprog(addr_temp + BIT_MAP_ADD + bit_map->cur/8,&bit_map->bit.byte[bit_map->cur/8],1);
	flash_multi_wprog(addr_temp + bit_map->cur*4,&data,4);
	bit_map->cur++;
	ret = 0;
	
	return ret;
}

int32_t bit_map_erase(bit_map_s *bit_map)
{
	int32_t ret = -1; 
	uint32_t addr_temp = 0;
	
	if(bit_map == NULL){
		return ret;
	}
	
	switch(bit_map->port){
	case 0:
		addr_temp = FLASH_ADD_1;
		break;
	
	case 1:
		addr_temp = FLASH_ADD_2;
		break;
	
	default:
		break;
	}
	
	flash_ROM_ioctrl(IOCTRL_ROM_ERASE_SECTOR,(uint8_t *)&addr_temp);
	bit_map->cur = 0;
	ret = 0;
	
	return ret;
}


 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。