1.内部FLASH的构成
STM32F407的内部FLASH包含主存储器、系统存储器、OTP区域以及选项字节区域。
一般我们说STM32内部FLASH的时候,都是指这个主存储器区域,它是存储用户应用程序的空间。STM32F407ZGT6型号芯片, 它的主存储区域大小为1MB。其中包含4个16KB扇区、1个64KB扇区和7个128KB的扇区。
- 系统存储区
系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、USB以及CAN等ISP烧录功能。
- OTP区域
OTP(One Time Program),指的是只能写入一次的存储区域,容量为512字节,写入后数据就无法再更改,OTP常用于存储应用程序的加密密钥。
- 选项字节
选项字节用于配置FLASH的读写保护、电源管理中的BOR级别、软件/硬件看门狗等功能,这部分共32字节。可以通过修改FLASH的选项控制寄存器修改。
2.对内部FLASH的写入过程
2.1解锁
由于内部FLASH空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给FLASH上锁, 这个时候不允许设置FLASH的控制寄存器,并且不能对修改FLASH中的内容。
所以对FLASH写入数据前,需要先给它解锁。解锁的操作步骤如下:
(1) 往Flash 密钥寄存器 FLASH_KEYR中写入 KEY1 = 0x45670123
(2) 再往Flash 密钥寄存器 FLASH_KEYR中写入 KEY2 = 0xCDEF89AB
2.2数据操作位数
在内部FLASH进行擦除及写入操作时,电源电压会影响数据的最大操作位数,该电源电压可通过配置FLASH_CR 寄存器中的 PSIZE位改变,见表 数据操作位数 。
最大操作位数会影响擦除和写入的速度,其中64位宽度的操作除了配置寄存器位外,还需要在Vpp引脚外加一个8-9V的电压源, 且其供电时间不得超过一小时,否则FLASH可能损坏,所以64位宽度的操作一般是在量产时对FLASH写入应用程序时才使用,大部分应用场合都是用32位的宽度。
2.3擦除扇区
在写入新的数据前,需要先擦除存储区域,STM32提供了扇区擦除指令和整个FLASH擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。
扇区擦除的过程如下:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何 Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位SER ”置 1,并设置“扇区编号寄存器位SNB”,选择要擦除的扇区;
(3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(4) 等待 BSY 位被清零时,表示擦除完成。
2.4写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位PG” 置 1;
(3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作;
(4) 等待 BSY 位被清零时,表示写入完成。
3.查看工程的空间分布
在上面map文件的描述中,我们了解到加载及执行空间的基地址(Base)都是0x08000000,它正好是STM32内部FLASH的首地址, 即STM32的程序存储空间就直接是执行空间;它们的大小(Size)分别为0x00001ae4及0x00001ab4, 执行空间的ROM比较小的原因就是因为部分RW-data类型的变量被拷贝到RAM空间了;它们的最大空间(Max)均为0x00100000,即1M字节,它指的是内部FLASH的最大空间。计算程序占用的空间时,需要使用加载区域的大小进行计算,本例子中应用程序使用的内部FLASH是从0x08000000至(0x08000000+0x00001ae4)地址的空间区域。所以,一个扇区的大小就够了。
4.FLASH读写实验
#ifndef __BSP_INTER_FLASH_H
#define __BSP_INTER_FLASH_H#ifdef __cplusplus
extern "C"{#endif#include "stm32f4xx.h"#define TEST_FLASH_SECTION FLASH_Sector_1 //这里用或操作直接两块section好像不太行
#define TEST_FLASH_BASE_ADDRESS 0x08004000
#define TEST_FLASH_SIZE 16*1024
#define TEST_FLASH_DATA 0x5a5aa5a5 void inter_flash_test(void);
#ifdef __cplusplus
}
#endif#endif
#include "bsp_inter_flash.h"
#include "stdio.h"void inter_flash_test()
{//1.解锁 2.擦除 3.写入 4.上锁 5.读取FLASH_Status status = FLASH_COMPLETE;FLASH_Unlock();status=FLASH_EraseSector(TEST_FLASH_SECTION,VoltageRange_3);if(FLASH_COMPLETE==status){printf("FLASH_EraseSector OK\r\n");}for(int i=0;i<TEST_FLASH_SIZE;i+=4){status=FLASH_ProgramWord(TEST_FLASH_BASE_ADDRESS+i,TEST_FLASH_DATA);if(FLASH_COMPLETE==status){printf("FLASH_ProgramWord OK\r\n");}}FLASH_Lock();__IO uint32_t* addr=(__IO uint32_t*)TEST_FLASH_BASE_ADDRESS;for(int i=0;i<TEST_FLASH_SIZE;i+=4){if(TEST_FLASH_DATA!=*(addr++)){printf("TEST_FLASH_DATA ERROR\r\n");}}
}