C语言循环读写Flash

目录

一、循环读写 flash 的相关接口和实现

二、如何使用


一、循环读写 flash 的相关接口和实现

1、FlashCycle.h 头文件

/* FlashCycle.h */
#ifndef __FLASH_CYCLE_H_
#define __FLASH_CYCLE_H_


#include "sys.h"
#include "Generaldef.h"
#include "flash.h"


//一个扇区的大小
#define FLASH_CYCLE_SECTOR_SIZE		(uint32_t)(2*1024)

//写入数据的密码
#define FC_SYSTEM_PATA_PSW		    0x4

//系统参数存储扇区,flash的最后一个扇区
#define FC_SYSTEM_PATA_ADDR  	    ((u32)FLASH_BASE+255*FLASH_CYCLE_SECTOR_SIZE)   

typedef struct 
{
	uint16_t psw;
	uint32_t startAddr;
	uint32_t size;
}FcDataType;

void Flash_InitCycle(FcDataType *FcData, uint16_t psw, uint32_t startAddr, uint32_t size);
BOOL Flash_ReadCycle(const FcDataType *FcData, uint8_t *rBuff);
BOOL Flash_WriteCycle(const FcDataType *FcData, const uint8_t *wBuff);


extern FcDataType FcSysData;

#endif

2、FlashCycle.c 文件

/* FlashCycle.c */
#include "FlashCycle.h"
#include <string.h>
#include <stdlib.h>

FcDataType FcSysData;

//擦除后FLASH状态,F系列为FFFF,L系列为0000
#define FC_RESET_HALF_WORD		0xFFFF



/**********************************************************************
* @brief 初始化一个数据结构
* @param FcData-数据结构存储
* @param psw-数据结构对应密码,如果密码被更改,用户数据将会被擦除永久丢失。
* @param startAddr-起始写入地址,最好是最小擦除单位首地址
* @param size-数据结构大小,建议适当增大,为后面增加参数预留位置
***********************************************************************/
void Flash_InitCycle(FcDataType *FcData, uint16_t psw, uint32_t startAddr, uint32_t size)
{
	if(FcData==0 || psw==0 || psw==0xFFFF 
		|| startAddr<FLASH_BASE || startAddr>FLASH_END || size==0) return; 

	FcData->psw=psw;
	FcData->startAddr = startAddr;
	FcData->size=size;
}


/************************************************************
* @brief 写入数据到flash块中
* @param FcData-数据结构存储
* @param wBuff-需要写入的数据
* @retur 是否写入成功
**************************************************************/
BOOL Flash_WriteCycle(const FcDataType *FcData, const uint8_t *wBuff)
{
	BOOL ret=FALSE;
	if(FcData==0 || wBuff==0) return ret;

	//密码一起写入
	uint32_t rlen=FcData->size+2;

	//数据存储四字节对齐
	uint32_t len=0,wlen=rlen%4==0? rlen/4:rlen/4+1;

	//每个数据块对应总字节数
	uint32_t blen=4*wlen;

	//申请一段内存,把密码也写入,用完之后要记得 free() 释放掉内存
	uint8_t *buff = malloc(blen);
	if(buff== 0) return ret;
	
	*(uint16_t *)buff = FcData->psw; 
	
	memcpy(&buff[2], wBuff, FcData->size);

   //遍历整个扇区,第一个密码为0xFFFF就是空区域,将数据写入。
	while(1)
	{
		uint16_t psw=*(vu16 *)(FcData->startAddr+len);  //直接取出flash中的值

		//扇区写完了,或者出现了别的数据  不是规定的密码0x03  或者0xffff
		if(len+blen > FLASH_CYCLE_SECTOR_SIZE || (FcData->psw!=psw && psw!=0xFFFF))
		{
			//擦除扇区需要时间,注意延长看门狗时间
			fmc_erase_pages(FcData->startAddr, 1);

            //在第一个区域写入
			fmc_program(FcData->startAddr, (const uint32_t *)buff, wlen);
			ret=TRUE;
			break;
		}
		//第一个空区域,写入数据
		else if(psw == 0xFFFF)
		{
			fmc_program(FcData->startAddr+len, (const uint32_t *)buff, wlen);
			ret=TRUE;
			break;
		}
        //密码正确,这里以已经写过数据,进入下一个区域
		else if(psw == FcData->psw) 
		{
			len+=blen;
		}
	}

	free(buff);

	return ret;
}


/***************************************************************
* @brief 在一段flash块中,读出最新存储的数据
* @param FcData-数据结构存储
* @param rBuff-读出缓存,将读出的数据放入这里
* @retur 是否读出成功
****************************************************************/
BOOL Flash_ReadCycle(const FcDataType *FcData, uint8_t *rBuff)
{
	BOOL ret=FALSE;
	if(FcData==0 || rBuff==0) return ret;

	//数据里包含密码
	uint32_t rlen=FcData->size+2;

	//数据存储四字节对齐
	uint32_t len=0, wlen=rlen%4==0 ? rlen/4:rlen/4+1;

	//每个数据块对应总字节数
	uint32_t blen=4*wlen;

    //遍历整个扇区,第一个密码为0xFFFF或最后一个区域就是最后写入的数据
	while(1)
	{
		uint16_t psw=*(vu16 *)(FcData->startAddr+len);
		
        //密码为0xFFFF,这个区域没有被写入数据,或者已经达到扇区末尾,说明前一个扇区就是最后写入的数据
		if(len+blen > FLASH_CYCLE_SECTOR_SIZE || psw==0xFFFF)
		{
            //第一个扇区,说明之前没有任何数据写入,不读取任何数据
			if(len==0) break;
			//返回上个区域,读出数据
			else
			{
				len-=blen;
				//写入的数据前2位是密码,不需要读出
				fmc_read(FcData->startAddr+len+2, rBuff, FcData->size);
				ret=TRUE;
				break;
			}
		}
		//密码正确,进入下一个区域
		else if(psw == FcData->psw)
        {
            len+=blen;
        }
        //有别的数据(数据段非空,且密码不正确),不做任何操作
		else
		{
			break;
		}
		
	}

	return ret;
}

二、如何使用

1、初始化

/*在初始化的地方调用
 *1、FC_SYSTEM_PATA_PSW:密码,一般不会随意更改;
 *2、254:每次写入的字节数,还不包括密码的长度;
 */
Flash_InitCycle(&FcSysData, FC_SYSTEM_PATA_PSW, FC_SYSTEM_PATA_ADDR, 254);
	

2、循环写

//在需要保存的地方调用,比如掉电,修改某些参数之后
void  WeitrAllParaToFlash(void)
{    		
	  memset(TempBuff,0,sizeof(TempBuff));

      //SysRunPara.FalshPara,要写入的结构体数据
	  memcpy(TempBuff,&SysRunPara.FalshPara,sizeof(SysRunPara.FalshPara));

	  if(Flash_WriteCycle(&FcSysData, TempBuff) == FALSE)
	  { 
	 	 Log_Printf("write error\r\n"); 
	  }							
}

3、循环读


u8  BuffPointer[254]; //保存从 flash 读出的数据

void  ReadAllParaFromFlash(void)
{ 	
	 memset(BuffPointer,0,sizeof(BuffPointer));	
	
	 if(Flash_ReadCycle(&FcSysData, BuffPointer))
	 {		 	 
		Log_Printf("\r\nread success\r\n");
	 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值