70.1 初学者重要提示
& L B- t" Z7 F/ }( m 本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。2 h. E* H" c( W1 v9 m
STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。
& Z0 r2 @6 z0 D( X! Y STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。6 E; _; ?5 J \' n9 l
HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。7 f; k( L7 i J8 T9 Q6 t( O
70.2 内部Flash基础知识. m" `! R1 w, Y! z: K
70.2.1 内部Flash的硬件框图% s8 x% i @' o+ K8 t; e
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。 r9 ?% f; ~: R8 c# \5 X
4 N$ ?! L/ K+ V8 b
; \/ D) l7 Q" H; d. _2 V
% m+ M( P$ z/ J+ }$ M. ^
通过这个框图,我们可以得到如下信息:
$ R6 A% U. E0 H# }4 |% C2 s, @+ w8 g7 ~7 g) ^; K
sys_ck时钟输入
8 h) E9 o/ F, S& RD1域总线时钟。- y( H- S5 |) E& Z5 y: o. ~
5 Z3 `# u/ d# B9 j1 i5 T po_rst输入7 q' V5 k6 ^5 Y5 s: n
Power on reset 上电复位。
2 p# [5 v) W. [# R( \& z) u; s: C6 ~' Z- q# Z6 z4 p3 ~( ` v0 T
d1_rst输入
( m- X u4 ?2 s. T& N) K% V' H8 e) _. YD1域系统复位。
6 J% Y! F( k6 t4 g& I# j, y4 M% b/ v- C' F. K
flash_it输出" `* X! z0 |) ^9 o* i
flash中断请求输出。/ ]- ^$ I/ m+ a8 U- B$ L
, m5 ~, p* ^8 _0 J' L, MSTM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
- [* U. I0 f9 k, K2 E$ Z/ f6 t. i# u* x: x/ N* R E
70.2.2 内部Flash框架
K' P. X- w2 N# L, A关于内部Flash的框架,了解以下几个知识点即可:
9 E( d6 v/ w: P0 x) [) z, Q) Z2 M+ a' d! {- M2 x! M, Q
256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
+ X7 M7 K8 z: {3 `* D$ R 两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
1 a6 h) }% h: u# `
7 {8 T8 Y1 b% R; U' r
$ I N9 u- t2 V$ g4 F' Z& [5 Q! {9 K: b& R. `1 v2 S* {" H8 S- R& {3 S
BANK1的地址范围:0x0800 0000到0x080F FFFF。
% ~ J* W. n+ K' x' S3 l- `
) q+ V% d6 L- g6 K8 A' g1 V; ABANK2的地址范围:0x0810 0000到0x081F FFFF。1 p8 l# k! X# k' C, J8 p: V
; a+ }1 q3 ~6 k" d
70.2.3 内部Flash读操作
4 W: V7 F; @' I* V$ l" MSTM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:
* [! K+ _5 g: i& {) x7 ], w9 h7 {% N+ j( d8 O3 b/ P4 f
' Z" p+ ?( I6 k' y$ x; g
: v8 e( z6 n2 c' T: b对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
* Q* a; A4 ^7 R
& Z- f8 y: _6 M' A5 K& p. x- @) e了解了这个知识点后,再来看下面的时序,非常具有参考意义:
- p9 F+ L, {. [
3 `2 z' J T- {' x; {" Z: A1 P注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。" M5 U$ z3 Y/ ?9 U3 \
/ r9 G* g5 _$ E' k* D8 f" H/ t9 u& I( N$ l, t
, `- l @, H. O' b. u
关于这个时序要要认识到以下几点:0 U8 J" o. L+ H; k5 S; i/ {' k
& |* j2 Z2 W0 x3 W* b" l
AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
6 a o) q. b( ^8 L4 L5 W4 p 由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
* ?* P7 r! b: m7 c* T5 L 如果不开Flash Cache的情况下,连续读可以提升性能。
) [) C$ y' q3 d6 ~/ i, c" u+ p( B& d4 L x
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
) r$ Z& u/ U; }, C5 o
: G- R9 V; ^; a! D8 e5 s+ {5 V
& M& l+ l o$ A8 |% h: H% j# ?$ k! l2 Q/ S% C3 z- o1 A
70.2.4 内部Flash写入和擦除操作1 v: j; n1 T1 {4 X8 c1 g6 [& _
最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。) Q( h- B9 }5 R4 Q
2 a j$ U, X7 e7 {+ l1 q
这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:
) Z: q$ [8 E" F5 K; @- |, d" T& ~+ B
先保证这块扇区空间之前已经擦除过了。
% k `9 n% x2 Q6 o6 p5 L& Z$ l* ]解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
! d7 [: w- t) y+ t; B检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。' n1 Q {* n2 u3 T7 w" J
' T& f, p# P* G4 Q6 f/ U. _! q W
Flash的擦除流程如下:% U1 s6 D' p" r7 g/ J7 ? C5 k
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。. M4 J& g/ t" i
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2# i- T- J; o2 `: a* q5 i
如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。
- W* t& Z' J4 z! K/ |6 O* M7 n
9 f$ \" i* i) {, ?% N- [* D6 z+ W
70.2.5 内部Flash读保护
) v) P( Y$ Q3 u$ M4 Z# D6 o内部Flash支持三级读保护RDP(read out protection)。
7 S) K! T1 g* v `+ e. q" @: b/ G n9 N; V9 T( E( J' C* D& x
Level 0(无保护)
+ D, C& `: M G& ]& N7 H% P9 z默认设置,所有读写和擦除操作都可以正常支持。7 [9 z- B! }0 L5 S
! f; L& P2 j2 C" O8 f
Level 1 (Flash连接保护)
O# C1 a8 Y H' x+ w" R0 ] 可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
8 P) ?. o8 p: d$ V1 ?5 u8 K 如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。; r/ ]9 p. s9 e# J) Z, T$ `8 o
如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。/ W* q/ K6 Y6 }* {
7 a/ `( z1 q3 g
Level 2(设备保护和自举保护)
+ M4 ?( s/ D* T/ Z2 d4 N) m4 O 所有调试特性被关闭。
0 b& G4 O& i; P% w D% y! F1 Y! B( G5 e 禁止从RAM启动。. V/ C" ~9 L5 V
除了选项字节里面的SWAP位可以配置,其它位都无法更改。0 ~! r3 E1 `' w* T9 @
禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
( j9 q' _2 T) h! a6 U
5 ^) b2 f% N2 W9 B A特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。, B M* c% |( |
: C% E3 N: C( d1 @
如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:
6 H8 d" g- h0 b/ U+ t: A5 u! x4 }. X F
3 G# |1 ?$ W, b$ F9 E
) K# H' T7 @4 Z0 d% R6 Y0 I# z) G I" n* w- J& s$ G/ ~& f# h
70.2.6 内部Flash选项字节
. i* G* ], C3 e* L& w! n1 lFlash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。
/ J8 i0 M" E( p1 O+ c
7 s% P4 J( s% V: k: I
1 C" U1 V5 }0 g6 B3 \) ^: q; ?! }3 l& z6 O Y* N4 \
70.2.7 内部Flash的ECC校验
! J; U3 U; e) z' i5 O& e8 ]这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。4 _4 Q9 l5 f1 y
3 M: ~0 D3 H* a. w" p对于STM32H7带的ECC校验,一般不需要用户去管理。9 o7 j5 i' D; L- Y; g! k7 j8 [
$ \ r/ w7 o0 ~6 H70.3 内部Flash的HAL库用法
; e2 `/ W4 K( a( Q: [6 }70.3.1 内部Flash结构体FLASH_TypeDef
6 L7 N9 x2 ^5 ]/ ~+ I. U内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
" ]# m2 B+ ?8 ]& K
1 k4 m& [! i! V, X* c- typedef struct
" Z2 O2 N8 N; O - {3 n& I1 B* N' C
- __IO uint32_t ACR; . Q! q& e* H+ u7 s% i0 M5 _
- __IO uint32_t KEYR1; - q& Y8 @, K4 ]: r1 @7 Q& H1 F6 c( d
- __IO uint32_t OPTKEYR;
1 |6 e# Y* I# a1 T( i* V - __IO uint32_t CR1; 6 p" t0 v& Y; i8 F
- __IO uint32_t SR1;
* F: C# B+ L8 v& Q/ T% ? - __IO uint32_t CCR1;
6 Z, P* d) N( M* k - __IO uint32_t OPTCR;
1 l. _! f* B4 w2 ]7 t- k* r$ B3 s - __IO uint32_t OPTSR_CUR;
: M! c' S% H' j( H1 p - __IO uint32_t OPTSR_PRG; 4 s$ y2 W; B0 K/ G- n( Z
- __IO uint32_t OPTCCR;
@- X9 Y. ]+ m& q7 p" E, z2 _ - __IO uint32_t PRAR_CUR1; 8 j# [8 o- s1 y V2 v; T2 s7 G* E ]
- __IO uint32_t PRAR_PRG1; ' F) d" ~; {( K
- __IO uint32_t SCAR_CUR1; - `# A2 N# @2 J: U/ Z1 y0 t& {3 E8 g! v
- __IO uint32_t SCAR_PRG1; " u# V- @. S8 ^ b4 @
- __IO uint32_t WPSN_CUR1; - n) [$ R. h& z, \( q
- __IO uint32_t WPSN_PRG1; & V6 e1 e1 H- J, ~' E5 }; Y6 F+ }
- __IO uint32_t BOOT_CUR;
, }1 N5 }( O! m+ z! _ - __IO uint32_t BOOT_PRG; 2 y) e7 Y+ v; x& D5 X" c' {
- uint32_t RESERVED0[2]; - X* x8 @6 x( `0 |( L9 r8 b
- __IO uint32_t CRCCR1;
3 N1 \8 H( x% |; U f - __IO uint32_t CRCSADD1;
, c, ]7 {& r+ {" z - __IO uint32_t CRCEADD1;
8 C$ T1 q$ i4 n3 ]; ~: u7 d - __IO uint32_t CRCDATA; 1 {( ?. A7 N9 L# V V
- __IO uint32_t ECC_FA1; 3 x. X l: C* R3 t) P
- uint32_t RESERVED1[40];
& ~8 n# {. g0 s; r7 W - __IO uint32_t KEYR2; 6 j/ k1 F4 `. I, a3 ^7 P" k# D
- uint32_t RESERVED2; 2 ^5 b7 V( c; I+ b/ U
- __IO uint32_t CR2; 1 ~ t4 i, T# g h
- __IO uint32_t SR2;
/ e( |, r; q5 t. y - __IO uint32_t CCR2; , }8 c& b0 K# k$ a$ t% r5 Z! }
- uint32_t RESERVED3[4];
. e/ N) F2 `& A" c& j - __IO uint32_t PRAR_CUR2;
, t R& }5 ~4 r3 j, @; e - __IO uint32_t PRAR_PRG2; 1 H; o, Z$ ~* p( O+ K% v
- __IO uint32_t SCAR_CUR2;
3 X" m/ B3 d) O; o q( p; v - __IO uint32_t SCAR_PRG2;
" _1 ]8 f P( L' D# g- l: J - __IO uint32_t WPSN_CUR2; 7 b; \2 H( i! o2 ^+ [# B1 E
- __IO uint32_t WPSN_PRG2;
" h: @( J! P& n - uint32_t RESERVED4[4];
$ l! `9 n3 x6 a) a+ c {& C$ a - __IO uint32_t CRCCR2;
4 K" L6 T0 P2 C, f( r1 M, R - __IO uint32_t CRCSADD2;
0 V7 I* j3 o' L1 b6 } - __IO uint32_t CRCEADD2;
1 r. h3 h/ ~4 j - __IO uint32_t CRCDATA2; 6 }& P0 _7 I8 s1 ]! [- \* q
- __IO uint32_t ECC_FA2;
- ^/ b6 D) y- ]4 P - } FLASH_TypeDef;
复制代码
9 q7 O3 p V) c0 X, E3 X这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。8 e! R7 [ Y, h) |$ d
; z% a6 _- b# q* J: }
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
5 C( |& t, R. U! X |- #define __O volatile /*!< Defines 'write only' permissions */
, J+ i& j( k# X' n( E* U5 p6 [) i - #define __IO volatile /*!< Defines 'read / write' permissions */
复制代码 r, E# T- b3 [2 k6 m: y g1 F. W
下面我们看下Flash的定义,在stm32h743xx.h文件。
: i) N8 q `6 }5 G; K. d/ b
' x0 M6 x8 H1 m4 J$ [- #define PERIPH_BASE (0x40000000UL)
& r* U$ K E8 X; d - #define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000UL)! c- ]# h5 u$ j* ]+ q
- #define FLASH_R_BASE (D1_AHB1PERIPH_BASE + 0x2000UL)) R' M; Y1 T( H9 w2 ?) S
- #define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码
- n% P/ X0 M* b我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。2 c: L* a' T1 w5 L6 n) \) W
8 h5 A$ _! N3 R; n
70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
3 P& t( z, s1 t5 D, l& Y% O A下面是做内部Flash擦除的结构体,用到的地方比较多:
7 ~8 I9 o3 j" W& C) q" d, X5 f% T s. ~+ s
- typedef struct6 b3 | f' C6 ?# Z
- {& I @# D8 q5 ?/ _/ ?6 U
- uint32_t TypeErase;
: h& s( f4 d# ? - uint32_t Banks;
Z3 ]( [/ p# W/ ^" f - uint32_t Sector; ' W# X! K* W+ C* T# @% B
- uint32_t NbSectors; / Q* j- B, ], D9 l% `+ m
- uint32_t VoltageRange;
% A/ `! m, C. k - } FLASH_EraseInitTypeDef;
复制代码 ! B4 h5 Q- f8 U( q4 B) q
下面将结构体成员逐一做个说明:
3 ?4 N: ?: A* k6 i1 c# P TypeErase+ G8 Y9 x0 S: V0 h: g K- s7 ^
$ U5 G" P( U+ e1 z4 a
+ }5 B: g* n6 I- @0 I- M7 x用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:% \7 o& H( @0 b
- ^- s% J; c1 y5 T# y5 Q/ r+ ?
- #define FLASH_TYPEERASE_SECTORS 0x00U /* 扇区方式擦除 */
4 ]7 ?% ?0 n7 H; B3 Y - #define FLASH_TYPEERASE_MASSERASE 0x01U /* BANK方式擦除 */
复制代码
" }. ]( q; S0 m Banks
" T5 J' L* P4 n1 d4 k用于选择要擦除的BANK,或者两个BANK都选择:
- g/ R& _! d6 q
; n2 j9 s0 s; I5 Q- `- #define FLASH_BANK_1 0x01U /* Bank 1 */
3 k$ h% a5 F% R! t - #define FLASH_BANK_2 0x02U /* Bank 2 */
! F: z) X4 n" U( B& Z/ `( f. _0 s0 k - #define FLASH_BANK_BOTH (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码 $ \8 X3 F: ]5 k' W/ g
Sector3 a2 s* @1 h% {4 A
用于选择要擦除的扇区:# T' P/ K/ j/ w) q1 K' q {5 O ]6 x
- #define FLASH_SECTOR_0 0U /* Sector Number 0 */& R4 |1 u, \! _) r
- #define FLASH_SECTOR_1 1U /* Sector Number 1 */7 K4 Z8 A) w5 ^2 Y/ L( T: E
- #define FLASH_SECTOR_2 2U /* Sector Number 2 */+ W1 b [8 m) z3 T9 E- t6 u4 A+ F
- #define FLASH_SECTOR_3 3U /* Sector Number 3 */: ^/ |0 Z; S2 L1 F2 y/ a
- #define FLASH_SECTOR_4 4U /* Sector Number 4 */7 U5 Y1 r' f- y+ q
- #define FLASH_SECTOR_5 5U /* Sector Number 5 */
" E5 e; a: S& v9 I7 Y, e. w3 A6 D - #define FLASH_SECTOR_6 6U /* Sector Number 6 */
" E5 y5 I. H! M8 }, e - #define FLASH_SECTOR_7 7U /* Sector Number 7 */
复制代码 8 X, Y( M! R3 M7 _. F8 J
NbSectors
1 c( i v4 o+ }" V+ } \" x* ~用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。
: ?$ a) [; ~3 ^* u/ U$ s/ a
7 k4 }& ?' P5 d VoltageRange) D! P7 v, S+ H0 T5 E2 r% o
用于设置编程的并行位数,电压不同,位数不同:
5 \; |. J( D. F- #define FLASH_VOLTAGE_RANGE_1 0x00000000U /* Flash program/erase by 8 bits */6 G; J6 \# U8 X& C7 `
- #define FLASH_VOLTAGE_RANGE_2 FLASH_CR_PSIZE_0 /* Flash program/erase by 16 bits */
* c E" n' M6 N1 A8 _6 b - #define FLASH_VOLTAGE_RANGE_3 FLASH_CR_PSIZE_1 /* Flash program/erase by 32 bits */
5 F7 ]- x8 |3 T6 S% V' W; e - #define FLASH_VOLTAGE_RANGE_4 FLASH_CR_PSIZE /* Flash program/erase by 64 bits */
复制代码 7 s+ l4 o" V7 d; `! j
; {9 X, x* b! r4 U7 M! j' H
70.3.3 内部Flash的操作总结$ s3 |% R0 g' T- ]
2 N1 Z1 V+ { a& b# ^) c: X, _# F6 w( C0 f8 l% h" m' D
使用方法由HAL库提供:- f" L* `4 H2 j
Flash编程函数操作流程+ `* B5 D$ Z7 V/ y1 B- D0 Z
Flash解锁函数HAL_FLASH_Unlock。
2 k( z$ X$ y7 p% n8 [7 o/ _ q Flash查询方式编程HAL_FLASH_Program。) g U5 h" Z& a) s
Flash中断方式编程HAL_FLASH_Program_IT。
% \1 |' B0 J1 v/ Z& W3 [6 _ Flash上锁函数HAL_FLASH_Lock。
3 r, A" I3 v) F ! D6 i) @) a0 M3 |5 W# o5 }4 V
选项字节编程流程
|! K1 P, m) u 选项字节解锁函数HAL_FLASH_OB_Unlock。
6 H+ j; ]+ C6 t 选项字节加载函数HAL_FLASH_OB_Launch。
3 Y1 l. E( E& s( a 选项字节编程函数HAL_FLASHEx_OBProgram。( s* \6 I* C& y7 G5 m |7 Y4 f
选项字节加锁函数HAL_FLASH_OB_Lock。
8 E' l+ }- j& i% c1 q
8 T% Y' ~6 B! g% H$ P Flash擦除流程
6 O& V/ s: C) W Flash解锁函数HAL_FLASH_Unlock。) ?& U4 T- w( x* E" z& I
Flash查询方式擦除HAL_FLASHEx_Erase。
& y5 t7 @3 Y- X% E9 l. R Flash中断方式擦除HAL_FLASHEx_Erase_IT。
1 e+ g& ]1 ^" y Flash上锁函数HAL_FLASH_Lock。
q+ n7 z4 M* I! n6 N+ \1 Q/ S+ Y3 N! w- q8 Q9 f/ D
9 v5 y+ N% G' X1 `6 Z
70.4 内部Flash源文件stm32h7xx_hal_flash.c
3 ~, i8 p6 H t' p6 t, R: M此文件涉及到的函数较多,这里把几个常用的函数做个说明:
9 O* t" ?" q9 ]' G0 u9 J! z7 O
' F5 {3 ~4 Q/ u: s2 v" Z HAL_FLASH_Unlock
, ]1 V8 s) F4 s3 s1 \ r/ X HAL_FLASH_Lock- U. Z& e! {& H- H M5 \
HAL_FLASHEx_Erase
, T9 a* m& i, U+ d9 }5 _ HAL_FLASH_Program. X$ c" `* {7 p7 Q( j( @3 _. L
$ N7 r& f# M8 N: P& o
70.4.1 函数HAL_FLASH_Lock7 q5 h" `/ o8 O8 R, G7 r
函数原型:
7 p$ U" |4 J+ Y1 t8 i8 b+ Q3 f- r0 t7 `; ]1 s
- HAL_StatusTypeDef HAL_FLASH_Lock(void)
1 A" a: ?1 Q# `6 [( g8 H) h, r - {
- I- D4 I G0 P! Q" q* f. [& L - /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */2 s9 T0 b' g0 J0 m' h" U% V
- SET_BIT(FLASH->CR1, FLASH_CR_LOCK);
+ F' O% J/ O4 Z% ]7 V: {" g/ n8 H - # x( t6 C' g# X" D$ d+ ~. M" E
- /* 验证Flash Bank1是否已经被锁住 */$ t+ w: k. V# L" G
- if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)/ x8 h# a) j% U7 ]( A+ j
- {
. Z* K) M4 l% j - return HAL_ERROR;4 l1 d, S; X- E' D' H9 b3 n! S# ~
- }
0 w$ n' }4 \; ~ - 2 H& i7 V& y2 M+ l' p
- /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
: D" l. O( O% f. R5 a* h( ^ - SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
9 f3 W1 E! f, b% u - 5 b8 f* J% a' n+ @6 }$ r9 `
- /* 验证Flash Bank2是否已经被锁住 *// m8 f& K, e2 s Z, D5 ~
- if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)
; E; f* j+ u t$ w* Y - {
' Z. A) {+ w+ @% r4 h p - return HAL_ERROR;( B7 f3 y3 u* y, R0 |( e
- }
) L. U/ T- D3 X* m6 \ - 8 L, Y3 F5 x! Q$ S a
- return HAL_OK;
3 A( N: l- \& z& { - }
复制代码 2 I" }, L- L+ i0 E& G+ b
函数描述:; f; }# s9 C* z1 L) s. F
9 V2 b: t% Q; J2 M
用于Flash加锁,加锁后将不能对Flash进行编程和擦除。. ~; M$ A7 O( I3 j: I% ^
: Q8 |/ p! s# z' k70.4.2 函数HAL_FLASH_Unlock
4 w( u1 a ]( l4 r7 W( Q函数原型:; C7 p% U6 ]: v: H, o
- HAL_StatusTypeDef HAL_FLASH_Unlock(void)9 Y( V3 @7 M. U9 e5 \* C: w
- {
: _% T4 l7 Z# G% c J, s+ \ - if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)& m) S& K+ K: O' B2 b( B3 W* t
- {8 K( O. l* X$ r" L; e3 @0 p* t
- /* 允许访问Flash Bank1 */
5 F9 _# D- h+ V. W$ F, K) U - WRITE_REG(FLASH->KEYR1, FLASH_KEY1);( e% I+ u( r2 ^. y( ^/ k
- WRITE_REG(FLASH->KEYR1, FLASH_KEY2);4 h; U. ~* Y; ?0 M5 ~9 D9 u
- * W7 a8 e5 D. M, f9 O9 [
- /* 验证是否已经解锁 */6 r% I! u3 r5 F3 s
- if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
# R2 _$ G# r: D8 A/ H2 H/ R+ p - {
/ U& q1 E: O% Z U, F0 l v: `1 v - return HAL_ERROR;( P% p7 R: o8 T4 w, G% G
- }8 g9 O5 J! ^* ~ K4 ? g8 D
- }) L% }, ~2 b$ V3 X ~/ v. v
' m3 n( B" r6 W6 Y6 O* D( r& v- if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)0 O7 s9 S2 \1 d
- { s. E3 ~& I0 I7 V9 v1 y# _7 u
- /* 允许访问Flash Bank2 */9 E4 T6 }" t& x
- WRITE_REG(FLASH->KEYR2, FLASH_KEY1);
2 C q g" r& G - WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
7 C0 T4 Z# W% o) Z# _1 U* k - 3 z' ]% d2 _# C f9 S$ X( `
- /* 验证是否已经解锁 */
" b. v9 r7 x. V! L c% t; d$ e( z - if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
- h7 E3 w6 r5 |2 z! L - {
7 c( U: E# l( P5 W: t. p" c - return HAL_ERROR;9 @- p/ a" q+ U* z* F/ Q1 W
- }
& I& c: k8 I! L& N) D# i. I# ]) n - }
# I9 g$ x0 S6 a# Y4 n0 H" i8 R
, a, ^6 C; G( r4 c2 k1 L0 }- return HAL_OK;: E* u* e2 \- d% l, ~
- }
复制代码
& K1 n: G- t5 [% g% b9 n函数描述:8 Q" F U. Z: V4 g. B. i) u
7 F$ t- E4 P8 e2 P; o: w( v
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。& c0 F# Q7 i2 `/ e
K- w+ ?. O; H2 X7 ?
70.4.3 函数HAL_FLASH_Program
* _% b) u; c2 @, @" K/ i函数原型:; v9 g2 u/ u5 ~1 z; Z
. M+ u* z# d0 L# I- HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)0 e5 w! U2 |' ]0 @8 H0 B% Y( Y
- {/ R1 ~" m8 r% N1 V" o
- HAL_StatusTypeDef status;
7 z$ _8 l: q5 A7 s' g% l/ s - __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;
* Q! j1 [- c }# | - __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;! u6 O1 i# _ A8 k! K# l
- uint32_t bank;1 K" W; t4 p j' Q8 u5 {- w. n8 u( Y
- uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;* X' B! O# H9 \
- 1 r) |! r3 A3 O
- /* 检测参数 */
; h, i7 [7 R: z" X5 ] - assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
6 D3 S0 D/ Y+ Z- Y+ w2 K: [ - assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));
0 \' k) `1 z% T& n* a$ U" J9 B$ u0 D - $ r& h% a; ?. V5 g; P( ^
- /* 上锁 */
, P8 A* {, q! n, X4 @ - __HAL_LOCK(&pFlash);! ^$ w9 g7 F# S+ g- {
2 t3 X7 B" I! ~; L7 T- S2 I' Y! H- #if defined (FLASH_OPTCR_PG_OTP)
% N, Z, i0 i4 C, \7 y2 F& G - if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))! j' Y5 C$ ~8 r! Y, Q9 N' |: S" _
- #else9 T! \. ^7 E* [$ S; g0 x6 ]
- if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))
* R( B; e/ t" x+ G& N, G* C/ i - #endif
# ^7 u/ D0 B$ O2 `& C: `" Z - {& A9 j2 R% o1 @- M! C. k
- bank = FLASH_BANK_1;. d. M4 t8 M% W& l: M8 V+ F5 C
- }1 w3 J E" l6 k/ P( g0 w
- else4 v9 c# `% L6 D- J% B9 q
- {
9 a3 A% ? L) o: ]" ?/ Y& ] - bank = FLASH_BANK_2;. C( J) q0 R$ _+ q
- }" ?; _+ ~3 ^ n2 l" e( L
- ' w2 H* j* N+ i6 b3 D1 h
- /* 错误标识,无错误 */% h, @! w6 k* {: ~# a
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
4 i5 [4 S% N) h
6 `- d9 V N7 { [8 q( h2 W- /* 等待操作完成 */7 @8 f5 E7 Q9 X1 T
- status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
$ @2 t* v+ \$ h4 [& _ - ( Y/ x3 Q0 _; [
- if(status == HAL_OK)' F/ W- h6 ?6 \) K8 ?- l0 R4 j
- {& ]$ o L% o. \) o# Q1 f
- if(bank == FLASH_BANK_1), N& x( p* v9 R- {; V( |
- {
6 _; g) L+ n' e: N - #if defined (FLASH_OPTCR_PG_OTP)
# Q- c$ Y, _7 f1 K$ ^ - if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)! n0 F. m0 ]: J( J x
- {
. c# I# T7 \- R) C - /* 设置OTP寄存器的PG位,使能可以编程 */
0 n4 F- Q; I* S$ ^ - SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);8 `* D" l" ]4 x: m3 |0 t
- }
3 y9 u2 z2 J% ~, J2 V5 M# \$ ~# X, R - else
. {) {- Z. |( h0 n) d - #endif 4 P( ~% _; @) M
- {( @5 i) l Y; Z
- /* 设置PG位,使能可编程 */+ r5 q, B8 y4 p
- SET_BIT(FLASH->CR1, FLASH_CR_PG);- {6 }' [ |' v9 d* V. R
- }; G* u8 |; N9 A. |
- }2 C3 S9 ?. a' @) s7 N/ z
- else
' M Y( P1 d* L% E- B4 F - {
5 u! P+ |. o- j) h2 u - /* 设置PG位 */
7 K$ k5 R* @% a5 @8 T, U - SET_BIT(FLASH->CR2, FLASH_CR_PG);
$ _* ?: B8 R3 d; x5 _! ~4 B1 s - }. f& ^' L" ?: ?0 I9 i2 a
- $ ]( _3 r- C' f% a, d' x
- __ISB();
3 Q0 ^ }0 v4 Q( D( ?" n - __DSB();/ d) ^6 ^7 N+ ]3 {; D) B' a: z4 G
! Y# f' g6 C2 Y' n- #if defined (FLASH_OPTCR_PG_OTP)- ], U2 o2 b2 u" y
- if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
# [# U( Y( _ V; t: U/ ^ - {
, j, _4 T! Q4 H% W1 X' { - /* 编程OTP(16 bits) */: O6 ~9 |5 j ?! E/ M/ c
- *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;* p r& C: ~5 |) f/ B/ V
- }
) S$ o0 T( Q. ]) ?2 Q$ O - else
6 f0 m5 D& t5 v a* `: v: N - #endif 4 [8 L' B* }% E2 W
- {
% H: `) M( S5 a1 } - /* 对Flash进行编程 */6 ~- r K& L2 [6 \% h0 P: k0 I
- do2 h% P4 l. {5 B: @2 \! z s. g
- {! U/ D# O# L6 f+ c* m! a" Y1 c! v
- *dest_addr = *src_addr;% o+ G/ i! I# t# \) u
- dest_addr++;
% X/ L7 r2 t, a( y - src_addr++;
5 R8 x' A: ]: h. B - row_index--;; N) @: B5 n: w2 K* Y" K
- } while (row_index != 0U);
) Q) d' n/ N4 f9 a - }5 L- P; ]8 {2 u
: [, u' t" s. c2 } k- H- __ISB();9 Z' H; w3 Y+ X- ^
- __DSB();
! L: p3 W [6 C1 A. K- M1 W; } - 2 _* y- N; k0 u* V3 g
- /* 等待最后一次操作完成 */
- x4 i) j0 {8 o6 [& ] - status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
0 V+ }# ]* L/ J$ R! X
- f0 F/ ]$ }4 B7 p% s* C- #if defined (FLASH_OPTCR_PG_OTP)
/ A& Q2 C- Z1 z+ |& l( \ - if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
8 k: f6 C' }9 N! w& ^ - {" P1 L. p* s3 w% T+ S) N- o
- /* 如果编程操作完成,关闭OTP PG位 */7 O2 v$ i9 A( ^) t! v
- CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);/ A3 G& h8 C# s: F& ]& ~7 ]
- }; m; f3 n! k. Q# U
- else
( R2 f/ m* T* K; T, M1 ` - #endif ' R! i& C T1 l
- {* X8 P$ w) i* d a( I8 f7 |
- if(bank == FLASH_BANK_1)- U+ c0 y0 \* G/ I" ~ r- o
- {9 `9 [: m( ]& t1 q# y# ]( t
- /* 如果操作完成,关闭PG位 */* X! {9 Q' f7 H" c; @2 `
- CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);
6 M, _0 c9 j3 s6 i2 K - }
- v1 U4 q- T, G' k5 l" S - else& s' D; U3 w4 M5 K
- {5 r. k# M$ \" U' U, a! x8 ?/ `
- /* 如果操作完成,关闭PG位 */' {/ m! W9 t$ \2 q9 i
- CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);+ a9 I2 }, @8 X8 X+ V5 Q. O
- }
) q1 E! P, G, a- v7 B - }
1 W n1 u6 K$ S: H5 G3 @$ u - }$ B: A O7 l1 @8 @3 X+ B. e+ g7 o3 J% P5 M
- 1 v Y l/ v9 W( y
- /* 解锁 */
V; a2 t- |; R! A$ W - __HAL_UNLOCK(&pFlash);
* t2 C/ N4 [3 v6 N; V
5 g9 K- Z9 h. {" s- return status;
; L# [8 o3 K; c- @! P2 V! L - }; S1 B4 v/ L' g/ u( A4 T9 j$ ^" |
- + i: o$ E6 `3 ], D3 k- S
复制代码
6 T! r; H) l* o# f8 {6 {% Q: R. Z函数描述:
, l3 n E1 p" y5 t此函数主要用于Flash编程,固定编程32个字节数据。
# M3 g0 j0 z i" [& \7 x/ d y, u* U- G. ~4 Z
函数参数:
' w7 ?( c) q' Z9 }第1个参数是要编程的Flash类型,支持两种参数:; L5 R) {$ q3 q U# `! a6 Y5 s% r
FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
6 y, T1 N6 r- H FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。
: A% V5 y% [0 R/ \5 k: a9 C
7 Q. J* i$ C& E+ c' Y* Y" ?第2个参数是要编程的Flash地址。
% n J T' A2 @
( P. T# V# B- H% K第3个参数是要编程到Flash的数据地址。
. R4 r( }" K: d6 R6 H, y( }+ z# y5 e返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。 d" {+ s9 O2 p4 q& p8 C0 e4 U+ t
; r+ H! Q1 g8 E4 r4 [
/ K+ P( H# i9 m注意事项:
: [4 M" [, n5 c5 o3 L 第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
9 e* q, `6 G& c$ {# ^0 P 第3个参数务必要是32字节的整数倍。
% T6 Q: M& y4 z k0 Y4 o8 `: O$ v% W3 O* m
70.4.4 函数HAL_FLASHEx_Erase
2 K2 U- t8 @# _8 j函数原型:0 N5 o' @4 M3 G" {/ o
. n0 I4 U, p6 W, y) F4 Y: R
- HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)
- @' d# g2 D ]$ ?0 I( }" W$ S; G - {
& l [9 N$ e# \! e( ^ - HAL_StatusTypeDef status = HAL_OK;
. S( q$ e8 f7 ?5 N6 W! }3 T - uint32_t sector_index;! z7 R) n3 B0 \+ u/ r) n ^
- 1 k2 ~) i: ]- b, k8 `4 E
- /* 检查参数 */
1 ], X2 Z% I- [- |6 x - assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
) i1 B- _5 u( q( }5 U - assert_param(IS_FLASH_BANK(pEraseInit->Banks));8 K5 w7 C0 l4 o! r' X7 \% j
: |/ n; H/ `- I) W# }9 s: n/ E- /* 上锁 */
- _ h1 Y h3 L4 b0 l1 g - __HAL_LOCK(&pFlash);2 ~, \3 [8 C" y* W" C: l: _
: P( I* j( h7 u( X- /* 无错误 */# d, o6 k# A0 P- j
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
- s9 X7 f4 z' Z6 | - p; i5 H- ?# A/ U: e* r
- /* 等待BANK1的操作完成 */
& A0 Y/ ^- G9 q6 Z3 w# `. { - if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
/ q( w6 t: f; j: s& z# z) ^0 c - {+ o* w3 k! U) i8 t2 e7 B
- if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
. }8 m; I+ ^2 C: l* |3 t. z G G# V - {4 L% i3 ?8 h9 {, j t
- status = HAL_ERROR;+ D* U& t6 @3 R: I$ z1 p+ X
- }
1 ?+ |" S' N$ ^) f3 d* U) X - }
9 Z; C5 y. k, J" Q - " o- b" _8 W- Q s- G. z! A
- /* 等待BANK2的操作完成 */
' b* I" b2 y- n/ n - if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
}6 W1 x% m8 F9 ` - {
9 h( h R9 |4 y; |" c r; S1 W# r - if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)" ?. J; w& C7 |* G5 m8 ?
- {
( j7 U9 P$ H- {3 Q6 D - status = HAL_ERROR;
7 Y- ~3 X' l& r* \2 ^5 d1 x - }
$ I3 `2 Z5 Z) l% l: G2 A - }/ t; ?4 s4 n* v
/ D+ f) f1 e5 n) H6 M- _' d5 t H- if(status == HAL_OK)6 H n) s: ~6 ?
- {- k- q1 b" L3 j1 V- `
- if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
% }$ ~3 L3 D2 j' [3 u# T9 `! v - {
' O4 h$ `( k# J% W" y. L( @ - /* 整个BANK1或者BANK2擦除 */
' f& h9 |4 @; J( ` - FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
" q- e5 d( _& I- @ - 7 H% v3 M/ @! ~* ^) C& i- P
- /* 等待操作完成 */1 ?' R& S; r2 x5 P" T% h
- if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
9 @8 W0 z* _# I: c" T - {% n* z3 R- M% F* J0 ~4 {, I" U
- if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
5 k4 }# V7 ?" j# c1 r - {: Q# o5 I0 f8 M; u
- status = HAL_ERROR;
2 l9 o0 S6 {& n5 m! `4 m) N a - }% C- X- F2 M _/ A
- /* 如果擦除完成,关闭BANK1的BER位 */
2 K; h4 d+ L0 d+ ]- k8 o- O - FLASH->CR1 &= (~FLASH_CR_BER);$ L9 W7 S8 L# K3 v. ` \
- }
; _, E5 I6 H8 _9 X% e; r - if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2): h; x- a- f) o: W) \! v
- {* p X, g; [, R k! Y
- if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
- J0 X8 }, C7 v - {' O8 K0 }4 D: }( a- _6 T9 X! q% O
- status = HAL_ERROR;
. X0 ` X H8 B" M& g0 N/ f' e - }5 N: C, C& m. S
- /* 如果擦除操作完成,关闭BANK2的BER位 */
# k* T6 W* x# B) ` - FLASH->CR2 &= (~FLASH_CR_BER);
" m' |+ o$ b8 l+ n, c. L - }
% |5 X! ]" K, s# A - }0 r7 w; p! P+ E" _: ?6 f
- else
5 ?/ \+ q* a! M1 q, R. P - {/ z" ~1 w7 _. ?4 x i
- /* 初始化扇区错误码 */
' o* I6 C, F* m6 S; P - *SectorError = 0xFFFFFFFFU;' f5 {3 m# B- x/ _3 y! E
- * }. P2 P1 ?. V! i
- /* 扇区方式擦除 */
( H5 G7 q+ R% ^" w3 h - for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector); K. f' \, z: {
- sector_index++)
0 V U/ n6 A3 ^$ a! {- z2 m; m( d' F/ G6 h - {
; a$ m- l, d1 E+ P: l: X - FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);5 D( u" m6 X$ h/ H. J, L
- 7 C( G5 x" s# o) I/ N! k5 h/ P
- if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)% U5 R7 d9 \% ^+ X( S4 n! G
- {8 ~2 U; i0 S. u4 M' q
- /* 等待BANK1操作完成 */, z7 V7 W; Z$ E* [, C, p
- status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);0 s& P9 L6 ~- O: v g
- 6 U, u' C9 w% p' ~2 D0 \
- /* 如果擦除操作完成,禁止SER位 */' H9 C9 F" W) w5 N
- FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));' E( l9 Q! \: |5 I- \" F1 n
- }( u) k! S& G2 {; {/ e! u. I
- if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
, p# ?0 F3 u0 l2 W, O& K2 _9 j& @ - {9 v& e: K/ M" S
- /* 等待BANK2操作完成 */! ?! B8 G' L" A
- status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);6 u1 p& w7 U9 M' s$ c1 Q
3 ^% l( Y) x3 v5 g- z( x- /* 如果擦除操作完成,禁止SER位 */7 q, d! y8 \6 W5 u; F; w$ _
- FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
: w3 F* ]! M1 m; Y - }
8 f- T- D/ `# G; |" D3 z L& v - . ], O& o3 r% @6 w* g2 R
- if(status != HAL_OK)
$ R3 l# o! D# K t0 B - {
. F A7 t1 b4 }9 G0 A - /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */
2 f& F' m$ y+ u: A! @: k# d - *SectorError = sector_index;' C% }* B9 q5 [# J2 N: `/ Q
- break;: C8 r X2 i3 _% F$ y$ Z
- }/ ^+ Q2 h) H) i* M, g/ m
- }
9 ~" a* j: W+ `4 m! A* b7 [/ l - }
; ~9 X$ s: W6 p" B/ P& X1 V5 n - }( M. L- q2 o* W3 y1 A4 G$ f
- 0 N2 I; J% `/ E8 `9 p
- /* 解锁 */- Q* m0 H8 N& S/ a
- __HAL_UNLOCK(&pFlash); ~ n6 O7 y/ W
- ' ?3 u0 T# f! U+ B: _$ R
- return status;5 g( p Q& e% [6 Z$ R% ~* A7 d# s
- }
. Q% b0 O; m& c) q
复制代码 7 [$ R. E( _5 J: D, u4 Q Z
函数描述:! q# x! f5 c' j7 L! r
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。' c) g+ H. @4 |
" a9 w7 N- M$ y' }( U
函数参数:4 L& T, c) t, _* e g4 e; t
第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。
% i5 Q) g+ x0 {6 P# R 第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。( D4 c; \. B8 i. b
返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。6 t3 z8 s2 Z& j+ M) }! s
7 E' Y8 ^7 x o. {: M
70.5 总结7 f5 Z' e* \5 K) X) s
本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。6 I/ Z2 b1 D3 `/ ~* n- C2 p* {% e
7 ^' K. H Q$ [& t2 X* x) J) }3 g3 K' M
: S1 O1 O) j& ^& z$ d) \ |