主要特性:
● 对于STM32F40x和STM32F41x,容量高达1 MB;对于STM32F42x和STM32F43x,容量高达2 MB
(这里,STM32F407ZGT6:1MB,STM32F407ZET6:512KB)
● 128位宽数据读取
● 字节、半字、字和双字数据写入
● 扇区擦除与全部擦除
● 存储器组织结构
Flash 结构如下:
— 主存储器块,分为 4 个 16 KB扇区、1个64 KB扇区和7个128 KB扇区
— 系统存储器,器件在系统存储器自举模式下从该存储器启动
— 512 字节 OTP(一次性可编程),用于存储用户数据
OTP 区域还有 16 个额外字节,用于锁定对应的 OTP 数据块。
— 选项字节,用于配置读写保护、 BOR 级别、软件/硬件看门狗以及器件处于待机或
停止模式下的复位。
● 低功耗模式
Flash模块构成(STM32F40x和STM32F41x):
读接口:
-- CPU时钟频率与Flash读取时间之间的关系 --
为了准确读取 Flash数据,必须根据CPU时钟(HCLK)频率和器件电源电压在Flash存取控制寄存器(FLASH_ACR)中正确地编程等待周期数(LATENCY)。
等待周期通过 FLASH_ACR寄存器的LATENCY[2:0]三个位设置。复位后, CPU时钟频率为16Mhz,FLASH_ACR寄存器中的等待周期(WS)为0。
供电电压是3.3V,所以我们设置168Mhz频率作为CPU时钟之前,必须先设置LATENCY为5,否则FLASH读写可能出错,导致死机。
-- 自适应实时存储器加速器(ART Accelerator™) --
最大工作频率 168Mhz 时,虽然FLASH理论上需要6个CPU等待周期,
但凭借ART加速器所获得的性能相当于 Flash在CPU频率高达 168MHz时以0个等待周期执行程序。 (内部机制,知道就行,暂无深究必要)
擦除和编程操作
执行任何 Flash 编程操作(擦除或编程)时,CPU时钟频率(HCLK)不能低于1 MHz。如果在Flash操作期间发生器件复位,无法保证Flash中的内容。
在对STM32F4xx的Flash执行写入或擦除操作期间,任何读取Flash的尝试都会导致总线阻塞。
只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能从Flash中执行代码或数据获取操作。
-- Flash控制寄存器解锁 --
复位后, Flash 控制寄存器(FLASH_CR)不允许执行写操作,以防因电气干扰等原因出现对Flash的意外操作。(配置前,需要进行解锁)
此寄存器的解锁顺序如下:
1.在Flash密钥寄存器(FLASH_KEYR)中写入KEY1 = 0x45670123
2.在Flash密钥寄存器(FLASH_KEYR)中写入KEY2 = 0xCDEF89AB
顺序不能错,否则将返回总线错误并锁定 FLASH_CR 寄存器,直到下一次复位。
-- 编程/擦除并行位数 --
STM32F4 闪存的编程位数可以通过 FLASH_CR的PSIZE字段配置,PSIZE的设置必须和电源电压匹配
通过FLASH_CR寄存器中的PSIZE 字段配置并行位数(每次对 Flash 进行写操作时将编程的字节数)。
在进行任何编程/擦除操作前,必须在 FLASH_CR 寄存器中对其进行正确配置。
外部VPP电源为3.3V,所以PSIZE设置为10,即32位并行位数。擦除或者编程,都必须以32位为基础进行。
-- 擦除 --
Flash 擦除操作可针对扇区或整个Flash(批量擦除)执行。执行批量擦除时,不会影响OTP扇区或配置扇区。
STM32F4 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFFFFFF),否则无法写入。
扇区擦除步骤:
1. 检查 FLASH_SR寄存器中的BSY位,以确认当前未执行任何 Flash操作
2. 在 FLASH_CR寄存器中,将SER位置 1,并从主存储块的12个(STM32F405xx/07xx和STM32F415xx/17xx)或24个(STM32F42xxx和STM32F43xxx)扇区中选择要擦除
的扇区 (SNB)
3. 将 FLASH_CR 寄存器中的 STRT 位置1
4. 等待 BSY 位清零
批量擦除步骤:
1. 检查FLASH_SR寄存器中的BSY位,以确认当前未执行任何Flash操作
2. 将FLASH_CR寄存器中的MER位置1(STM32F405xx/07xx和STM32F415xx/17xx器件)3. 将FLASH_CR寄存器中的MER和MER1位置1(STM32F42xxx和STM32F43xxx器件)
4. 将FLASH_CR寄存器中的STRT位置1
5. 等待 BSY位清零
-- 编程 --
标准编程步骤:
1. 检查FLASH_SR中的BSY 位,以确认当前未执行任何 Flash操作。
2. 将 FLASH_CR寄存器中的PG位置1。
3. 针对所需存储器地址(主存储器块或OTP区域内)执行数据写入操作:
— 并行位数为 x8时按字节写入
— 并行位数为 x16时按半字写入
— 并行位数为x32时按字写入 (字 = 32位)
— 并行位数为 x64时按双字写入
4. 等待 BSY位清零。
注意:1、设置 FLASH_CR 之前要先解锁; 2、编程前,要确保要写如地址的FLASH已经擦除(0xFFFFFFFF)。
寄存器
-- 寄存器一览 --
① FLASH_ACR : Flash访问控制寄存器 (Flash access control register)
② FLASH_KEYR : Flash 密钥寄存器 (Flash key register)
③ FLASH_OPTKEYR : Flash选项密钥寄存器 (Flash option key register)
④ FLASH_SR : Flash状态寄存器 (Flash status register)
⑤ FLASH_CR : Flash控制寄存器 (Flash control register)
⑥ FLASH_OPTCR : Flash选项控制寄存器 (Flash option control register)
-- FLASH_ACR(访问控制寄存器)--
LATENCY[2:0] :必须根据我们MCU的工作电压和频率,来进行正确的设置,否则,可能死机
DCEN、ICEN和 PRFTEN : 一般都设置为1即可
-- FLASH_KEYR (秘钥寄存器)--
用来解锁 FLASH_CR
-- FLASH_CR (控制寄存器)--
LOCK : 用于指示FLASH_CR寄存器是否被锁住,该位在检测到正确的解锁序列后,硬件将其清零。在一次不成功的解锁操作后,在下次系统复位之前,该位将不再改变。
STRT : 用于开始一次擦除操作。在该位写入1,将执行一次擦除操作。
PSIZE[1:0] : 用于设置编程宽度,3.3V时,我们设置PSIZE =2 即可。
SNB[3:0] : 这4个位用于选择要擦除的扇区编号,取值范围为0~11。
SER : 用于选择扇区擦除操作,在扇区擦除的时候,需要将该位置1。
PG : 用于选择编程操作,在往FLASH写数据的时候,该位需要置1。
-- FLASH_SR(状态寄存器) --
BSY : 该位位1时,表示正在执行FLASH 操作。该位为0时,表示当前未执行任何FLASH操作。
库函数
-- 锁定解锁函数 --
void FLASH_Unlock(void); //FLASH进行写操作前必须先解锁,解锁操作也就是必须在FLASH_KEYR寄存器写入特定的序列(KEY1和 KEY2)
void FLASH_Lock(void); //在对FLASH写操作完成之后,我们要锁定FLASH
-- 写操作函数 --
FLASH_Status FLASH_ProgramDoubleWord(uint32_t Address, uint64_t Data); //双字
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); //字
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); //半字
FLASH_Status FLASH_ProgramByte(uint32_t Address, uint8_t Data); //字节
-- 擦除函数 --
FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector, uint8_t VoltageRange); //擦除某个sector
FLASH_Status FLASH_EraseAllSectors(uint8_t VoltageRange); //擦除全部的sectors
FLASH_Status FLASH_EraseAllBank1Sectors(uint8_t VoltageRange); //用于STM32F42X系列和STM32F43X系列
FLASH_Status FLASH_EraseAllBank2Sectors(uint8_t VoltageRange); //用于STM32F42X系列和STM32F43X系列
-- 获取FLASH状态 --
FLASH_Status FLASH_GetStatus(void); //返回 FLASH操作的几个状态
返回值 :
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;
-- 等待操作完成函数 --
FLASH_Status FLASH_WaitForLastOperation(void) //在进行写或擦除操作时,不能进行代码或数据的读取操作。
//在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。