1、STM32 的内部 FLASH 简介
在 STM32 芯片内部有一个 FLASH 存储器,它主要用于存储代码,我们在电脑上编写好应用程序后,使用下载器把编译后的代码文件烧录到该内部 FLASH 中,由于 FLASH 存储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部 FLASH 中加载代码并运行,见下图:
除了使用外部的工具(如下载器)读写内部 FLASH 外, STM32 芯片在运行的时候,也能对自身的内部 FLASH 进行读写,因此,若内部 FLASH 存储了应用程序后还有剩余的空间,我们可以把它像外部 SPI-FLASH 那样利用起来,存储一些程序运行时产生的需要掉电保存的数据。
由于访问内部 FLASH 的速度要比外部的 SPI-FLASH 快得多,所以在紧急状态下常常会使用内部 FLASH 存储关键记录;为了防止应用程序被抄袭,有的应用会禁止读写内部FLASH 中的内容,或者在第一次运行时计算加密信息并记录到某些区域,然后删除自身的部分加密代码,这些应用都涉及到内部 FLASH 的操作。
2. 内部 FLASH 的构成
STM32 的内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及大小下表:
区域 |
块 |
名称 |
块地址 |
大小 |
主存储器 |
块 1 |
扇区 0 |
0x0800 0000 - 0x0800 3FFF |
16 Kbytes |
扇区 1 |
0x0800 4000 - 0x0800 7FFF |
16 Kbytes |
||
扇区 2 |
0x0800 8000 - 0x0800 BFFF |
16 Kbytes |
||
扇区 3 |
0x0800 C000 - 0x0800 FFFF |
16 Kbyte |
||
扇区 4 |
0x0801 0000 - 0x0801 FFFF |
64 Kbytes |
||
扇区 5 |
0x0802 0000 - 0x0803 FFFF |
128 Kbytes |
||
扇区 6 |
0x0804 0000 - 0x0805 FFFF |
128 Kbytes |
||
扇区 7 |
0x0806 0000 - 0x0807 FFFF |
128 Kbytes |
||
扇区 8 |
0x0808 0000 - 0x0809 FFFF |
128 Kbytes |
||
扇区 9 |
0x080A 0000 - 0x080B FFFF |
128 Kbytes |
||
扇区 10 |
0x080C 0000 - 0x080D FFFF |
128 Kbytes |
||
扇区 11 |
0x080E 0000 - 0x080F FFFF |
128 Kbytes |
||
块 2 |
扇区 12 |
0x0810 0000 - 0x0810 3FFF |
16 Kbytes |
|
扇区 13 |
0x0810 4000 - 0x0810 7FFF |
16 Kbytes |
||
扇区 14 |
0x0810 8000 - 0x0810 BFFF |
16 Kbytes |
||
扇区 15 |
0x0810 C000 - 0x0810 FFFF |
16 Kbyte |
||
扇区 16 |
0x0811 0000 - 0x0811 FFFF |
64 Kbytes |
||
扇区 17 |
0x0812 0000 - 0x0813 FFFF |
128 Kbytes |
||
扇区 18 |
0x0814 0000 - 0x0815 FFFF |
128 Kbytes |
||
扇区 19 |
0x0816 0000 - 0x0817 FFFF |
128 Kbytes |
||
扇区 20 |
0x0818 0000 - 0x0819 FFFF |
128 Kbytes |
||
扇区 21 |
0x081A 0000 - 0x081B FFFF |
128 Kbytes |
||
扇区 22 |
0x081C 0000 - 0x081D FFFF |
128 Kbytes |
||
扇区 23 |
0x081E 0000 - 0x081F FFFF |
128 Kbytes |
||
系统存储区 |
0x1FFF 0000 - 0x1FFF 77FF |
30 Kbytes |
||
OTP 区域 |
0x1FFF 7800 - 0x1FFF 7A0F |
528 bytes |
||
选项字节 |
块 1 |
0x1FFF C000 - 0x1FFF C00F |
16 bytes |
|
块 2 |
0x1FFE C000 - 0x1FFE C00F |
16 bytes |
各个存储区域的说明如下:
(1)主存储器
一般我们说 STM32 内部 FLASH 的时候,都是指这个主存储器区域,它是存储用户应用程序的空间,芯片型号说明中的 1M FLASH、 2M FLASH 都是指这个区域的大小。
主存储器分为两块,共 2MB,每块内分 12 个扇区,其中包含 4 个 16KB扇区、 1 个 64KB 扇区和 7 个 128KB 的扇区。如STM32F429IGT6 型号芯片,它的主存储区域大小为 1MB,所以它只包含有表中的扇区 0-扇区 11。
与其它 FLASH 一样,在写入数据前,要先按扇区擦除,而有的时候我们希望能以小规格操纵存储单元,所以 STM32 针对 1MB FLASH 的产品还提供了一种双块的存储格式,见下表:
1M 字节单块存储器的扇区分配(默认) |
1M 字节双块存储器的扇区分配 |
||||
DB1M=0 |
DB1M=1 |
||||
主存储器 |
扇区号 |
扇区大小 |
主存储器 |
扇区号 |
扇区大小 |
1MB |
扇区 0 |
16 Kbytes |
Bank 1 512KB |
扇区 0 |
16 Kbytes |
扇区 1 |
16 Kbytes |
扇区 1 |
16 Kbytes |
||
扇区 2 |
16 Kbytes |
扇区 2 |
16 Kbytes |
||
扇区 3 |
16 Kbytes |
扇区 3 |
16 Kbytes |
||
扇区 4 |
16 Kbytes |
扇区 4 |
64 Kbytes |
||
扇区 5 |
64 Kbytes |
扇区 5 |
128Kbytes |
||
扇区 6 |
128Kbytes |
扇区 6 |
128Kbytes |
||
扇区 7 |
128Kbytes |
扇区 7 |
128Kbytes |
||
扇区 8 |
128Kbytes |
Bank 2 512KB |
扇区 12 |
16 Kbytes |
|
扇区 9 |
128Kbytes |
扇区 13 |
16 Kbytes |
||
扇区 10 |
128Kbytes |
扇区 14 |
16 Kbytes |
||
扇区 11 |
128Kbytes |
扇区 15 |
16 Kbytes |
||
|
|
扇区 16 |
64 Kbytes |
||
|
|
扇区 17 |
128Kbytes |
||
|
|
扇区 18 |
128Kbytes |
||
|
|
扇区 19 |
128Kbytes |
通过配置 FLASH 选项控制寄存器 FLASH_OPTCR 的 DB1M 位,可以切换这两种格式,切换成双块模式后,扇区 8-11 的空间被转移到扇区 12-19 中,扇区细分了,总容量不变。
注意如果您使用的是 STM32F40x 系列的芯片, 它没有双块存储格式,也不存在扇区 12-23,仅 STM32F42x/43x 系列产品才支持扇区 12-23。
(2)系统存储区
系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、 USB 以及 CAN 等 ISP 烧录功能。
(3)OTP 区域
OTP(One Time Program),指的是只能写入一次的存储区域,容量为 512 字节,写入后数据就无法再更改, OTP 常用于存储应用程序的加密密钥。
(4)选项字节
选项字节用于配置 FLASH 的读写保护、电源管理中的 BOR 级别、软件/硬件看门狗等功能,这部分共 32 字节。可以通过修改 FLASH 的选项控制寄存器修改。
3、 对内部 FLASH 的写入过程
3.1、解锁
由于内部 FLASH 空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会结 FLASH 上锁,这个时候不允许设置 FLASH 的控制寄存器,并且不能对修改 FLASH 中的内容。
所以对 FLASH 写入数据前,需要先给它解锁。解锁的操作步骤如下:
(1) 往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB
3.2、数据操作位数
在内部 FLASH 进行擦除及写入操作时,电源电压会影响数据的最大操作位数,该电源电压可通过配置 FLASH_CR 寄存器中的 PSIZE 位改变,见下表。
电压范围 |
2.7 - 3.6 V |
2.7 - 3.6 V |
2.1 – 2.7 V |
1.8 – 2.1 V |
位数 |
64 |
32 |
16 |
8 |
PSIZE(1:0)配置 |
11b |
10b |
01b |
00b |
最大操作位数会影响擦除和写入的速度,其中 64 位宽度的操作除了配置寄存器位外,还需要在 Vpp 引脚外加一个 8-9V 的电压源,且其供电时间不得超过一小时,否则 FLASH可能损坏,所以 64 位宽度的操作一般是在量产时对 FLASH 写入应用程序时才使用,大部分应用场合都是用 32 位的宽度。
3.3、擦除扇区
在写入新的数据前,需要先擦除存储区域, STM32 提供了扇区擦除指令和整个FLASH 擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。
扇区擦除的过程如下:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位 SER ”置 1,并设置“扇区编号寄存器位 SNB”,选择要擦除的扇区;
(3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(4) 等待 BSY 位被清零时,表示擦除完成。
3.4. 写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
(3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作;
(4) 等待 BSY 位被清零时,表示写入完成。