软件优化Flash擦除时间长的方法

概述:
  通过地址的偏移,巧妙的避开Flash擦除长时间占用CPU的使用。
  MCU-STM32H743,编译环境-Keil
说明:
基础知识可以看:Flash读写 其中包含了本代码涉及到的所有函数。
正文:
  首先要明白Flash擦除需要很长的时间,写用不了多少时间,所以我们可以在写之前执行擦除指令,使Flash在待写状态,这样再写的时候就不会占用大量的CPU时间。下图为H7写Flash时间和擦除Flash的时间,可以看出写都是us级的,而擦除则是s级的。
在这里插入图片描述
思路:
利用Flash的两个扇区进行擦写

//使用Flash的扇区1和扇区2
#define FLASH_SAVE_ADDR  0x08020000//扇区1
#define FLASH_USER_ADDR  0x08040000//扇区2

●FLASH_USER_ADDR 地址处的Flash在程序每次初始化的时候将内容擦除。
●FLASH_SAVE_ADDR 地址处保存FLASH_USER_ADDR 地址擦除前的内容。
  我们每次可以在FLASH_SAVE_ADDR 地址提取数据,在FLASH_USER_ADDR 地址处写数据,这样擦除都在初始化的时候完成,这样写Flash就不会长时间占用CPU的正常运行。

★上电只能写一次Flash代码

uint32_t Flash_UserBuff[8]={0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};
uint32_t Flash_SaveBuff[8]={0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};//保存的数据
int main(void)
{
/*初始化*/
		STMFLASH_Read(FLASH_USER_ADDR,(uint32_t*)Flash_UserBuff,8);//将FLASH_USER_ADDR地址中的数据读出至Flash_UserBuff[]数组中
		if(Flash_UserBuff[0] != 0xFFFFFFFF)//判断该值是否全F,如果不等于全F,则该地址为上次写入的数据,将数据读出放入FLASH_SAVE_ADDR地址中,如果全F则已经被擦除过,不保存擦出过的数据
		{
			STMFLASH_Write(FLASH_SAVE_ADDR,(uint32_t*)Flash_UserBuff,8);//数据读出放入FLASH_SAVE_ADDR地址
		}
		STMFLASH_Read(FLASH_SAVE_ADDR,(uint32_t*)Flash_SaveBuff,8);//将上次保存的数据读出,用于这次程序的使用
		STMFLASH_OnlyErase(FLASH_USER_ADDR,8);//擦除FLASH_USER_ADDR地址的内容,用于这次数据的存储。
/*主循环*/
	while(1)
	{
		//用户任务,在任务中只能写入一次数据,因为初始化只擦了一次

	}

★上电多次写Flash代码
因为Flash擦除是一整个扇区擦除,详情看上一个博客Flash读写

●FLASH_USER_ADDR 地址处的Flash在程序每次初始化的时候将内容擦除。
●FLASH_SAVE_ADDR 地址处保存FLASH_USER_ADDR 地址擦除前的内容。
   在FLASH_USER_ADDR中写入一次数据后我们地址偏移32字节作为下一次数据写入的首地址,因为STM32H7每次写入数据必须为8个字(32字节),因此我们存放的数据如下图所示,每次都占用Flash的32个字节。
在这里插入图片描述
   在写的时候比如我们写了4次,则第四次尾地址后的数据全为FFFFFFFF,我们遍历FLASH_USER_ADDR 地址的数据,直到找到FFFFFFFF的数据,然后向前偏移32字节则为我们在扇区2 中上次写入数据的首地址(FLASH_USER_ADDR +偏移量),因此就找到了上次写入的数据,按下述代码思想就可提取数据。
在这里插入图片描述

  我们每次可以在初始化时在上述找到的首地址(FLASH_USER_ADDR +偏移量) 中提取数据保存在FLASH_SAVE_ADDR地址中,然后擦除FLASH_USER_ADDR 地址处写数据,这样擦除在初始化的时候完成,这样写Flash就不会长时间占用CPU的正常运行。用数据是将数据从FLASH_SAVE_ADDR处读出即可。
代码如下:

uint32_t Flash_UserBuff[8]={0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};
uint32_t Flash_SaveBuff[8]={0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};//保存的数据
int main(void)
{
/*初始化*/
	STMFLASH_Read(FLASH_USER_ADDR,(uint32_t*)Flash_UserBuff,8);//提前读一次
	if(Flash_UserBuff[0] != 0xFFFFFFFF)//如果上次被写入
	{
		while(Flash_UserBuff[0] != 0xFFFFFFFF)//遍历找到没被写的区域,就找到上次写入的地址(循环退出的地址减32字节就是保存ID的地址)
		{
			STMFLASH_Read(FLASH_USER_ADDR+32*Flash_Cnt,(uint32_t*)Flash_UserBuff,8);//遍历找到没被写的区域后退出
			Flash_Cnt++;
		}
		STMFLASH_Read(FLASH_USER_ADDR+32*(Flash_Cnt-2),(uint32_t*)Flash_UserBuff,8);//找到的没被写的区域往前偏移32字节,从该地址就可以读出上次写入的数据
		STMFLASH_Write(FLASH_SAVE_ADDR,(uint32_t*)Flash_UserBuff,8);//写入读取的数据放置在0x08020060(扇区2)flash地址中(转存上一次写入的数据)	
		STMFLASH_OnlyErase(FLASH_USER_ADDR,8);//将FLASH_USER_ADDR位置的数据擦除,准备这次的数据写入			
	}
	STMFLASH_Read(FLASH_SAVE_ADDR,(uint32_t*)Flash_SaveBuff,8);//在FLASH_SAVE_ADDR(扇区1)地址,读取一次数据放置内存中(这次程序使用)
/*主循环*/
	while(1)
	{
		//用户任务,在任务中可多次写入,因为每次写入Flash会地址偏移
		/*----多次写----*/
		Write_FlashAddress = FLASH_USER_ADDR + Write_Cnt*32;//写一次地址偏移32Byte
		Write_Cnt++;//写一次加一	
		STMFLASH_OnlyWrite(Write_FlashAddress,(uint32_t*)Flash_WData,8);//不擦除写	
		/*-------------*/
	}

通过以上方法可以避免在程序运行中Flash擦除占用CPU的时间,因为擦除都是在初始化的时候完成的。

参考博客 Flash读写

★★★如有错误欢迎指导!!!

猜你喜欢

转载自blog.csdn.net/qq_40147893/article/details/107428956