摘要
STM32单片机都带有ROM和RAM,其中STM32根据自身的ROM(Flash)可以分为小容量产品、中容量产品、大容量产品
根据FLASH容量可以分为:
- 小容量:0-32K
- 中容量:64-128K
- 大容量:256K以上(包含256K)
按照不同容量,存储器组织成32个1K字节/页(小容量)、128个1K字节/页(中容量)、256个2K字 节/页(大容量)的主存储器块和一个信息块,各容量的页大小如下图所示
在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地
进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。
信息块分为两个部分:
- 系统存储器是用于存放在系统存储器自举模式下的启动程序,这个区域只保留给ST使用,启动程序使用USART1串行接口实现对闪存存储器的编程;ST在生产线上对这个区域编程并锁定以防止用户擦写。关于使用这个启动程序的详细信息,请参阅AN2606。
- 选择字节
对主存储器和信息块的写入由内嵌的闪存编程/擦除控制器(FPEC)管理;编程与擦除的高电压由内部产生。
闪存存储器有两种保护方式防止非法的访问(读、写、擦除):
- 页写入保护
- 读出保护
正文
说了这么多的官方语言,无非就是将STM32单片机是用不到的ROM部分当做存储盘来用而已,保存一些读写频率比较低的数据而已
说道保存数据,无非就是 读 写 擦除 保护等等
前言
现在 STM32 的 FLASH 寿命是 10000 次,如果不是频繁的擦除和写入,使用FLAHS模拟EEPROM是没有毛病的,但是要注意的是,存取数据的位置尽量靠后,要给代码留下足够的空间,不然就尴尬了
stm32是32bit处理器,所以它的字是32bit的(一次处理4字节长度的数据)。半字自然就是16bit(2字节);字节是8bit
FLASH的读写都是以半字为单位的
读
读的话就相对更简单了,有了对应的地址,直接去地址中的内容就可以了
- 举例
要读取 地址0x08030000出的内容*((vu16*)0x08030000); 就可以将该位置的内容读取出来了
要想读取多个字节
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=*((u16*)(ReadAddr));//读取两个字节.
ReadAddr+=2;//地址向后偏移2个字节.
}
}
写
对于大容量产品,从第0页至第61页,写保护是以每2页为单位实现的,剩下的存储器块(第62页至第255页)则是同时提供保护。对于小容量和中容量的产品,写保护是以每4页为单位实现的。
如果试图在一个受保护的页面进行编程或擦除操作,在闪存状态寄存器(FLASH_SR)中会返回一个保护错误标志。
在写入之前需要解除闪存锁
- RDPRT键 = 0x000000A5
- KEY1 = 0x45670123
- KEY2 = 0xCDEF89AB
复位后,FPEC模块是被保护的,不能写入FLASH_CR寄存器;通过写入特定的序列到FLASH_KEYR寄存器可以打开FPEC模块,这个特定的序列是在FLASH_KEYR写入两个键值(KEY1和KEY2,见2.3.1节);错误的操作序列都会在下次复位前锁死FPEC模块和FLASH_CR寄存器。
写入错误的键序列还会产生总线错误;总线错误发生在第一次写入的不是KEY1,或第一次写入的是KEY1但第二次写入的不是KEY2时;FPEC模块和FLASH_CR寄存器可以由程序设置FLASH_CR寄存器中的LOCK位锁住,这时可以通过在FLASH_KEYR中写入正确的键值对FPEC解锁。
解锁
void FLASH_Unlock(void)
{
/* Authorize the FPEC of Bank1 Access */
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
有解锁就有上锁
上锁
void FLASH_Lock(void)
{
/* Set the Lock Bit to lock the FPEC and the CR of Bank1 */
FLASH->CR |= CR_LOCK_Set;//CR_LOCK_Set是((uint32_t)0x00000080)
}
为什么是CR_LOCK_Set是((uint32_t)0x00000080)
请看FLASH—CR寄存器的第七位
擦除
闪存可以按页擦除,也可以整片擦除。
页擦除
闪存的任何一页都可以通过FPEC的页擦除功能擦除;擦除一页应遵守下述过程:
- 检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作
- 设置FLASH_CR寄存器的PER位为’1’
- 用FLASH_AR寄存器选择要擦除的页
- 设置FLASH_CR寄存器的STRT位为’1’
- 等待BSY位变为’0’
- 读出被擦除的页并做验证
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{
FLASH_Status status = FLASH_COMPLETE;
/* Check the parameters */
assert_param(IS_FLASH_ADDRESS(Page_Address));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase the page */
FLASH->CR|= CR_PER_Set;
FLASH->AR = Page_Address;
FLASH->CR|= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
/* Disable the PER Bit */
FLASH->CR &= CR_PER_Reset;
}
/* Return the Erase Status */
return status;
}
整片擦除
可以用整片擦除功能擦除所有用户区的闪存,信息块不受此操作影响。建议使用下述过程:
- 检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作
- 设置FLASH_CR寄存器的MER位为’1’
- 设置FLASH_CR寄存器的STRT位为’1’
- 等待BSY位变为’0’
- 读出所有页并做验证
FLASH_Status FLASH_EraseAllPages(void)
{
FLASH_Status status = FLASH_COMPLETE;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase all pages */
FLASH->CR |= CR_MER_Set;
FLASH->CR |= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
/* Disable the MER Bit */
FLASH->CR &= CR_MER_Reset;
}
/* Return the Erase Status */
return status;
}