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