4. STM32 Flash编程模型
在STM32的量产烧录中,真正决定“能不能烧、烧多快、烧完能不能跑”的,并不是上位机软件,而是芯片内部的Flash编程模型。上位机发出的每一个擦除、编程、校验命令,最终都要落到Flash控制器和存储阵列上。理解页擦除、编程机制、选项字节以及写保护/读保护的作用,是设计稳定烧录流程的前提。
一、Flash存储阵列的组织方式
STM32的Flash并不是按字节随机写入的存储器,而是按“页(Page)”或“扇区(Sector)”划分的块结构。以常见的STM32F103系列为例,主存储区被划分为若干页,每页1KB或2KB;而STM32F4系列则按扇区划分,扇区大小从16KB到128KB不等。不同系列的页/扇区粒度不同,烧录算法必须与具体型号匹配。
Flash的物理特性决定了两个基本约束:
- 写入只能把位从1变为0,不能从0变回1;
- 擦除的最小单位是页/扇区,擦除后整页变为0xFF。
因此,任何一次“修改”Flash内容的操作,都必须遵循“先擦除、后编程”的顺序。如果目标地址所在页不是全0xFF状态,直接编程会导致写入数据与原有数据按位与,结果不可预期。
二、页擦除与编程机制
页擦除操作由Flash控制器执行。以STM32F1为例,典型流程是:解锁Flash(写入KEY1、KEY2到FLASH_KEYR)→ 设置FLASH_CR的PER位 → 选择页地址 → 置STRT位 → 等待BSY位清零。擦除完成后,目标页所有字节变为0xFF。
编程操作则以半字(16位)为单位。STM32F1要求每次写入一个半字,写入前需检查目标地址是否为0xFFFF。编程流程为:解锁 → 置FLASH_CR的PG位 → 向目标地址写入半字 → 等待BSY清零。若目标地址未被擦除,写入会失败并置PGERR标志。
// STM32F1 页擦除与半字编程示意(伪代码)
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
// 页擦除
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = page_addr;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
// 半字编程
FLASH->CR |= FLASH_CR_PG;
*(volatile uint16_t*)addr = data;
while (FLASH->SR & FLASH_SR_BSY);
在量产烧录中,擦除和编程的粒度直接影响烧录时间。例如,一个64KB的固件,若按1KB页擦除,需要64次擦除;若按16KB扇区擦除,只需4次。但扇区擦除会擦掉整个扇区,若固件只占扇区一部分,其余部分也会被清空。因此,烧录算法需要根据固件大小和扇区布局,选择“整片擦除”还是“按需擦除”。
三、选项字节:芯片的“配置开关”
选项字节(Option Bytes)是Flash中一块独立区域,用于配置芯片的启动行为、看门狗、复位方式以及读写保护。它不随主存储区擦除而改变,但可以被修改。常见的选项字节字段包括:
- RDP:读保护等级(0xAA表示无保护,其他值表示保护);
- nWRP:写保护位,按扇区/页设置;
- USER:看门狗、复位、启动模式等;
- DATA0/DATA1:用户自定义数据。
选项字节的修改需要先解锁,写入新值,再触发选项字节加载。修改后通常需要复位芯片才能生效。在量产烧录中,选项字节的配置往往与固件烧录一起完成,例如:先烧录固件,再设置读保护等级,最后复位运行。
四、写保护与读保护对烧录流程的影响
写保护(WRP)和读保护(RDP)是量产烧录中最容易导致“烧不进去”或“读不出来”的两个因素。
写保护作用于主存储区的指定页/扇区。若目标区域被写保护,擦除和编程操作都会被硬件拒绝,FLASH_SR的WRPRTERR标志置位。此时烧录器会报“写保护错误”。解决方法是先解除写保护(修改选项字节),再执行擦除和编程。在量产中,通常会在烧录前统一解除写保护,烧录完成后再根据需要重新设置。
读保护则限制外部调试接口(SWD/JTAG)读取Flash内容。当RDP设置为保护等级1时,调试器无法读取Flash,但芯片仍可正常运行。若尝试通过调试器读取,会触发总线错误,甚至导致Flash被自动擦除(部分系列在解除读保护时会擦除主存储区)。因此,在量产烧录流程中,读保护的设置时机非常关键:必须在固件烧录并校验通过之后,再设置读保护,否则会导致后续无法读取或校验。
五、烧录流程中的关键判断
结合上述机制,一个稳定的量产烧录流程通常包含以下判断点:
- 烧录前读取选项字节,确认当前写保护/读保护状态;
- 若目标区域被写保护,先解除写保护;
- 根据固件大小和扇区布局,选择擦除范围;
- 执行擦除后,回读目标区域确认全0xFF;
- 按半字/字编程,写入固件;
- 回读校验,确认写入数据与源文件一致;
- 校验通过后,按需设置读保护等级;
- 复位芯片,进入运行模式。
其中,“擦除后回读确认”和“编程后回读校验”是两道关键防线。前者防止擦除不彻底导致编程失败,后者防止编程过程中出现位翻转或地址错位。在量产环境中,这两步通常由烧录器自动完成,但理解其背后的Flash机制,有助于在出现异常时快速定位问题。
总结来看,STM32的Flash编程模型可以概括为“页擦除、半字编程、选项字节配置、读写保护约束”四个层面。在量产烧录中,烧录器需要根据芯片型号的页/扇区结构、当前选项字节状态以及固件大小,动态决定擦除范围、编程顺序和保护设置时机。只有把这些机制理解清楚,才能在面对“烧录失败”“校验不通过”“芯片被锁死”等问题时,快速判断是擦除不彻底、写保护未解除,还是读保护设置过早导致的。