当前位置: 代码迷 >> 综合 >> STM32F4 Flash数据的保存和读取。
  详细解决方案

STM32F4 Flash数据的保存和读取。

热度:90   发布时间:2023-09-22 08:14:41.0

STM32F4 Flash数据的保存和读取。

??STM32 F4的存储和F1的存储稍稍有些区别。F4的最小存储单位是扇区,而F1的最小存储单位是。(那么这样擦除的时候就存在区别,F1系的可以只擦除一页PAGES(最小1K),而F4需要擦除一个扇区SECTORS(最小16K),好处就是F1可以最大程度不影响本扇区非本页的数据,而F4则会影响本扇区数据)

对于写Flash数据,都支持1、2、4字节写入
STM32F4 Flash数据的保存和读取。

??STM32的读取比较简单,直接用指针指向对应的空间地址就可以取数据。最小可以写4个字节,即以为存储单位。

u32 STMFLASH_ReadWord(u32 faddr)
{
    return *(vu32*)faddr; 
}  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个字节. }
}

??STM32的写入稍微麻烦一点,需要先把扇区的数据擦除成0XFF,然后才可以写入数据。具体做法如地下:
1.禁止中断
2.flash解锁,禁止数据缓存
3.扇区擦除并检验
4.写入数据
5.开启数据缓存,flash上锁
7.开启中断


uint16_t STMFLASH_GetFlashSector(u32 addr)
{
    if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10; return FLASH_Sector_11;	
}void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{
     FLASH_Status status = FLASH_COMPLETE;u32 addrx=0;u32 endaddr=0;	if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址IntsStorage;StoreDisableInts;         //禁止中断FLASH_Unlock();		//解锁 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存addrx=WriteAddr;				//写入的起始地址endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址if(addrx<0X1FFF0000)			//只有主存储区,才需要执行擦除操作!!{
    while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除){
    if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区{
       status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!if(status!=FLASH_COMPLETE)break;	//发生错误了}else addrx+=4;} }if(status==FLASH_COMPLETE){
    while(WriteAddr<endaddr)//写数据{
    if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据{
     break;	//写入异常}WriteAddr+=4;pBuffer++;} }FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存FLASH_Lock();//上锁RestoreInts;     //开启中断
} 

上述函数在写扇区的时候,会将该扇区擦除,然后再将数据写入,有个弊端,浪费了nor 单字节编程的优势。

??所以如果要修改扇区内的数据,则需要先将扇区内的数据取出来,然后修改对应的数据,最后再存入

??以修改一个结构体数据为例,先将数据使用memcpy函数cpy出来,然后使用结构体指向该数据,然后该结构体赋新值,最后再写入数据,这样就不会影响该扇区其他结构体的数据。

void UpdateSystemFuncParaData(struct ElevatorFuncPara  *elevator_func_parameter)
{
    memcpy(ParaBuffer,(u8*)LiftSystemaComParaAddr,520);struct ElevatorFuncPara   *temp_elevator_func_parameter = (struct ElevatorFuncPara*)&ParaBuffer[40];temp_elevator_func_parameter->AccXBaseCount        = elevator_func_parameter->AccXBaseCount;temp_elevator_func_parameter->CloseLimitOffset     = elevator_func_parameter->CloseLimitOffset;temp_elevator_func_parameter->CloseStartTimeLimit  = elevator_func_parameter->CloseStartTimeLimit;temp_elevator_func_parameter->CloseStopTimeLimit   = elevator_func_parameter->CloseStopTimeLimit;temp_elevator_func_parameter->OpenLimitOffset      = elevator_func_parameter->OpenLimitOffset;temp_elevator_func_parameter->OpenStartTimeLimit   = elevator_func_parameter->OpenStartTimeLimit;temp_elevator_func_parameter->OpenStopTimeLimit    = elevator_func_parameter->OpenStopTimeLimit;temp_elevator_func_parameter->QuitCheckTime        = elevator_func_parameter->QuitCheckTime;STMFLASH_Write(LiftSystemaComParaAddr,(u32*)ParaBuffer,130);
}
  相关解决方案