FLASH
1.FLASH介绍
**主存储器:**分为4个16KB扇区、1个64KB扇区和7个128KB扇区。boot0/boot1都接GND时从0x08000000开始运行代码。
**系统存储器:**器件在系统存储器自举模式下从该存储器启动,主要存放芯片的bootloader代码,此代码出厂时固化在芯片内部了。用于给主存储器下载代码。当boot0接3.3V、boot1接GND时从此处开始运行,即进入串口下载模式。
**OTP区域:**512字节OTP(一次性可编程),用于存储用户数据。OTP区域还有额外的16个字节,用于锁定对应的OTP数据块。
**选项字节:**用于配置读写保护、BOR级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。
1.1闪存的编程和擦除
STM32F4的闪存编程由6个32位寄存器控制:
(1)FLASH访问控制寄存器(FLASH_ACR)
(2)FLASH秘钥寄存器(FLASH_KEYR)
(3)FLASH选项秘钥寄存器(FLASH_OPTKEYR)
(4)FLASH状态寄存器(FLASH_SR)
(5)FLASH控制寄存器(FLASH_CR)
(6)FLASH选项控制寄存器(FLASH_OPTCR)
STM32F4复位后,FLASH编程操作是被保护的,不能写入FLASH_CR。
FALSH_CR解锁步骤为:
(1)写0X45670123到FLASH_KEYR
(2)写0XCDEF89AB到FLASH_KEYR
STM32F4闪存的编程位数通过FLASH_CR的PSIZE字段设置,PSIZE的设置必须和电源电压匹配。
STM32F4标准编程步骤:
(1)检查FLASH_SR中的BSY位,确保当前未执行任何FLASH操作。
(2)将FLASH_CR寄存器中的PG位置1,激活FLASH编程。
(3)执行写入操作
(4)等待BSY位清零,完成一次编程。
扇区擦除步骤:
(1)检查FLASH_CR的LOCK是否解锁,如果没有先解锁
(2)检查FLASH_SR寄存器中的BSY位,确保当前未执行任何FLASH操作
(3)在FLASH_CR寄存器中,将SER位置1,并从主存储块的12个扇区中选择要擦除的扇区(SNB)
(4)将FLASH_CR寄存器中的STRT位置1,触发擦除操作
(5)等待BSY位清零
2.相关寄存器
3.配置方法
3.1 内部flash分步操作
3.1.1解锁和锁定
#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
#define FLASH_CR_LOCK ((uint32_t)0x80000000)
void FLASH_Unlock(void)
{
if((FLASH->CR & FLASH_CR_LOCK) != RESET)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
}
void FLASH_Lock(void)
{
FLASH->CR |= FLASH_CR_LOCK;
}
3.1.2写操作
FLASH_Status FLASH_ProgramDoubleWord(uint32_t Address, uint64_t Data)
{
FLASH_Status status = FLASH_COMPLETE;
assert_param(IS_FLASH_ADDRESS(Address));
status = FLASH_WaitForLastOperation();
if(status == FLASH_COMPLETE)
{
FLASH->CR &= CR_PSIZE_MASK;
FLASH->CR |= FLASH_PSIZE_DOUBLE_WORD;
FLASH->CR |= FLASH_CR_PG;
*(__IO uint64_t*)Address = Data;
status = FLASH_WaitForLastOperation();
FLASH->CR &= (~FLASH_CR_PG);
}
return status;
}
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
FLASH_Status status = FLASH_COMPLETE;
assert_param(IS_FLASH_ADDRESS(Address));
status = FLASH_WaitForLastOperation();
if(status == FLASH_COMPLETE)
{
FLASH->CR &= CR_PSIZE_MASK;
FLASH->CR |= FLASH_PSIZE_WORD;
FLASH->CR |= FLASH_CR_PG;
*(__IO uint32_t*)Address = Data;
status = FLASH_WaitForLastOperation();
FLASH->CR &= (~FLASH_CR_PG);
}
return status;
}
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
FLASH_Status status = FLASH_COMPLETE;
assert_param(IS_FLASH_ADDRESS(Address));
status = FLASH_WaitForLastOperation();
if(status == FLASH_COMPLETE)
{
FLASH->CR &= CR_PSIZE_MASK;
FLASH->CR |= FLASH_PSIZE_HALF_WORD;
FLASH->CR |= FLASH_CR_PG;
*(__IO uint16_t*)Address = Data;
status = FLASH_WaitForLastOperation();
FLASH->CR &= (~FLASH_CR_PG);
}
return status;
}
FLASH_Status FLASH_ProgramByte(uint32_t Address, uint8_t Data)
{
FLASH_Status status = FLASH_COMPLETE;
assert_param(IS_FLASH_ADDRESS(Address));
status = FLASH_WaitForLastOperation();
if(status == FLASH_COMPLETE)
{
FLASH->CR &= CR_PSIZE_MASK;
FLASH->CR |= FLASH_PSIZE_BYTE;
FLASH->CR |= FLASH_CR_PG;
*(__IO uint8_t*)Address = Data;
status = FLASH_WaitForLastOperation();
FLASH->CR &= (~FLASH_CR_PG);
}
return status;
}
3.1.3擦除操作
FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector, uint8_t VoltageRange);
FLASH_Status FLASH_EraseAllSectors(uint8_t VoltageRange);
FLASH_Status FLASH_EraseAllBank1Sectors(uint8_t VoltageRange);
FLASH_Status FLASH_EraseAllBank2Sectors(uint8_t VoltageRange);
3.1.4获取FLASH状态
FLASH_Status FLASH_GetStatus(void)
{
FLASH_Status flashstatus = FLASH_COMPLETE;
if((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY)
{
flashstatus = FLASH_BUSY;
}
else
{
if((FLASH->SR & FLASH_FLAG_WRPERR) != (uint32_t)0x00)
{
flashstatus = FLASH_ERROR_WRP;
}
else
{
if((FLASH->SR & FLASH_FLAG_RDERR) != (uint32_t)0x00)
{
flashstatus = FLASH_ERROR_RD;
}
else
{
if((FLASH->SR & (uint32_t)0xE0) != (uint32_t)0x00)
{
flashstatus = FLASH_ERROR_PROGRAM;
}
else
{
if((FLASH->SR & FLASH_FLAG_OPERR) != (uint32_t)0x00)
{
flashstatus = FLASH_ERROR_OPERATION;
}
else
{
flashstatus = FLASH_COMPLETE;
}
}
}
}
}
return flashstatus;
}
返回值是通过枚举类型定义的
typedef enum
{
FLASH_BUSY = 1,
FLASH_ERROR_RD,
FLASH_ERROR_PGS,
FLASH_ERROR_PGP,
FLASH_ERROR_PGA,
FLASH_ERROR_WRP,
FLASH_ERROR_PROGRAM,
FLASH_ERROR_OPERATION,
FLASH_COMPLETE
}FLASH_Status;
3.1.5等待操作完成
在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后 读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。
FLASH_Status FLASH_WaitForLastOperation(void)
{
__IO FLASH_Status status = FLASH_COMPLETE;
status = FLASH_GetStatus();
while(status == FLASH_BUSY)
{
status = FLASH_GetStatus();
}
return status;
}
3.1.6读取FLASH指定地址数据
u32 STMFLASH_ReadWord(u32 faddr)
{ return *(u32*)faddr; }
3.2FLASH读数据函数
void STM32_FLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)
{
u32 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=STM32_FLASH_ReadWord(ReadAddr);
ReadAddr+=4;
}
}
3.3FLASH写数据函数
void STM32_FLASH_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);
addrx=WriteAddr;
endaddr=WriteAddr+NumToWrite*4;
if(addrx<0X1FFF0000)
{
while(addrx<endaddr)
{
if(STM32_FLASH_ReadWord(addrx)!=0XFFFFFFFF)
{
status=FLASH_EraseSector(STM32_FLASH_GetFlashSector(addrx),VoltageRange_3);
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_Lock();
}
//这个宏定义用法保存一下,挺好
const u8 text_buf[]="www.prechin.net";
#define TEXTLEN sizeof(text_buf)
#define TEXTSIZE (TEXTLEN/4+((TEXTLEN%4)?1:0))
讲解不到位的希望大家指出,有需要我讲解的部分,希望大家提出,我会出文档讲解。
|