STM32GO中Flash充当EEPROM的操作

STM32GO中Flash充当EEPROM的操作

之前在学校的时候一直使用的是STM32F1的芯片,本月找了一份工作,安排下来的任务是写一个传感器的程序,程序比较简单,主要分为了两个部分:
- 在Flash中找一片区域充当EEPROM的功能,实现初始化数据的存储。
- 使用ADC和DAC功能来实现将输入的信号,按照要求重新规划到规定的电压区间,然后输出。

由于之前一直都是直接使用的外置EEPROM芯片,所以这一次是一个新的学习过程,所以记录一下,废话不多说,正文开始。

在编写过程中主要需要注意的有两点

  1. 选址
    要想实现Flash当作EEPROM的使用,第一步只能是去翻看芯片手册中对于Flash部分的描述:
    首先我们要做的就是要选择一个合适的地址范围,我用到型号是STM32GO81xx,Main memory共有128 kb,被划分为了64Page,每页大小有2K。为了好找,我选择的区域是最后一页,地址范围为:
    0x0801 F800 - 0x0801 FFFF。
    STM32GO中Flash充当EEPROM的操作_第1张图片
  2. 闪存的编程和擦除
    通过手册中的描述,在芯片复位以后,Flash编程操作是被保护的,不能写入。通过写入特定的序列KEY、KEY2到FLASH_KEYR寄存器才可解除写保护,只有在写保护被解除后,我们才能操作相关的寄存器。
    这个操作有官方库中的HAL_FLASH_Unlock()函数来实现,操作完成以后,FLASH_CR便被解锁了,如果写入错误,那么FLASH_CR将被锁定,知道下次复位才可以再次解锁。
    STM32GO中Flash充当EEPROM的操作_第2张图片
    而且从手册中我们可以看出,STM32G0的Flash的写入只支持双字写入:
    STM32GO中Flash充当EEPROM的操作_第3张图片
    还有一点需要注意的就是在往Flash写入数据以前需要检查该区域是否已经擦除,因为在对Flash进行编程的时候,必须要求其写入地址的Flash是被擦出的(也就是说其值必须是0xFFFFFFFF),否则无法写入,STM32G0擦除时有两种模式可以选择,批量擦除和页擦除,由于用到的只有最后一页,所以,这里我选择的是页擦除模式。
		FLASH_EraseInitTypeDef FlashEraseInit;
		FlashEraseInit.TypeErase=FLASH_TYPEERASE_PAGES;       		//擦除类型,页擦除 
		FlashEraseInit.Page=63;   									//从哪页开始擦除
		FlashEraseInit.NbPages=1;                             		//一次只擦除一页
		if(HAL_FLASHEx_Erase(&FlashEraseInit,&PageError)!=HAL_OK) 
		{
			break;//发生错误了	
		}

主要的需要注意的讲完以后,我们就要开始正式编程了,标准的编程步骤如下:

  1. 解锁。
  2. 确保要写入地址的Flash已经擦除完全。
  3. 检查 FLASH_SR 中的 BSY 位,确保当前未执行任何 FLASH 操作。
  4. 将 FLASH_CR 寄存器中的 PG 位置 1,激活 FLASH 编程.
  5. 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作.
  6. 等待 BSY 位清零,完成一次编程.

完整的Flash写入函数如下:

u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu32*)faddr; 
}

void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
	FLASH_EraseInitTypeDef FlashEraseInit;
	HAL_StatusTypeDef FlashStatus=HAL_OK;
	u32 PageError=0;
	u32 addrx=0;
	u32 endaddr=0;	
	if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址
    
	HAL_FLASH_Unlock();             //解锁	
	addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*8;	//写入的结束地址
	if(addrx<0X1FFF0000)
	{
		while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			 if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)	//有非0XFFFFFFFF的地方,要擦除这个扇区
			 {   
				FlashEraseInit.TypeErase=FLASH_TYPEERASE_PAGES;    //擦除类型,页擦除 
				FlashEraseInit.Page=63;   						   //从哪页开始擦除
				FlashEraseInit.NbPages=1;                          //一次只擦除一页
				if(HAL_FLASHEx_Erase(&FlashEraseInit,&PageError)!=HAL_OK) 
				{
					break;//发生错误了	
				}
			}else addrx+=4;
			FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
		}
	}
	FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);        //等待上次操作完成
	if(FlashStatus==HAL_OK)
	{
		 while(WriteAddr<endaddr)									//写数据
		 {
			if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,WriteAddr,*(uint64_t*) pBuffer)!=HAL_OK)//写入数据
			{ 
				break;												//写入异常
			}
			WriteAddr+=8;
			pBuffer+=2;
		}  
	}
	HAL_FLASH_Lock();           									//上锁
} 

void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)   		//连续读取
{
	u32 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadWord(ReadAddr);	//读取4个字节.
		ReadAddr+=4;												//偏移4个字节.	
	}
}

main函数:

int main()
{
	int aa[4]={1,2,3,4};
	HAL_Init();
    SystemClock_Config();
    STMFLASH_Write(STM32_EEPROM_BASE,(u32*)aa,sizeof(aa)/8);
    while(1)
    {
    
	}
}

通过Keil的调试功能可以看到数据已经写入进入,重新复位数据依然存在:
STM32GO中Flash充当EEPROM的操作_第4张图片

写在最后:
第一次写,存在很多的不足,主要是为了加深印象和给像我这样的小白一些参考,存在的不足也希望大家能够不吝赐教,谢谢!

你可能感兴趣的:(STM32G0)