STM32F407ZG开发板学习(12)
闪存 FLASH
简介
Flash 又称为闪存,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还可以快速读取数据(NVRAM的优势),使数据不会因为断电而丢失。
STM32 的 Flash 接口可管理 CPU 通过 AHB I-Code 和 D-Code 对 Flash 进行的访问。该接口可针对 Flash 执行擦除和编程操作,并实施读写保护机制。Flash 接口通过指令预取和缓存机制加速代码执行。


STM32F407ZG 的具体分区如下:

主存储器,存放代码和数据常数(如const 类型的数据)。从上图可以看出主存储器的起始地址就是 0X08000000 。当 B0 、 B1 都接 GND 的时候,就是从 0X08000000 开始运行代码的。
系统存储器,主要用来存放STM32F4 的 bootloader 代码,此代码是出厂的时候就固化
在 STM32F4 里面了,专门来给主存储器下载代码的。当 B0 接 V3.3 B1 接 GND 的时候,从
该存储器启动(即进入串口下载模式)。
OTP 区域,即一次性可编程区域,共 528 字节,被分成两个部分,前面 512 字节( 32 字节为 1 块,分成 16 块),可以用来存储一些用户数据(一次性的,写完一次,永远不可以擦除!!),后面 16 字节,用于锁定对应块。这里的一次性是指写入一次后,再次写入的话是前后相与的值,两次不相同则会置零。
选项字节,用于配置读保护、BOR 级别、软件 硬件看门狗以及器件处于待机或停止模式下的复位。
闪存的读取
STM32F4 可通过内部的 I Code 指令总线或 D Code 数据总线访问内置闪存模块。为了准确读取 Flash 数据,必须根据 CPU 时钟 (HCLK) 频率和器件电源电压在 Flash 存取控 制寄存器 (FLASH_ACR) 中正确地编程等待周期数 (LATENCY)。当电源电压低于 2.1 V 时,必须关闭预取缓冲器。

于是一般正常工作时(168MHz,3.3V),应设置 LATENCY 为 5 WS。


Flash 读取,即对 Flash 某个地址读一个字(32位),只要知道地址即可通过如下语句读取:
data = * (vu32 * )addr; //volatile unsigned int 32,每次读取需要重新取,不能直接读寄存器的值。
闪存的编程和擦除
执行任何 Flash 编程操作(擦除或编程)时,CPU 时钟频率 (HCLK) 不能低于 1 MHz。如果 在 Flash 操作期间发生器件复位,无法保证 Flash 中的内容。
在对 STM32F4xx 的 Flash 执行写入或擦除操作期间,任何读取 Flash 的尝试都会导致总线阻塞。只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能从 Flash 中执行代码或数据获取操作。
闪存的擦除和编程是通过设置寄存器的值来控制的。
编程步骤
- 检查 FLASH_SR 中的 BSY 位,确保当前未执行任何 FLASH 操作。
- 将 FLASH_CR 寄存器中的 PG 位置 1 ,激活 FLASH 编程。
- 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作:
— 并行位数为 x8 时 按字节写入( PSIZE = 00 )
— 并行位数为 x16 时按半字写入( PSIZE = 01 )
— 并行位数为 x32 时按字写入( PSIZE = 02 )
— 并行位数为 x64 时按双字写入( PSIZE = 03 ) - 等待 BSY 位清零,完成一次编程。
注意写入操作必须要在保证写入地址已被擦除。
擦除步骤
- 检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁
- 检查 FLASH_SR 寄存器中的 BSY 位,确保当前未执行任何 FLASH 操作
- 在 FLASH_CR 寄存器中,将 SER 位置 1 ,并从主存储块的 12 个扇区中选择要擦除的扇区(SNB)
- 将 FLASH_CR 寄存器中的 STRT 位置 1 ,触发擦除操作
- 等待 BSY 位清零
寄存器
访问控制寄存器 (FLASH_ACR)
用于使能/失能 数据缓存、指令缓存、预取 相关的功能,最重要的是在于低三位用于设置 LATENCY 的值。

控制寄存器 (FLASH_CR)
CR 有两种,分别对应 stm32f405xxx/407xxx/415xxx/417xxx 和 42xxx/43xxx 。这里贴出前者。


秘钥寄存器 (FLASH_KEYR)
此寄存器用于解锁 CR ,有固定的两个设置值,否则会将 CR 锁定。

状态寄存器 (FLASH_SR)
包括 BSY 繁忙标志 、各种错误标志、EOP 操作结束标志 。具体见官方手册。
一般来说只有使能了相关错误中断,这些错误标志位才有意义。
选项控制寄存器 (FLASH_OPTCR)
对于OPT的控制,具体见官方手册。
选项秘钥寄存器 (FLASH_OPTKEYR)
与 KEYR 类似,用于解锁 OPTCR 。

定时读写 FLASH 计数值
需求
定时读写Flash,开机读取Flash计数值,每10秒钟计数加1并重新写入Flash保存。
思路
使用通用定时器 TIM3 设定重装值使定时为10s,每次自动重装时转入中断函数读取 Flash 计数值自增,并重新擦除写入。
实验过程中的一些问题
TIM 相关
- 实验中发现 TIM 初始化时,最开始也会进入一次中断,因此会导致还没开始计时就自增了一次。解决方法是使用了一个标志位,首次中断不做处理。
- TIM 触发中断后,会自动重装计数值,且中断函数的执行和计数互不影响。也就是说虽然对 Flash 的操作会有一定延迟,但并不影响计时,也不影响下一次中断(经实验擦写大概需要1s)。
代码
tim3 的配置详情见我的另一篇文章: STM32F4ZG TIM
tim3 的中断函数:
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //判断发生中断
{
if(first_flag == 0) //首次中断仅打印计数值初始值
{
first_flag = 1;
printf("%d\r\n", counter);
}
else
{
u32 load[1];
LED1 = !LED1;
counter++;

本文详细介绍了STM32F407ZG开发板中闪存的读取、编程和擦除过程,以及如何通过控制寄存器进行操作。还阐述了定时读写Flash计数值的实现,利用TIM3定时器每10秒自增计数并保存到Flash中,同时展示了相关代码和实验结果。
最低0.47元/天 解锁文章
1269





