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