#include "stm32f4xx.h"
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址
#define FLASH_SAVE_ADDR 0x080A0000 //保存地址
//FLASH 扇區的起始地址
#define ADDR_FLASH_SECTOR_0 ((u32)0x08000000) //扇區0起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_1 ((u32)0x08004000) //扇區1起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_2 ((u32)0x08008000) //扇區2起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_3 ((u32)0x0800C000) //扇區3起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_4 ((u32)0x08010000) //扇區4起始地址, 64 Kbytes
#define ADDR_FLASH_SECTOR_5 ((u32)0x08020000) //扇區5起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_6 ((u32)0x08040000) //扇區6起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_7 ((u32)0x08060000) //扇區7起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_8 ((u32)0x08080000) //扇區8起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_9 ((u32)0x080A0000) //扇區9起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_10 ((u32)0x080C0000) //扇區10起始地址,128 Kbytes
#define ADDR_FLASH_SECTOR_11 ((u32)0x080E0000) //扇區11起始地址,128 Kbytes
//讀取指定地址的半字(16位數據)
//faddr:讀地址
//返回值:對應數據.
u32 STMFLASH_ReadWord(u32 faddr)
{
return *(vu32*)faddr;
}
//獲取某個地址所在的flash扇區
//addr:flash地址
//返回值:0~11,即addr所在的扇區
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;
}
//從指定地址開始寫入指定長度的數據
//特別注意:因爲STM32F4的扇區實在太大,沒辦法本地保存扇區數據,所以本函數
// 寫地址如果非0XFF,那麼會先擦除整個扇區且不保存扇區數據.所以
// 寫非0XFF的地址,將導致整個扇區數據丟失.建議寫之前確保扇區裏
// 沒有重要數據,最好是整個扇區先擦除了,然後慢慢往後寫.
//該函數對OTP區域也有效!可以用來寫OTP區!
//OTP區域地址範圍:0X1FFF7800~0X1FFF7A0F
//WriteAddr:起始地址(此地址必須爲4的倍數!!)
//pBuffer:數據指針
//NumToWrite:字(32位)數(就是要寫入的32位數據的個數.)
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; //非法地址
FLASH_Unlock(); //解鎖
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();//上鎖
}
//從指定地址開始讀出指定長度的數據
//ReadAddr:起始地址
//pBuffer:數據指針
//NumToRead:字(4位)數
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個字節.
}
}
void FLASHEXT_ReadFlash( u8 *pbData, u32 dwDataLen )
{
u32 Len;
u32 dwData;
u32 i=0,j=0;
Len= dwDataLen/4+((dwDataLen%4)?1:0);
STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)(pbData),Len);
return;
}
void FLASHEXT_WriteFlash( u8 *pbData, u32 dwDataLen )
{
u32 Len;
u32 dStartTime;
u8 pu8ReadData[60];
u8 i=0;
Len= dwDataLen/4+((dwDataLen%4)?1:0);
STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)(pu8ReadData),Len);
for(i=0;i<dwDataLen;i++)
{
if(pbData[i]!=pu8ReadData[i])
{
STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)(pbData),Len);
break;
}
}
return ;
}