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