32Flash闪存的擦除和编程
执行任何Flash编程操作(擦除或编程)时,CPU时钟频率(HCLK)不能低于1 MHz。如果 在Flash 操作期间发生器件复位,无法保证Flash中的内容。
在对STM32F4的Flash 执行写入或擦除操作期间,任何读取Flash的尝试都会导致总线阻 塞。只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能从Flash中执行代码或数据获取操作。
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_CR 的 PSIZE 字段配置,PSIZE 的设置必须 和电源电压匹配,见表:

一、Flash 操作的关键限制条件
- CPU 时钟要求执行 Flash 擦除 / 编程时,
HCLK(CPU 时钟)不能低于 1 MHz,否则操作会失败,甚至可能损坏 Flash。 - 复位风险如果在 Flash 操作过程中发生复位,Flash 中的数据 / 代码可能会损坏,因此操作时要尽量避免复位或断电。
- 总线阻塞问题在擦除 / 写入期间,任何对 Flash 的读取操作都会导致总线阻塞,直到操作完成才能恢复。这意味着:
- 不能在擦除 / 写入时,同时从 Flash 中执行代码或读取数据
- 通常需要把擦除 / 写入的关键代码放到 RAM 中执行,避免 “操作期间读取 Flash” 导致死锁
二、Flash 编程控制寄存器解析
STM32F4 的 Flash 操作主要由 6 个 32 位寄存器控制,每个寄存器的作用如下:
| 寄存器名 | 核心作用 |
|---|---|
FLASH_ACR |
Flash 访问控制寄存器,配置等待周期(LATENCY)、预取缓冲、缓存等 |
FLASH_KEYR |
Flash 密钥寄存器,用于解锁 Flash 写保护,必须按顺序写入特定密钥 |
FLASH_OPTKEYR |
选项字节密钥寄存器,用于解锁选项字节的修改权限 |
FLASH_SR |
Flash 状态寄存器,标记操作是否完成、是否发生错误(如编程错误、擦除错误) |
FLASH_CR |
Flash 控制寄存器,控制擦除 / 编程操作的启动、扇区选择、操作类型(字 / 半字 / 字节) |
FLASH_OPTCR |
选项控制寄存器,配置读保护、BOR 级别、看门狗等选项字节参数 |
三、Flash 编程的标准流程(关键步骤)
结合这些寄存器,Flash 擦除 / 写入的标准流程是:
- 解锁 Flash 写保护向
FLASH_KEYR依次写入密钥KEY1 = 0x45670123、KEY2 = 0xCDEF89AB,解除 Flash 的写保护。 - 等待 Flash 操作空闲检查
FLASH_SR寄存器的BSY位,确保没有正在进行的 Flash 操作。 - 擦除目标扇区在
FLASH_CR中设置:SER位(扇区擦除模式)SNB位(选择要擦除的扇区号)STRT位(启动擦除)等待擦除完成(检查BSY位)。
- 写入数据在
FLASH_CR中设置:PG位(编程模式)PSIZE位(设置数据宽度:字节 / 半字 / 字)向目标地址写入数据,等待操作完成。
- 上锁 Flash操作完成后,向
FLASH_CR的LOCK位写 1,重新锁定 Flash,防止意外修改。
四、关键注意事项
- 擦除是前提:Flash 只能把位从
1改成0,要修改已写入的数据,必须先擦除整个扇区(擦除会把扇区所有位恢复为1)。 - 地址对齐:写入数据的地址必须和数据宽度对齐(如 32 位写入时,地址必须是 4 字节对齐)。
- 错误处理:操作后要检查
FLASH_SR的错误标志(如PGERR、WRPERR),及时处理编程错误或写保护错误。
补充:
一.编程位数是什么?
编程位数(也叫并行位数 / PSIZE),是 STM32F4 Flash 写入操作时,一次能同时写入的数据宽度,它决定了每次编程操作的效率和硬件支持的电压范围。
1. 核心概念
PSIZE 是 FLASH_CR 寄存器里的配置位,它的取值和供电电压强绑定,不同电压下,Flash 控制器能支持的 “并行写入位数” 不同:
PSIZE=00(x8):一次写入 8 位(1 字节),仅在 1.8V~2.1V 下支持PSIZE=01(x16):一次写入 16 位(半字),仅在 2.1V~2.7V 下支持PSIZE=10(x32):一次写入 32 位(字),仅在 2.7V~3.6V 下支持(开发板常用 3.3V 时用这个)PSIZE=11(x64):一次写入 64 位(双字),仅在 2.7V~3.6V 且使用外部高压Vpp时支持
2. 为什么要这么设计?
Flash 存储单元的编程操作需要特定的电压和电流条件,供电电压越高,控制器能驱动的并行单元越多,一次写入的数据宽度就越大:
- 电压低时,只能提供较弱的编程电流,一次只能驱动 8 位 / 16 位单元
- 电压高时(如 3.3V),可以提供足够的电流,一次驱动 32 位甚至 64 位单元
- 外部高压
Vpp模式下,能提供更高的编程电压,支持 64 位并行写入,效率最高
3. 实际开发中的影响
-
写入效率并行位数越高,写入速度越快:
- 同样写入 4 字节数据,
x32模式下只需要 1 次操作,x8模式下需要 4 次操作 - 开发板 3.3V 供电时,设置
PSIZE=10(x32)是效率最高的选择
- 同样写入 4 字节数据,
-
地址对齐要求写入地址必须和并行位数对齐:
x32模式:写入地址必须是 4 字节对齐(地址末 2 位为 0)x16模式:写入地址必须是 2 字节对齐(地址末 1 位为 0)x8模式:无对齐要求(可写入任意地址)
-
电压匹配限制必须严格按照表格设置
PSIZE:- 3.3V 供电设置
PSIZE=10(x32),如果强行设置PSIZE=11(x64),在无外部Vpp时会导致写入失败 - 低电压下强行设置高并行位数,会因为电流不足导致写入错误或 Flash 损坏
- 3.3V 供电设置
4. 代码配置示例(寄存器版)
// 解锁Flash
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
// 配置PSIZE(3.3V供电设置为x32,即PSIZE[1:0] = 10)
FLASH->CR &= ~(0x3 << 8); // 清除PSIZE位
FLASH->CR |= (0x2 << 8); // 设置PSIZE=10(x32)
// 启动编程模式
FLASH->CR |= FLASH_CR_PG;
四.位数 和 地址 的强制规则(必须遵守)
规则 1:写多少位,地址就要按多少位对齐
| 编程位数 | 一次写多大 | 地址必须满足 | 例子(合法地址) |
|---|---|---|---|
| x8(8 位) | 1 字节 | 任意地址 | 0x08000000、0x08000001、0x08000002 |
| x16(16 位) | 2 字节 | 地址能被 2 整除 | 0x08000000 ✅ 0x08000002 ✅ |
| x32(32 位) | 4 字节 | 地址能被 4 整除 | 0x08000000 ✅ 0x08000004 ✅ |
| x64(64 位) | 8 字节 | 地址能被 8 整除 | 0x08000000 ✅ 0x08000008 ✅ |
最关键(你 99% 会用到)
3.3V + x32 模式👉 地址必须是 4 的倍数!👉 地址最后两位必须是 00例如:
- 0x0800 0000 → ✅ OK
- 0x0800 0004 → ✅ OK
- 0x0800 0008 → ✅ OK
- 0x0800 0001 → ❌ 错误!不对齐
更多推荐

所有评论(0)