STM32F407实现内部FLASH的读写功能
文章目录
- 前言
- 一、FLASH 简介
- 二、读数据
- 三、写数据
- 四、最终效果
- 五、完整工程
前言
我们通过仿真器下到芯片的程序一般会保存到eflash里面,在我们的STM32F407里面这里的空间挺大的,我所使用的芯片型号是STM32F407ZGT6,FLASH 容量为 1024K 字节。不同的项目会选择不同的芯片进行开发。
一、FLASH 简介
FLASH 是 EEPROM 的一种,是带电可擦除可编程的只读存储器,本文特指 STM32 内部的 Flash,主要用于存储用户程序代码以及必要的配置信息。
特性:
非易失性:数据在断电后依旧存储在数据中,适合存储程序代码和关键配置信息。
快速访问:FLASH 具有较快的读取速度
较长寿命:一般的 FLASH 可擦除约十万次
先擦再写:FLASH 的写操作只能将数据位从 1 写成 0,而不能从 0 写成 1,如果一个数据位已经写成 0 了,那 FLASH 必须先将该位所处的扇区或区块先擦除,才能重新写入。
FLASH 的擦除操作其实就是将对应扇区、区块或者全部区块的数据位全擦除为 1,所以FLASH的默认值是0xFF.
STM32F4 的闪存模块由:主存储器、系统存储器、OPT 区域和选项字节等 4 部分组成。 主存储器,该部分用来存放代码和数据常数(如 const 类型的数据)。分为 12 个扇区,前 4个扇区为 16KB 大小,然后扇区 4是 64KB 大小,扇区5~11 是 128K 大小,不同容量的 STM32F4,拥有的扇区数不一样,比如我们的 STM32F407ZGT6,则拥有全部 12 个扇区。从上图可以看出主存储器的起始地址就是 0X08000000, B0、B1 都接 GND 的时候,就是从 0X08000000 开始运行代码的。
系统存储器,这个主要用来存放 STM32F4 的 bootloader 代码,此代码是出厂的时候就固化在 STM32F4 里面了,专门来给主存储器下载代码的。当 B0 接 V3.3,B1 接 GND 的时候,从该存储器启动(即进入串口下载模式)。
OTP 区域,即一次性可编程区域,共 528 字节,被分成两个部分,前面 512 字节(32 字节为 1 块,分成 16 块),可以用来存储一些用户数据(一次性的,写完一次,永远不可以擦除!!),后面 16 字节,用于锁定对应块。
在没有使用IAP功能的时候我们的程序一般会从0x08000000开始,当然也可以从其他的地址开始,可以在KEIL的魔术棒的target中设置,具体如下图:
图中框起来的内容前面是起始地址后面是大小,我这里设置的是从0x08000000到0x08100000也就是我们在flash中可存储数据的全部空间1024K 。
二、读数据
STM23F4 的 FLASH 读取是很简单的。例如,我们要从地址 addr,读取一个字(字节为 8位,半字为 16 位,字为 32 位),可以通过如下的语句读取:
data=(vu32)addr;
将 addr 强制转换为 vu32 指针,然后取该指针所指向的地址的值,即得到了 addr 地址的值。类似的,将上面的 vu32 改为 vu16,即可读取指定地址的一个半字。
代码如下:
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个字节. }
}u32 STMFLASH_ReadWord(u32 faddr)
{return *(vu32*)faddr;
}
在STMFLASH_Read函数中调用的是STMFLASH_ReadWord,在for循环中每次读取四字节保存到buf中。
三、写数据
STM32F4 的闪存编程由 6 个 32 位寄存器控制,他们分别是:
⚫ FLASH 访问控制寄存器(FLASH_ACR)
⚫ FLASH 秘钥寄存器(FLASH_KEYR)
⚫ FLASH 选项秘钥寄存器(FLASH_OPTKEYR)
⚫ FLASH 状态寄存器(FLASH_SR)
⚫ FLASH 控制寄存器(FLASH_CR)
⚫ FLASH 选项控制寄存器(FLASH_OPTCR)
STM32F4 复位后,FLASH 编程操作是被保护的,不能写入 FLASH_CR 寄存器;通过写入特定的序列(0X45670123 和 0XCDEF89AB)到 FLASH_KEYR 寄存器才可解除写保护,只有在写保护被解除后,我们才能操作相关寄存器。
FLASH_CR 的解锁序列为:
1, 写 0X45670123 到 FLASH_KEYR
2, 写 0XCDEF89AB 到 FLASH_KEYR
通过这两个步骤,即可解锁 FLASH_CR,如果写入错误,那么 FLASH_CR 将被锁定,直到下次复位后才可以再次解锁。
STM32F4 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFFFFFF),否则无法写入。STM32F4 的标准编程步骤如下:
1,检查 FLASH_SR 中的 BSY 位,确保当前未执行任何 FLASH 操作。
2,将 FLASH_CR 寄存器中的 PG 位置 1,激活 FLASH 编程。
3,针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作:
—并行位数为 x8 时按字节写入(PSIZE=00)
—并行位数为 x16 时按半字写入(PSIZE=01)
—并行位数为 x32 时按字写入(PSIZE=02)
—并行位数为 x64 时按双字写入(PSIZE=03)
4,等待 BSY 位清零,完成一次编程。
代码如下:
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();//上锁
}
四、最终效果
在上图可以看到在0x0800C004这个地址开始写入了数据,就是const u8 TEXT_Buffer[]={“STM32 FLASH TEST”};这个内容只不过是16进制。
将存进去的数据再读出来,通过串口打印。
五、完整工程
我用夸克网盘分享了「FLASH读写.rar」
链接:https://pan.quark.cn/s/b544c17570f1