01概述 这里的flash是指STM32F207内部集成的Flash
2 \" s+ z8 M8 t f4 W& I6 ]Flash存储器有以下特点
9 i; I/ H# o4 o( c6 h/ y- 最大1M字节的能力
- 128位,也就是16字节宽度的数据读取
- 字节,半字,字和双字写入
- 扇区擦除和批量擦除( B1 ~& P4 E9 m# T+ t* u$ |
7 B' ~/ M. H% Q3 B4 Z, `) ?
存储器的构成 " }, ^5 ~2 W/ h k; O
主要存储区块包含4个16K字节扇区,1个64K字节扇区和7个128K字节扇区。 5 K3 w6 W* s% R# _9 R2 b, k
系统存储器是用于在系统boot模式启动设备的。这一块是预留给ST的。包括bootloader程序,boot程序用于通过以下接口对Flash进行编程。USART1、USART3、CAN2、USB OTG FS设备模式(DFU:设备固件升级)。boot程序由ST制造期间编写,用于保护防止错误写入和擦除操作。
' P$ V+ G1 k9 r
512OTP(一次性编程)字节用于用户数据。OTP区域包含16个附加的字节,用于锁定响应的OTP数据。
! g6 ]7 z5 }. z7 l- X& ?
选项字节,读写保护,BOR水平,软件/硬件看门狗和复位当设置处于待机和停机状态。 # C1 e% k2 E0 d7 T
% e3 I3 K% w( {" g, U6 v( P& p
低功耗模式(参考参考手册的PWR部分) 7 p" |2 G1 q7 a3 i" ~3 S8 J1 W* w7 ^: G
对比参考手册的boot部分 9 o, s- ~8 J9 L6 f; z; v! f
当BOOT0为0是运行主存储区 + R4 E% v! ]4 g: g4 X
当BOOT0为1,BOOT1为0时运行系统存储区
& j0 h1 y% p/ q3 K3 h) Y- e
系统存储区运行的是ST出厂的bootloader代码,跳过过了用户的代码。如果在应用层代码锁定了JTAG管脚(将JTAG管脚用于普通GPIO),我们可以通过修改boot管脚状态,进入系统存储中,再进行debug。
; l+ h4 {# j9 d8 m- @ 02Flash操作. Q+ _1 @1 V8 ]
2.1、读取 内置的Flash是处于CortexM3的数据总线上的,所以可以在通用地址空间之间寻址,任何32位数据的读操作都能访问Flash上的数据。 - data32 = *(__IO uint32_t*)Address;
复制代码 + |3 }! b! k% D5 j- ~+ d
将Address强制转化为32位整型指针,然后取该指针所指向的地址的值,就得到了Address地址上的32位数据。
/ z4 l9 m/ Y- W" u& i* b+ a- f' S
C0 e# v3 e$ N+ U8 ]: J# V& L
2.2、擦除 Flash 擦除操作可针对扇区或整个Flash(批量擦除)执行。执行批量擦除时,不会影响OTP扇区或配置扇区。 - a9 }$ O4 B3 I! M& K6 T
扇区擦除步骤 - 1、检查FLASH_SR 寄存器中的BSY 位,以确认当前未执行任何Flash 操作
- 2、在FLASH_CR 寄存器中将SER 位置1 并选择要擦除的扇区(SNB)(主存储器块中的12个扇区之一)
- 3、将FLASH_CR 寄存器中的STRT 位置1
- 4、等待BSY 位清零
K+ e# ?4 S7 ~. o
/ a% E6 A0 e, F3 w& I$ T8 E4 E
# E0 k; A! G) z$ \4 Z
批量擦除步骤 : H8 w1 v0 ^- g; e8 \& s8 C$ x
- 1、检查FLASH_SR 寄存器中的BSY 位,以确认当前未执行任何Flash 操作
- 2、将FLASH_CR 寄存器中的MER 位置1
- 3、将FLASH_CR 寄存器中的STRT 位置1
- 4、等待BSY 位清零 s$ J* R5 v- w2 g
4 l# ^! [# Q" m {; L
2 p4 S8 h' q! H* C. ]( ]/ n# ^
ST提供相应的库函数接口 - + q$ v9 \! R7 T& l1 z( c
- FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector, uint8_tVoltageRange)" g- o. o( k$ }0 D: H$ x
- FLASH_Status FLASH_EraseAllSectors(uint8_tVoltageRange)
复制代码 ) x, u. d9 |' }9 q, r' E/ c0 ]
* b( G+ ]4 |/ q7 X. y8 {: m注意到,有个特殊的参数VoltageRange,这是因为 ) [3 c+ y h% a* k) H8 i' a* K( q
+ Q0 M$ i2 @4 r- l+ v7 F: Y q* o4 F这里就不再翻译了,就是在不同电压下数据访问的位数不同,我们是3.3V,所以是32位数据,这也就是在读数据是为什么要读取32位的原因。
/ L4 v) E) T( x" L- K n$ s
2.3、写入 写入之前必须擦除,这里和NorFlash操作是相同的 9 M# [7 e, E# ^ Z I1 @
复位后,Flash控制器寄存器(FLASH_CR)不允许写入的,去保护Flash闪存因为电气原因出现的以外操作,以下是解锁的步骤
8 @ ?* V) M7 J1 h: ^3 H9 K- k2 _- 1、在Flash 密钥寄存器(FLASH_KEYR) 中写入KEY1 = 0x45670123
- 2、在Flash 密钥寄存器(FLASH_KEYR) 中写入KEY2 = 0xCDEF89AB
~) C8 k, [: q& w& ?. p
; h O0 m% Q1 {
将FLASH_CR 寄存器中的LOCK 位置为1 后,可通过软件再次锁定FLASH_CR 寄存器 . m3 O# Z% O9 a
ST提供了库函数
# D! Z$ a2 Q0 N. B4 J
: J8 T' @' p0 e- FLASH_Unlock();//解锁9 V! X6 Z5 K5 s
- FLASH_Lock();//重新上锁
复制代码
+ U3 `# I" x, x) J1 m' s( I4 q5 i2 L. b
备注: 2 z2 |3 W' t( t+ [) n: X, s# D( s
当FLASH_SR 寄存器中的BSY 位置为1 后,将不能在写模式下访问FLASH_CR 寄存器。BSY 位置为1 后,对该寄存器的任何写操作尝试都会导致AHB 总线阻塞,直到BSY位清零
7 H8 T% y4 ]4 }. D8 g$ S
这要求我们在写入前必须判断下FLASH_SR寄存器中的BSY位。
4 T7 m/ W+ ^- `1 D/ j$ }
ST提供了对用的库函数
& [2 t. g) @5 w- R- FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR| FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
复制代码
) U6 o. @3 Y: k, ?) o写入步骤 & L2 l% v$ p7 M% v& N
- 1、检查FLASH_SR 中的BSY 位,以确认当前未执行任何主要Flash 操作
- 2、将FLASH_CR 寄存器中的PG 位置1。
- 3、通过不同的位宽对指定地址写入
- 4、等待BSY 位清零 F: d0 _6 A. s
! {- H6 ~; t( i9 K% j' a! ]
对于写入接口,ST提供相应的库函数,提供了8位,16位,32位的操作,因为我们是3.3V电压,所以使用32位写入接口 - FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data): z0 N, U" P# W- P4 e$ v0 |' h- |
复制代码
/ t6 ~& B' ~) Y2.4、中断 如果对于写入要求较高,可以使能中断,对于写入完成,写入错误都会有响应的中断响应。我也没有详细研究,参看Flash编程手册的15.5章节 - d& Z) }( ~& M6 P. _
03Flash保护/ u% H+ \ w! ?2 H2 {
3.1概述 Flash具有读写保护机制,主要是用过选项地址实现的。还有一次性编程保护
! s/ z# H$ c3 _+ \+ B/ r7 L5 T
这讲述了选项字节的构成
+ g/ t+ A# D7 Z. D. C1 r" s$ E8 p
用户修改选项字节 2 }1 v, j( R( `8 x
To run any operation on this sector, the option lock bit (OPTLOCK) inthe Flash option control register (FLASH_OPTCR) must be cleared. Tobe allowed to clear this bit, you have to perform the followingsequence:
5 r+ e8 J& U- I9 n 1. Write OPTKEY1 = 0x0819 2A3B in the Flash option key register(FLASH_OPTKEYR) 2. Write OPTKEY2 = 0x4C5D 6E7F in the Flash option key register(FLASH_OPTKEYR) The user option bytes can be protected against unwanted erase/programoperations by setting the OPTLOCK bit by software.
8 d' Q& N7 K* M1 O; n
这个上面讲述的解锁Flash相同,就是要写入不能的数值 ! b% V4 Q( H# S8 ~7 z* t% F
ST提供相应的库函数 ! ?- X7 n" r- X" J1 w
- ' K5 E9 ]3 t; p! B6 q) I5 J
- void FLASH_OB_Unlock(void)
i: m; A# M' W. b% O - void FLASH_OB_Lock(void)
复制代码
( j; ?9 I7 ~! a& D1 L9 Y; Z $ `+ f. z, {4 e; p }
修改用户字节的步骤
7 y) O( q$ i) H
- 1、检查FLASH_SR 寄存器中的BSY 位,以确认当前未执行任何Flash 操作
- 2、在FLASH_OPTCR 寄存器中写入所需的选项值
- 3、将FLASH_OPTCR 寄存器中的选项启动位(OPTSTRT) 置1
- 4、等待BSY 位清零
1 D! G ~7 d2 U9 a: }. j) C
; I! q" ]& }# X* y e% r+ @6 |
5 e9 c r, V% ^ j
3.2 读保护 从上面概述中得知,Flash读保护共分三个等级 1 等级0:没有保护
7 C2 p: i- \$ \% ?, [. a将0xAA 写入读保护选项字节(RDP) 时,读保护级别即设为0。此时,在所有自举配置(Flash用户自举、调试或从RAM 自举)中,均可执行与Flash 或备份SRAM 相关的所有读/写操作(如果未设置写保护)。
1 y% D* n9 A I, v. I3 {( [$ n% K( ` 2 等级1:闪存读保护
+ v$ n/ O* `! ]/ Y9 G$ w' q这是擦除选项字节后的默认读保护级别。将任意值(分别用于设置级别0 和级别2 的0xAA和0xCC 除外)写入RDP 选项字节时,即激活读保护级别1。设置读保护级别1 后:
\* n+ I8 p( e
-在连接调试功能或从RAM 进行自举时,将不执行任何Flash 访问(读取、擦除和编程)。Flash 读请求将导致总线错误。而在使用Flash 用户自举功能或在系统存储器自举模式下操作时,则可执行所有操作
. v1 n" m5 R5 R/ O9 h-激活级别1 后,如果将保护选项字节(RDP) 编程为级别0,则将对Flash 和备份SRAM执行批量擦除。因此,在取消读保护之前,用户代码区域会清零。批量擦除操作仅擦除用户代码区域。包括写保护在内的其它选项字节将保持与批量擦除操作前相同。OTP 区域不受批量擦除操作的影响,同样保持不变。 ! M4 a& J. {& E# C, e
只有在已激活级别1 并请求级别0 时,才会执行批量擦除。当提高保护级别(0->1,1->2, 0->2) 时,不会执行批量擦除。. 3 等级2:禁止调试/芯片读保护
6 F( s/ q% _) Z2 z5 t. u7 a注意:
2 L" i& n& K5 ~3 e3 e
在注意中写道,如果使能了等级2的读保护,永久禁止JTAG端口(相当于JTAG熔丝)ST也无法进行分析,说白了就是没办法再debug了,目前我没有使用到这个水平的读保护 读保护库函数 - void FLASH_OB_RDPConfig(uint8_t OB_RDP)
复制代码
2 `: {1 i# `2 _9 F. [查询读保护状态库函数 - FlagStatus FLASH_OB_GetRDP(void)
复制代码 \$ f m& U) U0 g8 C( m5 g
3.3 写保护 Flash 中的用户扇区(0到11)具备写保护功能,可防止因程序计数器(PC) 跑飞而发生意外的写操作。当扇区i 中的非写保护位(nWRPi, 0 ≤ i ≤ 11) 为低电平时,无法对扇区i 执行擦除或编程操作。因此,如果某个扇区处于写保护状态,则无法执行批量擦除。
J: S1 T: ~8 Z
- Q/ o4 G2 R ^! j" I1 U ?4 ~( `2 |% ?. x
如果尝试对Flash 中处于写保护状态的区域执行擦除/编程操作(由写保护位保护的扇区、锁定的OTP 区域或永远不能执行写操作的Flash 区域,例如ICP),则FLASH_SR 寄存器中的写保护错误标志位(WRPERR) 将置1。
' E4 s. N8 H8 Y, u- w }
* X1 c( u1 W: @4 j+ T! t+ r7 s X9 H4 n
写保护库函数
! {0 C: i0 b' f$ k- B8 j- void FLASH_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState)
复制代码 + O6 N' V$ t* w) A. K
- C5 v' f$ e0 E, M2 z& |查询写保护状态库函数
. ~4 i' c# U b* ~4 X) c' n. U$ @/ {
- uint16_t FLASH_OB_GetWRP(void)
复制代码 04一次性可编程字节
( G$ o( S$ v% n8 V. O( m( n5 d没有使用过,使用了芯片就废了吧,没有做过这个等级等保护,可以参看Flash编程手册的2.7章节
4 N* P. y7 F# \+ \7 G$ n 05 代码% S* V G. E' ]+ q: ~0 B6 e6 b
关于读写保护代码如何调用的问题,在stm32f2xx_flash.c文件中有调用说明.
+ `& o8 B& k' v$ v
$ n. R$ C/ S4 s, [: J' k& X7 D9 { |