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