STM32 Flash详解windows写保护错误
本文将根据ST官方的Flash编程手册,文档编号:PM0059,讲解STM32F207内部Flash编程。
01
概述
这里的flash指的是STM32F207内部集成的Flash
闪存具有以下特点
最大容量1M字节
128位,即读取16字节数据宽度
字节、半字、字和双字写入
扇区擦除和整体擦除
内存配置
主存储块包含4个16K字节扇区,1个64K字节扇区和7个128K字节扇区。
系统内存用于在系统引导模式下启动设备。此块为 ST 保留。它包含引导加载程序,用于通过以下接口对 Flash 进行编程。USART1、USART3、CAN2、USB OTG FS 设备模式(DFU:设备固件升级)。引导程序由 ST 在制造过程中编写,以防止错误的写入和擦除操作。
512 个 OTP(一次性编程)字节用于用户数据。OTP 区域包含 16 个附加字节,用于锁定响应的 OTP 数据。
选项字节、读/写保护、BOR 级别、软件/硬件看门狗以及在待机和停止状态时复位。
低功耗模式(请参阅参考手册的 PWR 部分)
比较参考手册的引导部分
当BOOT0为0时,主存储区正在运行
当BOOT0为1,BOOT1为0时,运行系统存储区
系统存储区运行ST出厂的bootloader代码,跳过用户代码。如果在应用层代码中锁定了JTAG引脚(将JTAG引脚用作普通GPIO),我们可以修改启动引脚状态,进入系统存储,然后进行调试。
02
快闪操作
2.1、阅读
内置Flash处于CortexM3的数据总线上,因此可以在通用地址空间之间寻址,任何32位数据读操作都可以访问Flash上的数据。
data32 = *(__IO uint32_t*)Address;
强制将Address转换成32位整型指针,然后取指针指向的地址的值,就得到了Address地址处的32位数据。
2.2. 擦除
Flash 擦除操作可以针对扇区或整个 Flash 执行(整体擦除)。执行整体擦除时,OTP 扇区或配置扇区不会受到影响。
扇区擦除步骤
1.检查FLASH_SR寄存器中的BSY位,确认当前没有正在进行Flash操作。
2.将FLASH_CR寄存器中的SER位置1,选择需要擦除的扇区(SNB)(主存储器块中的12个扇区之一)
3.将FLASH_CR寄存器中的STRT位置1
4.等待BSY位清除
批量擦除步骤
1.检查FLASH_SR寄存器中的BSY位,确认当前没有正在进行Flash操作。
2.将FLASH_CR寄存器中的MER位置1
3.将FLASH_CR寄存器中的STRT位置1
4.等待BSY位清除
ST提供相应库函数接口
FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector, uint8_tVoltageRange)
FLASH_Status FLASH_EraseAllSectors(uint8_tVoltageRange)
注意有一个特殊参数VoltageRange,这是因为
这里就不翻译了,但是不同电压下,数据访问的位数不一样,我们的是3.3V,所以是32位数据,这也是为什么读数据的时候要读32位的原因。
2.3. 写入
写入之前必须先擦除,和NorFlash操作相同。
复位后,Flash 控制器寄存器(FLASH_CR)不允许写入,以保护 Flash 存储器免受电气原因造成的意外操作。以下是解锁步骤。
1. 在Flash密钥寄存器(FLASH_KEYR)中写入KEY1 = 0x45670123
2. 在Flash密钥寄存器(FLASH_KEYR)中写入KEY2 = 0xCDEF89AB
将FLASH_CR寄存器中的LOCK位置1后,可以通过软件再次锁定FLASH_CR寄存器。
ST提供库函数
FLASH_Unlock();//解锁
FLASH_Lock();//重新上锁
评论:
当 FLASH_SR 寄存器中的 BSY 位设置为 1 时,FLASH_CR 寄存器无法在写模式下访问。BSY 位设置为 1 后,任何尝试写入此寄存器的操作都会导致 AHB 总线阻塞,直到 BSY 位被清除为止。
这就要求我们在写入之前检查FLASH_SR寄存器中的BSY位。
ST 提供了库函数
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR| FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
写作步骤
1. 检查FLASH_SR中的BSY位,确认当前没有执行重大Flash操作。
2.将FLASH_CR寄存器中的PG位置1。
3.通过不同的位宽写入指定地址
4.等待BSY位清除
对于写入接口,ST提供了相应的库函数,提供了8位、16位、32位的操作,由于我们使用3.3V电压,所以采用32位的写入接口。
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
2.4 中断
如果写入要求高的话,可以开启中断,写入完成和写入错误都会有相应的中断响应,我没有详细研究过,可以参考Flash编程手册15.5章。
03
闪存保护
3.1 概述
Flash 具有读写保护机制,主要利用选项地址实现。此外还有一次性编程保护
这描述了选项字节的结构
用户修改的选项字节
要对该扇区执行任何操作,必须清除 Flash 选项控制寄存器 (FLASH_OPTCR) 中的选项锁定位 (OPTLOCK)。要清除该位,您必须执行以下步骤:
1. 在Flash选项密钥寄存器(FLASH_OPTKEYR)中写入OPTKEY1 = 0x0819 2A3B
2. 在Flash选项密钥寄存器(FLASH_OPTKEYR)中写入OPTKEY2 = 0x4C5D 6E7F
通过软件设置 OPTLOCK 位,可以保护用户选项字节免遭不必要的擦除/编程操作。
这和上面说的解锁Flash是一样的,也就是写入一个不可能的值
ST提供相应库函数
void FLASH_OB_Unlock(void)
void FLASH_OB_Lock(void)
修改用户字节的步骤
1.检查FLASH_SR寄存器中的BSY位,确认当前没有正在进行Flash操作。
2. 在FLASH_OPTCR寄存器中写入所需的选项值
3. 将FLASH_OPTCR寄存器中的选项启动位(OPTSTRT)设置为1
4.等待BSY位清除
3.2 读保护
从上面的概述中,我们知道Flash读保护分为三个级别
0 级:无保护
当 0xAA 写入读保护选项字节 (RDP) 时,读保护级别设置为 0。此时,如果未设置写保护,则在所有启动配置(Flash 用户启动、调试或从 RAM 启动)中都允许进行与 Flash 或备份 SRAM 相关的所有读/写操作。
级别 1:Flash 读保护
这是选项字节被擦除后的默认读取保护级别。当任何值(除了分别用于设置级别 0 和级别 2 的 0xAA 和 0xCC)被写入 RDP 选项字节时,读取保护级别 1 被激活。设置读取保护级别 1 后:
- 连接到调试功能或从 RAM 启动时,不会执行任何 Flash 访问(读取、擦除和编程)。Flash 读取请求将导致总线错误。使用 Flash 用户启动功能或在系统内存启动模式下操作时,可以执行所有操作
-激活级别 1 后,如果保护选项字节 (RDP) 被编程为级别 0,则将对 Flash 和备份 SRAM 执行批量擦除。因此,在读取保护被移除之前,用户代码区域被清除为零。批量擦除操作仅擦除用户代码区域。包括写保护在内的其他选项字节将与批量擦除操作之前保持相同。OTP 区域不受批量擦除操作的影响,保持不变。
仅当激活 1 级并请求 0 级时才会执行批量擦除。增加保护级别 (0->1,1->2, 0->2) 时不会执行批量擦除。
级别 2:禁用调试/芯片读保护
注意:
注释里写了如果开启了2级读保护,JTAG口会永久失效(相当于JTAG熔丝),ST无法进行分析。说白了就是没法调试。我暂时没用过这个级别的读保护。
读保护库函数
void FLASH_OB_RDPConfig(uint8_t OB_RDP)
查询读保护状态库函数
FlagStatus FLASH_OB_GetRDP(void)
3.3 写保护
闪存中的用户扇区(0 至 11)具有写保护功能,以防止由于程序计数器 (PC) 失控而导致意外写入操作。当扇区 i 中的非写保护位 (nWRPi,0 ≤ i ≤ 11) 为低时,扇区 i 无法被擦除或编程。因此,如果扇区具有写保护功能,则无法执行批量擦除。
如果尝试对 Flash 存储器的写保护区域(受写保护位保护的扇区、锁定的 OTP 区域或 Flash 存储器永远不能写入的区域,比如 ICP)进行擦除/编程操作,则 FLASH_SR 寄存器中的写保护错误标志位(WRPERR)将被设置。
写保护库函数
void FLASH_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState)
查询写保护状态库函数
uint16_t FLASH_OB_GetWRP(void)
04
一次性可编程字节
我没用过,用了芯片就没用了,我也没做过这种级别的保护,可以参考Flash编程手册2.7章。
05
代码
关于如何调用读写保护代码的问题,在stm32f2xx_flash.c文件中有调用说明。
/** @defgroup FLASH_Group3 Option Bytes Programming functions
* @brief Option Bytes Programming functions
*
@verbatim
===============================================================================
Option Bytes Programming functions
===============================================================================
This group includes the following functions:
- void FLASH_OB_Unlock(void)
- void FLASH_OB_Lock(void)
- void FLASH_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState)
- void FLASH_OB_RDPConfig(uint8_t OB_RDP)
- void FLASH_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_STOP, uint8_t OB_STDBY)
- void FLASH_OB_BORConfig(uint8_t OB_BOR)
- FLASH_Status FLASH_ProgramOTP(uint32_t Address, uint32_t Data)
- FLASH_Status FLASH_OB_Launch(void)
- uint32_t FLASH_OB_GetUser(void)
- uint8_t FLASH_OB_GetWRP(void)
- uint8_t FLASH_OB_GetRDP(void)
- uint8_t FLASH_OB_GetBOR(void)
Any operation of erase or program should follow these steps:
1. Call the FLASH_OB_Unlock() function to enable the FLASH option control register access
2. Call one or several functions to program the desired Option Bytes:
- void FLASH_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState) => to Enable/Disable
the desired sector write protection
- void FLASH_OB_RDPConfig(uint8_t OB_RDP) => to set the desired read Protection Level
- void FLASH_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_STOP, uint8_t OB_STDBY) => to configure
the user Option Bytes.
- void FLASH_OB_BORConfig(uint8_t OB_BOR) => to set the BOR Level
3. Once all needed Option Bytes to be programmed are correctly written, call the
FLASH_OB_Launch() function to launch the Option Bytes programming process.
@note When changing the IWDG mode from HW to SW or from SW to HW, a system
reset is needed to make the change effective.
4. Call the FLASH_OB_Lock() function to disable the FLASH option control register
access (recommended to protect the Option Bytes against possible unwanted operations)
@endverbatim
* @{
*/
编程Flash,写保护,读保护代码开源
开源地址:
(提示:公众号不支持外部链接,请复制链接到浏览器下载)