STM32F4 Flash数据的保存和读取。
??STM32 F4的存储和F1的存储稍稍有些区别。F4的最小存储单位是扇区,而F1的最小存储单位是页。(那么这样擦除的时候就存在区别,F1系的可以只擦除一页PAGES(最小1K),而F4需要擦除一个扇区SECTORS(最小16K),好处就是F1可以最大程度不影响本扇区非本页的数据,而F4则会影响本扇区数据)
对于写Flash数据,都支持1、2、4字节写入。
??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);
}