1.FLASH介绍
FLASH存储器写入数据时,每一位只能由“1”变成“0”,不能由“0”变成“1“,因此,当我们有数据要保存到FLASH存储器时,要先对目标段进行整段擦除操作,擦除操作使对应段FLASH存储器变成全“1”,再对需要的位写为“0”,即完成写入操作。
FLASH读写操作流程如下:
(1)对FLASH写入数据
解锁FLASH
擦除FLASH
写入数据到FLASH
锁住FLASH
FLASH读取数据
(2)直接读取相应的FLASH地址
2.代码编写
FLASH读写不需要对STM32CubeMX进行配置,直接调用HAL相关函数进行开发。
在这里插入代码片
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址
#define FLASH_WAITETIME 50000 //FLASH等待超时时间
/* Base address of the Flash sectors /
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) / Base @ of Sector 0, 16 Kbytes /
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) / Base @ of Sector 1, 16 Kbytes /
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) / Base @ of Sector 2, 16 Kbytes /
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) / Base @ of Sector 3, 16 Kbytes /
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) / Base @ of Sector 4, 64 Kbytes /
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) / Base @ of Sector 5, 128 Kbytes /
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) / Base @ of Sector 6, 128 Kbytes /
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) / Base @ of Sector 7, 128 Kbytes /
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) / Base @ of Sector 8, 128 Kbytes /
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) / Base @ of Sector 9, 128 Kbytes /
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) / Base @ of Sector 10, 128 Kbytes /
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) / Base @ of Sector 11, 128 Kbytes */
/****************************************************************
*函数名:STMFLASH_ReadWord
*描 述:读取指定地址的字
*参 数:faddr 读地址
*返 回:数据
*****************************************************************/
uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
return *(__IO uint32_t*)faddr;
}
/****************************************************************
*函数名:STMFLASH_GetFlashSector
*描 述:获取某个地址所在的flash扇区
*参 数:addr:flash地址
*返 回:0~11,即addr所在的扇区
*****************************************************************/
uint8_t STMFLASH_GetFlashSector(uint32_t 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;
}
/****************************************************************
*函数名:STM32FLASH_EraseSector
*描 述:擦除地址所在的扇区
*参 数:addrx 地址
*返 回:None
*****************************************************************/
void STM32FLASH_EraseSector(uint32_t addrx)
{
uint32_t SectorError=0;
FLASH_EraseInitTypeDef FlashEraseInit;
HAL_FLASH_Unlock(); //解锁
FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS; //擦除类型,扇区擦除
FlashEraseInit.Sector = STMFLASH_GetFlashSector(addrx);//要擦除的扇区
FlashEraseInit.NbSectors = 1; //一次只擦除一个扇区
FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3; //电压范围,VCC=2.7~3.6V之间!!
printf("\r\n************erase************\r\n");
if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError) != HAL_OK)
{
printf("erase flash error!\r\n");
}
HAL_FLASH_Lock(); //上锁
}
/****************************************************************
*函数名:STMFLASH_Write
*描 述:在指定地址写入固定长度数据
*参 数:WriteAddr 起始地址,pBuffer 数据指针, NumToWrite 要写入的数据的个数
*返 回:-1 失败
*****************************************************************/
void STMFLASH_Write(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t NumToWrite)
{
FLASH_EraseInitTypeDef FlashEraseInit;
HAL_StatusTypeDef FlashStatus=HAL_OK;
uint32_t SectorError=0;
static uint32_t addrx=0;
uint32_t endaddr=0;
uint32_t len=0;//,size=0;
len = NumToWrite;
//size = len/4 + ((len%4)?1:0);
if(WriteAddr < STM32_FLASH_BASE || WriteAddr % 4) //非法地址
return;
HAL_FLASH_Unlock(); //解锁
addrx = WriteAddr; //写入的起始地址
endaddr = WriteAddr + len; //写入的结束地址
if(addrx<0X1FFF0000)
{
while(addrx < endaddr) //对非FFFFFFFF的地方,先擦除
{
if(STMFLASH_ReadWord(addrx) != 0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
{
FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS; //擦除类型,扇区擦除
FlashEraseInit.Sector = STMFLASH_GetFlashSector(addrx);//要擦除的扇区
FlashEraseInit.NbSectors = 1; //一次只擦除一个扇区
FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3; //电压范围,VCC=2.7~3.6V之间!!
printf("\r\n************erase************\r\n");
if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError) != HAL_OK)
{
printf("erase flash error!\r\n");
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_WORD,WriteAddr,*pBuffer)!=HAL_OK)//写入数据
{
break; //写入异常
}
WriteAddr += 4;
pBuffer++;
}
}
HAL_FLASH_Lock(); //上锁
}
/****************************************************************
*函数名:readdata_from_flash
*描 述:从指定地址读出固定长度数据
*参 数:readaddr 读地址 pbuffer 读出数据 numtoread 读长度
*返 回:-1 失败
*****************************************************************/
void STMFLASH_Read(uint32_t ReadAddr,uint32_t *pBuffer,uint32_t NumToRead)
{
uint32_t i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i] = STMFLASH_ReadWord(ReadAddr);//读取4个字节.
ReadAddr += 4;//偏移4个字节.
}
}