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