你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的内部Flash基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
. N8 T# p$ j8 H! z4 f1 u8 [  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
1 ?/ R4 q; S: k- g- w9 ~1 Z  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。+ G  i5 f+ \' t; m
  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。
4 Z) @; f2 S* P8 j# C/ X# ]  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。  C: `# E2 o1 ?
70.2 内部Flash基础知识
- h' f$ [# q3 [) V8 _1 p70.2.1 内部Flash的硬件框图
. w2 H8 w+ t* a, y; J7 l& {
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。8 k) M' I6 ~) i) t4 T( B
9 u$ _$ C0 x) y& v) d' i7 l
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
3 G5 J9 H  i7 V

% p6 r5 ^* j& Y5 }通过这个框图,我们可以得到如下信息:% \2 h3 G$ B7 g: t1 ]
, i/ ?1 c5 F2 Y8 V. u! I3 o
  sys_ck时钟输入
/ O2 P0 N( S  gD1域总线时钟。% ?" i6 Q" O  L. k

, Q7 [% x4 F. L: a* ~, d  po_rst输入: G+ i5 y5 O$ {6 U  I
Power on reset 上电复位。
: r5 @1 D$ S1 C9 X
# C* f6 h$ [) q( f6 C6 `0 n  d1_rst输入* b  g0 G1 |5 E, e7 }$ B
D1域系统复位。
/ l. T1 V/ l$ D7 K' {5 O/ k8 L
+ N* M$ _- a! u5 W  flash_it输出) t! n7 w" q- s: l+ d& w& C
flash中断请求输出。
; L0 q. z( j* N0 Z0 H) @
/ G; i+ _- O# v( e# X2 NSTM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
, t" ~4 n1 q4 R$ t/ b
6 ~$ R# M- \  G7 U0 X70.2.2 内部Flash框架
! i7 d6 A5 M* {. T! o4 m关于内部Flash的框架,了解以下几个知识点即可:9 f! V4 v* ]9 w; n& N, n

' e# c5 C' h- Y2 T3 T, r. {# W5 e  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
. h) }) K$ I6 C" p- y0 O  V  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。4 i3 g( V. V1 }9 h# Q
7 \! y; ^- Z# p9 K3 f+ B% ~- ]% j5 o
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

8 {$ m5 k" z( v0 i) H) ]6 K
& F+ T: m0 e* E7 FBANK1的地址范围:0x0800 0000到0x080F FFFF。
' y3 A% t  l2 s' U7 T5 H5 E6 i# x5 r3 X
BANK2的地址范围:0x0810 0000到0x081F FFFF。! v# S( v8 z; U3 f6 h
" N+ d2 j* D+ b1 H2 f: o
70.2.3 内部Flash读操作9 j) L8 v" a3 c7 L
STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:
; J. r! b* j: k3 {) H  W& E
7 s, I1 M5 W( Z  ?( K
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
/ ~3 [2 p1 l! H0 C$ T2 L2 _
; V# z) \) C2 n0 @! l% _9 }) b
对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。, Z  o4 u, }- O+ J" S% `" j
. x+ u& A* W5 F. D* {8 V
了解了这个知识点后,再来看下面的时序,非常具有参考意义:
3 M% f" o# I/ I6 C9 K2 i3 y3 b1 C; q! `+ ^4 k3 h# G
注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。0 f, D6 P9 [: a
9 H1 ~  ]$ X. x: n" O6 t% F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

3 K1 k  z) m) W0 a) g5 w& y; w" o  B1 a/ J' z) K6 ~
关于这个时序要要认识到以下几点:
2 M/ X2 c# ]0 J0 `) n# k, _2 a1 r/ }7 @5 U' j
  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
; G) m  I5 N  f5 R7 l  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
9 p2 t8 }3 Z' d$ _* Y! L* ^  如果不开Flash Cache的情况下,连续读可以提升性能。' o: ]. q" c$ z" {. V' j. O) c

* P, \' T9 {6 v  s4 R+ Y3 L7 f" D下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。; A9 L' N+ J6 ]7 j
* W/ y1 b9 s* Q( z
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

+ G0 K! g- m, a% [$ g
! q1 h4 x( W, ?/ R1 l  n  G70.2.4 内部Flash写入和擦除操作) L9 x+ M8 D# Q$ V9 O1 R
最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。, `  B! w' D! D  h9 l8 H& e# ]
" _+ o* J/ c8 a$ @# w3 @9 y$ J
这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:3 l, [1 v! L" `7 D: P7 p
  `  a  {+ z- }
先保证这块扇区空间之前已经擦除过了。3 N/ Q7 ?. z3 h
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。+ _5 [4 R: d2 T8 [6 u
检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。' @2 O6 I3 \+ s3 d1 `1 `& P  t
9 j1 b( F$ m5 b7 g2 p. T5 _
Flash的擦除流程如下:
2 \: [- i" O" o0 ^; S3 y解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。1 _/ ~3 T8 H6 G! C: f. s
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2
9 V5 s4 Z  u/ _; t如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。  F( x; e9 Q: A3 z9 b
: V5 i. ^: p9 M" L: j

9 {  Z1 L2 s" e" a70.2.5 内部Flash读保护
; y& w& @6 [- s( K! B( W) r% {内部Flash支持三级读保护RDP(read out protection)。: a8 d1 j% l7 _; x* b4 n1 P
3 z' K1 _0 r+ p
  Level 0(无保护)8 E: W/ d1 f4 h6 `& |: {
默认设置,所有读写和擦除操作都可以正常支持。$ N2 Z0 K9 F; l* F9 Z3 B

4 y7 r4 i; p2 v: A+ D- T3 `9 y/ |* S  Level 1 (Flash连接保护)5 |' w1 I  C- D7 N# M: c% i5 j  R7 H. l
  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
# @" c3 p+ z) M  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。7 y1 z$ U3 H# n) p8 M/ ~
  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。
8 I! G/ ^9 p5 O/ L+ C5 e2 p : I: O9 _5 n1 Q) p1 ]& e+ B: F
Level 2(设备保护和自举保护)
# i4 v/ V0 X  q" l  所有调试特性被关闭。
  v& N" ]1 _; e* q% B' X' t: n  禁止从RAM启动。0 B; T8 {, W3 ]5 `7 K6 |
  除了选项字节里面的SWAP位可以配置,其它位都无法更改。0 _2 a6 c& h. m) Z* B/ f
  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
1 N* _2 r4 P4 i  B) {' p$ x3 U3 T6 D% S
特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。
( i$ D  W  H( ?1 S% P4 a
' K$ C" n- Y8 {! i) a. T如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:
4 p! K+ U; Q. G" y) y3 A
+ i" b( M: S9 |, J
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
5 @& l9 j7 Z0 n* @/ J

' b2 B) k+ K4 b! Q3 Y
% N; X( q  N6 a: F70.2.6 内部Flash选项字节* K0 d5 Z0 e; x% x4 {
Flash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。1 p; d6 G) C7 f# z4 K8 b4 F
+ n+ I0 F; r/ A
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

1 I9 S6 b' e* f: B! L$ n% C, [0 @7 n0 ^% I* j/ o8 l
70.2.7 内部Flash的ECC校验
9 P+ h+ X3 W$ ^. ?# T! y" H这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。
* D/ D+ A8 _3 X, c7 |9 `4 C' n4 H7 L9 [: c
对于STM32H7带的ECC校验,一般不需要用户去管理。
6 J: j0 q8 s6 v2 P) Z% H5 t! N# l7 I. I0 e( R& v
70.3 内部Flash的HAL库用法
" _' l7 G5 s% n70.3.1 内部Flash结构体FLASH_TypeDef
: c: [9 f8 v' L% N1 P/ ^( j内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
. c4 d* H4 z9 ^+ a- o' O0 L) @, h. `  g$ C! F0 i5 r. C7 f) X
  1. typedef struct: l- ]6 D$ k6 z( s
  2. {
    5 q; P$ s2 s3 o
  3.   __IO uint32_t ACR;            
    + U. W' r! V. q5 e1 E/ G" _
  4.   __IO uint32_t KEYR1;           . r7 p& @; f. f1 U
  5.   __IO uint32_t OPTKEYR;         
    8 z# X" o7 \/ S2 |
  6.   __IO uint32_t CR1;            9 f( q4 ~0 G' u. r
  7.   __IO uint32_t SR1;             ' e* V' @9 m) |0 q9 C
  8.   __IO uint32_t CCR1;          ( _6 i& x1 f3 ?6 I$ i0 }& Z
  9.   __IO uint32_t OPTCR;           # O' O2 S8 `( l8 {6 H  o) l
  10.   __IO uint32_t OPTSR_CUR;       9 r, v2 l" d8 C& A' u6 W! z
  11.   __IO uint32_t OPTSR_PRG;      
      O" b) y1 e% L7 o
  12.   __IO uint32_t OPTCCR;          " W- f, u3 ~: Z5 j
  13.   __IO uint32_t PRAR_CUR1;       9 m4 y* n; z) U( D5 U
  14.   __IO uint32_t PRAR_PRG1;      
    9 E% C: Y" _) a' n
  15.   __IO uint32_t SCAR_CUR1;      
    ) f) f2 l- Z# k' a7 [3 M8 x. o6 C& ]
  16.   __IO uint32_t SCAR_PRG1;      
    6 ]7 X7 i& n5 M+ V7 X
  17.   __IO uint32_t WPSN_CUR1;      
    3 g  Y2 c: |" K" v- v
  18.   __IO uint32_t WPSN_PRG1;      
    ( _. M  _- @* p  |& i3 ^* X# M7 E
  19.   __IO uint32_t BOOT_CUR;      
    7 G: h( S$ ^* ?, M5 ]3 C1 f. V
  20.   __IO uint32_t BOOT_PRG;      
    # q7 Z- r, M! z7 I3 c1 \* {
  21.   uint32_t      RESERVED0[2];    $ r( S; t; G3 z$ F/ L- S
  22.   __IO uint32_t CRCCR1;         
    & \) Q' q3 E+ v
  23.   __IO uint32_t CRCSADD1;      
    ) X! ]& R+ M! D$ ^
  24.   __IO uint32_t CRCEADD1;        / H! y: p2 p5 @' C* b8 u9 P
  25.   __IO uint32_t CRCDATA;         
    " |$ i9 M+ G6 v* l6 u
  26.   __IO uint32_t ECC_FA1;         ' A' D* o: `# Z1 O
  27.   uint32_t      RESERVED1[40];  
    $ Z" b$ C5 @' f+ Z# p: c: _
  28.   __IO uint32_t KEYR2;           
    4 N/ }) R) ^$ L3 s! D7 L& [
  29.   uint32_t      RESERVED2;      5 E4 F0 P- L8 \' E. c/ T
  30.   __IO uint32_t CR2;            
    , l; A& Q$ d" F4 B- V  q# Q9 L
  31.   __IO uint32_t SR2;            
    # G$ [4 c4 l& V; j( S& X: \' O
  32.   __IO uint32_t CCR2;            3 A% U% S9 N4 h" l# w4 g
  33.   uint32_t      RESERVED3[4];   
    1 u/ t/ ^4 H: `3 b8 W# c
  34.   __IO uint32_t PRAR_CUR2;       ) r/ g- r$ N5 [
  35.   __IO uint32_t PRAR_PRG2;       ' `* s* ^/ [! d5 x
  36.   __IO uint32_t SCAR_CUR2;      
      z8 l9 t# C  Q' n( o, S
  37.   __IO uint32_t SCAR_PRG2;      : `$ D! v2 ^1 f! F/ r
  38.   __IO uint32_t WPSN_CUR2;      
    ' T3 t% F. w) x% o) M3 e
  39.   __IO uint32_t WPSN_PRG2;       ( G8 N  w& G" y1 E& ~$ _
  40.   uint32_t      RESERVED4[4];   
    ' Y- o/ h9 |* ^; u2 q; F; P( r( j
  41.   __IO uint32_t CRCCR2;          + |9 K& P0 ~9 |" Z+ _4 s
  42.   __IO uint32_t CRCSADD2;        
    0 w# }6 p4 @0 ?+ I) m- |( o  o
  43.   __IO uint32_t CRCEADD2;        7 p# N5 p: e6 ]# Y5 @1 a
  44.   __IO uint32_t CRCDATA2;        
      E' z5 K0 k8 N$ r! q
  45.   __IO uint32_t ECC_FA2;         
    ' f! L* n  z. m+ \9 x
  46. } FLASH_TypeDef;
复制代码

' @) ?+ ^+ R" U1 F6 a这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
; v0 o8 r+ I2 w& `/ {9 a3 Y- N  t' b2 a* o4 R6 z) B
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
7 T! R- q2 Z7 N
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    $ K6 E0 E- E# B* r: J3 P2 l
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

5 M7 V0 c6 a2 i3 T下面我们看下Flash的定义,在stm32h743xx.h文件。
. [8 u" L9 g3 C# }2 D) P* H) ]9 u3 [% e5 r4 f9 ~# r
  1. #define PERIPH_BASE              (0x40000000UL) 5 @$ V, P  }. e
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL)" O. q0 p* E0 [- D7 |2 x( D# A
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)
    ( l, G* I: T8 w1 C$ I/ Y0 g% @
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码
/ I( q0 ]4 {. B2 c# T9 W
我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。' V1 Q, f% O7 l: \5 Y

: o4 K1 f1 `% _7 W70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef, r4 t3 o) ]  B7 t5 w! c/ X
下面是做内部Flash擦除的结构体,用到的地方比较多:% J9 Y; f' D8 g! U' N

6 O* y5 Q* s% `' p9 K$ c
  1. typedef struct
    # C0 u  x9 X) A0 U/ \5 d
  2. {" [5 V8 R2 s( Z# O; w& z5 Z3 X
  3.   uint32_t TypeErase;  5 h2 m# o" Z) {; R% a
  4.   uint32_t Banks;      
    " X3 v; S' `5 {8 a& Q9 M
  5.   uint32_t Sector;      
    7 l$ f7 R* l6 r7 m$ v& H4 g4 I
  6.   uint32_t NbSectors;   
    + [8 H. A  E4 H5 P$ U
  7.   uint32_t VoltageRange; : N6 N0 Z4 v% A4 V0 B0 [
  8. } FLASH_EraseInitTypeDef;
复制代码

  E6 b" o) K4 ~2 ~8 i% l& O下面将结构体成员逐一做个说明:* [4 J5 }* t" n5 ~) L4 a* M
  TypeErase( Q8 V  Z2 y. b& |
# `/ f; f  _. h+ q" M4 Z
( V  }$ I3 Y- D  T; o+ r
用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:
9 N' g4 w$ M. J' b
7 d" X  n% t2 a6 }
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */3 M9 x( R5 N' Q
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码

5 X1 Q6 o5 Q# U& j* b+ b* h# a& ]  Banks5 K- a$ `' \# z4 y1 e1 M
用于选择要擦除的BANK,或者两个BANK都选择:
1 M5 ]$ |  q( s8 Z4 o; g% T! K0 e2 C2 \% e/ j7 Q
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */
    8 W' P, B* F7 M) i6 y, l- Y
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */
    % D1 p% A' p0 \. @9 _
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码
  t# Q6 {, q! V; S- K7 V7 A
  Sector
# r4 i+ @& Y. c6 {& @' f8 A用于选择要擦除的扇区:! A( k( h  {6 e4 \" t% g% c
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */" {4 L2 F3 d9 _: r0 u
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */
    2 e* W3 w7 _/ _0 B
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */. t, T" F/ Z9 u8 p
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */: _) K# H% h. s) m% p. w* W
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */
    3 _, ~2 c4 A5 y$ K* ~9 ]
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */
    ! u( X2 `8 I5 s
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */. z/ E+ B' m% {0 v" N, `
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码

2 A. s( ]2 f4 ~  NbSectors+ }4 q5 e+ Y+ c2 X( n6 U: d$ c
用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。8 \5 v! I, E, p5 ~# X- H2 g0 Y
& X; E) v' N. O5 B6 [% _& H
  VoltageRange, V8 M1 `' Y0 ]" y3 o! X$ J
用于设置编程的并行位数,电压不同,位数不同:, T& R# g, p. t2 Y( o
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */6 f& r% A0 T, b/ U" C" q3 L
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */
    * Y  Q+ q. Y, X
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */6 B. k0 z# H9 H- z. K
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码
% C( |/ z4 b+ v* X

3 _' [3 ?0 T" ]+ D# I7 @2 s70.3.3 内部Flash的操作总结
7 t6 C2 {8 h7 c0 Z0 b- h4 N; z3 G+ F3 I5 B1 X7 i* g
9 e5 N5 W) o( X; F7 @
使用方法由HAL库提供:
/ T# k+ E( c- Q( C9 M  Flash编程函数操作流程) h  F( T- D4 J- M! j$ F. @( F
  Flash解锁函数HAL_FLASH_Unlock。
  a; C  @" C) Q7 S! }% k  Flash查询方式编程HAL_FLASH_Program。
! N0 e+ ^# a7 f" S. V; d  Flash中断方式编程HAL_FLASH_Program_IT。" O- [6 E0 o8 `5 O- J2 a3 I; k
  Flash上锁函数HAL_FLASH_Lock。
/ \+ o. J" C6 j0 y5 i! r, j6 W  
; Q! [: F3 m. a9 n  F选项字节编程流程: h! v" d2 j; z8 o
  选项字节解锁函数HAL_FLASH_OB_Unlock。& ?8 N0 \, K" R8 w( n) y" J+ \4 }/ t
  选项字节加载函数HAL_FLASH_OB_Launch。; l- p" n% R$ T) X, `! H" P
  选项字节编程函数HAL_FLASHEx_OBProgram。
7 i* k+ k# |% _" H( M8 G  选项字节加锁函数HAL_FLASH_OB_Lock。2 g" A. q* U% x5 u# B& c

" v2 K+ a. B! E( D" c Flash擦除流程# V% H  n7 z! a, `# s7 S% m# B
  Flash解锁函数HAL_FLASH_Unlock。
" Z5 P2 [1 {  g/ g# G+ f& y8 ]  Flash查询方式擦除HAL_FLASHEx_Erase。
5 ~$ {% A. {' `% I/ q8 z  Flash中断方式擦除HAL_FLASHEx_Erase_IT。
2 @- Y3 j9 {0 E# Q) z4 _' K  Flash上锁函数HAL_FLASH_Lock。2 u" i0 V  H6 n' U3 v
& r% S6 K# i0 W

! a) S4 I. V& O8 T- e70.4 内部Flash源文件stm32h7xx_hal_flash.c
% w) x/ Q! D2 H  ?3 `  J# o! i此文件涉及到的函数较多,这里把几个常用的函数做个说明:$ F1 `/ v" g% p7 s6 v8 \

9 o7 B# G2 ]! U" O% Y  HAL_FLASH_Unlock- e9 O0 q; I+ l  T: @
  HAL_FLASH_Lock8 i# G' j& v9 q3 Z9 l
  HAL_FLASHEx_Erase, k. C. O; e9 [: z- H: Y7 p6 e0 v* o8 |
  HAL_FLASH_Program
. k5 \6 z" y7 K; p( X$ Y5 y. {4 _2 N2 E( p' r3 K9 n
70.4.1 函数HAL_FLASH_Lock9 R. C9 t! P2 u" M, [( w6 @* `
函数原型:
/ [; Q0 _# ?* r0 J3 D  i
0 ]6 N# l. q5 x$ w
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)
    - G6 h5 V! Z/ x, ^' T- u( p
  2. {
    * V9 p: y( v7 r, h3 O; g+ C
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */2 H: o9 `) Z5 f5 U( P2 Q
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);$ w! w" g# }2 H" _$ Q6 F

  5. 9 T1 k9 {. T! t
  6. /* 验证Flash Bank1是否已经被锁住 */) I) p9 h5 t- S& B  g0 B
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)9 S# @% I/ w* g2 ?" C
  8.   {
    , |. o. V; Z8 a/ f( p
  9.     return HAL_ERROR;
    . [0 C7 D$ n8 n; ?
  10.   }
    # t: G& n  y1 l
  11. $ h, m' [2 q8 I% o
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    , M( Q8 V+ L! o; A: I
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    # E3 N! b- X9 m( u- G' I" R
  14. ) F! b! ^9 c: u, K. u$ W6 B5 c
  15. /* 验证Flash Bank2是否已经被锁住 */  ?  [. W) Z3 R7 P1 N
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)( T' e% J+ Q. F3 E
  17.   {- T( e) @9 d* k( b: {) D  ]5 |
  18.     return HAL_ERROR;( h0 l8 V7 }, m6 b
  19.   }. j* N5 n: v: a5 j' W9 G$ Q- B
  20. 7 Y! _4 n0 u9 W6 x7 v6 n# o
  21.   return HAL_OK;- l; Z) U  L" v8 r- ]* ]
  22. }
复制代码
4 N% I$ w" _! U" B1 \& s" L
函数描述:
( s; `- Q2 Y) n0 B! e& M8 l6 j
1 W3 P$ f) `+ A6 p6 I用于Flash加锁,加锁后将不能对Flash进行编程和擦除。
4 i  h- t6 i# b0 d
& O( ^' e3 I1 T, T6 ]70.4.2 函数HAL_FLASH_Unlock; h  _& a: X" h% [" y+ k
函数原型:
6 B3 \2 {4 r6 c' y
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)
    & @0 b" `9 t( ?: U- O# @
  2. {
    ) p% f# B5 C+ I9 u
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
    2 g" M+ R# Q& h
  4.   {
    2 s" f; T6 D, q$ @: e
  5.     /* 允许访问Flash Bank1 */2 @/ {5 u  r6 Q( n
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);
    * O- Y5 w4 u: G. l! t5 {- M
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);9 W% j' a" M* ^" B5 u3 D1 C
  8. 8 g0 }, _4 T& r/ @
  9.     /* 验证是否已经解锁 */% s$ h  K, Q  e, [
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)6 y0 |3 p) s3 u! t$ w5 J1 c
  11.     {/ u$ D0 h4 j" H+ W4 ]/ X$ n; ~
  12.       return HAL_ERROR;
    ( _" L0 L5 U3 j: p
  13.     }
    / Y' u# A8 V8 l- X' o
  14.   }
    # G* F/ R+ k1 v7 q: @% m

  15. , t! w9 d( |9 |1 v8 P5 ]4 h
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)9 ~. n: E  {5 L- I2 {% m2 _2 M" ?! c
  17.   {
    6 I  [% D% K& a$ [8 f2 O; d
  18.     /* 允许访问Flash Bank2 */5 b7 Q7 k+ H7 u: O/ N1 }" G- D" R# F. R; X
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);" b# N) g0 [* M1 _8 g4 [+ @
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);- S8 Q. y" V0 a5 n
  21. / Q' c  ^& J% C( X6 B
  22.     /* 验证是否已经解锁 */
    2 p: C4 s5 i) J( L  N/ ?0 y! Q0 Z
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)3 O: B; O' q# ?6 }0 V
  24.     {
    + F0 S1 ^* b9 g0 ^
  25.       return HAL_ERROR;
    6 ^+ N% F9 ^4 ~( [5 e
  26.     }! f8 a: y. O# y5 [6 i. K" V" I% b6 b1 z
  27.   }
    ; U7 S  u% O2 Z% t" S* v
  28. 1 t" x" y+ y) _8 ^% G
  29.   return HAL_OK;
    ! R% A! G6 x& c4 I# t, R
  30. }
复制代码

7 ]% X% j7 l, O' ?4 V: G4 \5 O函数描述:
0 P; x* h6 d6 {# Y3 K# P' }% C5 H0 {: D
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。2 S  t  m& r% N+ @9 ~3 w! T( J3 A
' v* r# j! U  ?0 Y* ~" W& ]
70.4.3 函数HAL_FLASH_Program
! |5 e, }8 H) k5 e; [! x函数原型:
# p1 v1 q# i7 j, f, ~; Y& m% e& ?6 C8 v, p- P. Z. w/ u' u% ^
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)6 W, S; O; `0 A, c* g2 p
  2. {/ b$ L' N8 ]. g4 s; W
  3.   HAL_StatusTypeDef status;
    * f' C) D, K( `; P
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;% K. Z: f- c& Z# J( ?2 |
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;* c; R- k9 G. c# V% A) ^8 t/ B$ r& q" e0 I& s
  6.   uint32_t bank;
    6 H! e9 s0 e* T) |! B* X8 w
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;: C  D4 I" A/ n

  8. " F7 a  C+ l" q/ S& o
  9.   /* 检测参数 */+ @' Y8 T1 c. D( `" W$ \
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));; M( y; R4 b2 Y( Q7 H( u
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));
    4 a0 |- ^! U* N$ J+ v) J

  12. ) R' a% z- _" G9 t) v4 o
  13.   /* 上锁 */
    + m7 R+ v  m5 [, J
  14.   __HAL_LOCK(&pFlash);
    4 c% o' [$ s! O; u3 V

  15. $ }) U) s' Z& J6 q8 g1 j
  16. #if defined (FLASH_OPTCR_PG_OTP)0 H! s, a8 y5 i- Z" @3 G
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))
    / v1 F3 H  N6 u9 |5 y* p
  18. #else) b% O; P9 d! T3 X- f# _0 w
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))0 T) F/ U6 j; P8 n, O* |1 F
  20. #endif * g% K: N; |' x
  21.   {! N+ d) g4 @3 d* @6 m; |, x
  22.     bank = FLASH_BANK_1;- \1 k0 g! j9 [' M" K
  23.   }& B9 v7 b- W. r, B1 G9 z1 A
  24.   else
    $ U, A5 p0 {9 [! d5 p3 R  G* b
  25.   {
    0 m9 R+ V4 C! F; T( n1 y
  26.     bank = FLASH_BANK_2;
    7 d# J% |; ]8 P$ \
  27.   }& b# @9 e  w: A$ }; |+ P8 C

  28. - q& N9 o/ X) K" ?5 ]9 A
  29.   /* 错误标识,无错误 */$ i7 |0 V* @/ W% Y
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;- s8 r1 s$ J# V, b9 w3 w

  31. 2 _  h; ~4 y, p; P, d* u7 {
  32.   /* 等待操作完成 */
    1 r0 I  C/ Z# z+ f" d/ v; Z
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    : V+ `2 }! w5 n6 _
  34. * R0 I5 x: A* a
  35.   if(status == HAL_OK)& h+ Z/ l' z0 q, i4 K  v
  36.   {
      _$ N/ C' e  p3 N
  37.     if(bank == FLASH_BANK_1)
    ( {% ~. D. g& w1 G' Z* N: p
  38.     {
    4 ]2 }" }& L+ v6 r/ x% @
  39. #if defined (FLASH_OPTCR_PG_OTP): V2 c) L5 X* g1 p) b
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    ; ~& v8 K2 \1 @  U! U
  41.       {
    9 y- |% C2 L; y# Z$ ^
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */
    / J/ @4 Z0 [/ }4 V- r7 j/ V
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    $ {# ^; S; J( [" ], \7 i
  44.       }. n/ c! w, X& M1 c% \) _
  45.       else+ B) s5 L4 u7 Y2 \3 }
  46. #endif   n/ B7 S: O, f# y/ [5 T/ @
  47.       {
    ; T1 Q4 L# Z# H& P7 }( V3 c. R
  48.         /* 设置PG位,使能可编程 */
    % ~" Z" c1 V% i3 {' e3 H
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);3 Z. R, v) s9 r* @  a1 f
  50.       }
    . Y$ p0 I' j/ B8 }/ F" U8 M
  51.     }. _# j  {% S, h2 h% Y$ J/ H* G
  52.     else
    # `! [) I7 S4 i: q2 `+ Q8 |
  53.     {
    ! h" S6 M; w/ o
  54.       /* 设置PG位 */
    . z' L. ^! z" j( x9 N5 ?
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);/ K+ r& w2 A6 }: g
  56.     }
    $ n2 \, |, O$ q  I* M2 T/ Z1 M! d. o

  57. 4 h) ^$ A) s9 s5 n
  58.     __ISB();% }; B0 r: G1 ~$ o, k1 H- _
  59.     __DSB();
    * C# @% I' t+ c# H; K$ |% [/ ?) m2 ~9 }

  60. / J, ?8 f6 d$ H2 x' [: F
  61. #if defined (FLASH_OPTCR_PG_OTP): X$ K$ Q2 e% v, T
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    8 |2 {; o5 l7 F. R% O! {
  63.     {
    5 ?' b8 D1 D) ~# B
  64.       /* 编程OTP(16 bits) */6 I- N* h. \3 g6 n5 S* k2 w
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;
    # h1 h' }9 [+ P" g% w% D9 _
  66.     }: K# c; o; a+ M! d7 Q
  67.     else( v) j1 E, {3 u2 \" N
  68. #endif * ?% F( E7 }& m* R# @8 }6 V8 t
  69.     {
    $ m$ W5 I) j4 a# \
  70.       /* 对Flash进行编程 */+ q) |* S& T' q* Z
  71.       do; u; {8 ^& o! I& i) A% H
  72.       {- {) c. z. r) D. h% K0 y" X5 Q
  73.         *dest_addr = *src_addr;! v. K! U% V& B9 c0 D! t
  74.         dest_addr++;
    ) R% w+ s$ h3 F3 H! |7 V( l
  75.         src_addr++;
    9 N4 n: P% S# e; G1 }& `4 b
  76.         row_index--;! h3 Y6 y' E! S
  77.      } while (row_index != 0U);
    7 d% K5 R3 l! D; x3 i/ [: K
  78.     }% L- X- [1 {6 D7 R8 e2 m. }' S

  79. % ~0 P' Y! k/ I" n6 v8 U" ~
  80.     __ISB();) J3 M; g9 S) i0 N2 B$ }& X
  81.     __DSB();% o/ l3 u4 x2 n7 ^, [% [
  82. * `; ^* J* h2 ?
  83.     /* 等待最后一次操作完成 */
    7 b6 Z" u& j7 H3 f2 V/ }4 k5 D
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    0 m+ I! n3 r  g7 e9 f
  85. * k  y2 Z! X! m: g, u! b) ?
  86. #if defined (FLASH_OPTCR_PG_OTP), s3 |* d* T2 h) U1 |
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)- m: }, n3 ?5 @- \. l
  88.     {$ F( w3 Z4 B. Z
  89.       /* 如果编程操作完成,关闭OTP PG位 */
    6 R4 \! w) K* t% x6 d) R$ X6 i
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    ; C: h" N$ z/ |
  91.     }, D; q1 T# W- s, n3 l4 E
  92.     else
    " [  S( d2 c& |! K" ^9 R, }! U! F
  93. #endif
    : ]' I9 W" T; O
  94.     {- N7 i: D: R( J, L. F7 y: ^
  95.       if(bank == FLASH_BANK_1)7 ]- o: Y7 z0 M" S$ y) x% I; c
  96.       {$ ?# c- ?, H  ~  b! N, }
  97.         /* 如果操作完成,关闭PG位 */; H. K: x: [  k4 m* f
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);
    8 r' l' z. f9 j8 T: a- M1 B
  99.       }1 A% T  }) ^0 ]. h1 Q
  100.       else
    / J' N+ m* ~; M2 W. {$ K) T( r/ o
  101.       {
    . B# D$ B/ Q0 J: \, p2 R' b
  102.         /* 如果操作完成,关闭PG位 */5 s- b- Z; \8 u9 i# y
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);2 ~; [7 [5 a& l5 r; ~) T
  104.       }
    - ^3 M, R* h/ h4 K* h% C6 o8 s
  105.     }
    . ~9 u4 p+ \) E+ i2 ~4 X
  106.   }) i+ T2 \* x  n* u5 ?0 l7 w4 j
  107. - ?- v- P) _; w0 @/ B
  108.   /* 解锁 */
    ' `/ p: M3 e9 j8 ~3 F
  109.   __HAL_UNLOCK(&pFlash);2 U) T. O4 o$ A0 S; _3 H) J
  110.   y8 a% x3 H( n! d
  111.   return status;
    2 ~3 T4 P& a, h4 U1 }
  112. }2 k2 V* ~& S' O9 {- [7 C
  113. . }+ F+ R+ L8 |/ Q! r3 K
复制代码

! _3 w! S' U2 G; }5 b, I- B! v函数描述:
. K/ Q6 ]7 c: ~此函数主要用于Flash编程,固定编程32个字节数据。* K9 R2 B- q- c1 U

8 x, a1 l4 o  v2 w% W, D" M函数参数:+ P$ K0 ?+ L: B( ~6 O4 i  q( [
第1个参数是要编程的Flash类型,支持两种参数:+ C$ [- \. O+ R+ e7 ]! r, N* ~
  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。5 C/ o1 @0 \" j
  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。% l, D0 B6 u# E: x2 A% F8 C9 @& J% n

" @  L6 u0 D- w# C第2个参数是要编程的Flash地址。3 h+ T9 x6 X" @5 I

9 j' ]8 T0 E$ ^5 P& x3 Z第3个参数是要编程到Flash的数据地址。 1 v4 a: P/ u* j4 l
返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
0 H9 y/ `* E  _; z! v( U! t/ m' C, G

+ E1 l+ f3 W3 [, r7 d" A8 V: B注意事项:  b- E0 ?4 i& |- i
  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
" l. v" L# a1 K0 u# b  第3个参数务必要是32字节的整数倍。2 G- ^4 p6 I- k2 L

- R8 Z- B# F  r( B% G70.4.4 函数HAL_FLASHEx_Erase& l3 ~& C. O, {) V
函数原型:
( T/ Y+ d* B2 h  Z$ D1 v4 N8 y- ]( c& g' `2 Q) E0 }& {: b4 j
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)) O7 z/ |) i) M0 l8 B& _
  2. {* M9 i: \2 I# ^6 c/ F6 G9 _! A
  3.   HAL_StatusTypeDef status = HAL_OK;
    ; }& s& J' c0 N/ ]
  4.   uint32_t sector_index;
    ( m$ X" U2 S7 v& _+ ?
  5. 1 Z8 s  B! R( `( ?9 _
  6. /* 检查参数 */
    9 w. I+ g0 L2 P4 T
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));0 Y! }4 e2 j! S3 z& W( a, j
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));4 a: D( x- j1 r7 w) ]

  9. & x  Z' ?: r% n0 p* k* a2 w& ~9 N
  10. /* 上锁 */
    5 r, F& I3 R: y. u( v& A2 o
  11.   __HAL_LOCK(&pFlash);8 [5 `! \, c! x+ f

  12.   M% ^( ?! X' j1 g* a9 @
  13. /* 无错误 */4 y' x" v) f  L$ a+ u
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;9 R3 u" O  I  x/ l+ W' L

  15. ' k  A; F% k# O8 R
  16. /* 等待BANK1的操作完成 */' M' R5 E. [, ^
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    4 e( d$ P5 K' i, t- X# L" d  {
  18.   {7 R3 U7 I( C& W" I$ W. W
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    1 T5 t- w! c, W1 E
  20.     {% y7 v: `3 ^: }9 g2 V' i
  21.       status = HAL_ERROR;: b" l# S5 p" _; J3 O9 z; w! a
  22.     }( ]$ H, @) \! s( @# r
  23.   }
    3 |- d: |# u! u6 v( S

  24. 7 {9 ]) @3 C8 S0 [7 |
  25. /* 等待BANK2的操作完成 */
    $ x' _5 ]$ Q$ p7 o" t
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    8 E$ z, o. \/ [( |
  27.   {
    8 j& m' l( M- i- m" j  U
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)$ p  x& k$ f) {& ]% g. f7 C* D
  29.     {1 k0 \- L9 a7 L3 c
  30.       status = HAL_ERROR;
    & q0 m5 I8 ^# E  @( ^2 O" w
  31.     }
    5 Z0 V+ X- g2 P( [
  32.   }! W. o5 ~  }# v7 F
  33. % E3 x# n0 x% t; ~, e. @4 I; k
  34.   if(status == HAL_OK)+ Z4 W. z2 `0 r7 @3 g% \5 G0 ~
  35.   {
    & ?. Y& {& a! O( N
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
    % e: r. S( u( f0 U. s( J
  37.     {
    - j- b5 {/ S1 F- k. Q# Q5 i
  38.   /* 整个BANK1或者BANK2擦除 */
    ; a' @' d/ n' u5 _* k* B/ O  |
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);7 i+ L6 r) K4 B1 A# V6 k; h  v
  40. 6 C" p* J" w2 ~/ @* _
  41.   /* 等待操作完成 */$ C4 H8 D( \8 K, i2 ?/ `3 N7 @
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    : v9 S  x* M: i4 m$ O2 i
  43.       {
    ) F* m% W, _4 T0 t( j1 c
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    * r: k) F/ C" J% ^
  45.         {
    , Z, v" v- l5 N7 n1 Q) \
  46.           status = HAL_ERROR;
    . H' A2 ^; V% x& ~( a4 b) v
  47.         }  P' g0 H4 @: s* m2 C+ A7 j
  48.     /* 如果擦除完成,关闭BANK1的BER位 */
    : ]& I7 u: M* @" |" i( c- T( Z
  49.         FLASH->CR1 &= (~FLASH_CR_BER);
    " x5 d% l5 F2 o) _
  50.       }
    0 v8 `4 L5 {0 r
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    + J0 @3 v, h$ F5 {* m
  52.       {! H" d9 @1 P& U  y
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)$ r# ]- R1 u# z
  54.         {
    # c2 x0 q' o7 Z% Y. K/ O
  55.           status = HAL_ERROR;
    9 U2 d, Z. @# B8 Z/ C" p
  56.         }
    ! g( u' i; N- j. N# b( s; ^
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */
    " e( j' p6 [9 W4 a
  58.         FLASH->CR2 &= (~FLASH_CR_BER);
    8 T! c' L' c( i/ R4 w! j6 k
  59.       }- O  ^3 }$ `+ z9 p8 e  m6 q
  60.     }2 f8 u% m+ F  e
  61.     else
    0 w7 _5 W+ m2 W- I' x' b! Y
  62.     {
    1 n& T9 }; S7 H  s4 S
  63.   /* 初始化扇区错误码 */
    " G& J8 b8 f' m, z
  64.       *SectorError = 0xFFFFFFFFU;
    + W; C& d. N( g: Z6 X
  65. . }  U+ [' s/ E. m( N% P5 q: R
  66.   /* 扇区方式擦除 */
    . a3 `& h. E* C7 M! }
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);
    9 ^- ~* }$ v1 S. K# H; x3 F
  68. sector_index++)
    + Y/ Q" I: T5 {& z' b
  69.       {
    # T2 B& J3 w: J& e& X
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
    $ B' j- O: v2 ?  [( `% z

  71. * D. y1 T5 `4 w$ C+ \& d6 W3 D
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)' b+ j$ n4 F, n( c0 X! F( u
  73.         {" Y9 O5 z2 g) g2 J  Q& r, f
  74.       /* 等待BANK1操作完成 */
    3 o# W5 t* M5 Y4 A
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);; u( }) h9 Q) d# d& l) t

  76. # n2 q/ N9 M! E) n& _9 U$ B
  77.       /* 如果擦除操作完成,禁止SER位 */, y2 [, u+ k/ z8 f  |
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));  k* Q, N; U' H
  79.         }! V# z5 d: u% p' x
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)4 y5 H. ~, f1 t( v& k0 C0 F$ j2 Q
  81.         {2 l: z# E# O- A/ C2 T
  82.       /* 等待BANK2操作完成 */
    % r4 Y# r4 ]6 n* r& G: r
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);
    , N! A6 N' C. n0 B5 N
  84. + ]# ?7 `1 _& p* K
  85.       /* 如果擦除操作完成,禁止SER位 */
    2 e3 L0 c6 q, a/ P+ w$ \
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    - m8 }0 ?- X3 F5 x4 @5 ]
  87.         }2 z. d9 L7 H( R0 I" `
  88. ( D2 I" J( Z1 J5 x% O
  89.         if(status != HAL_OK)' K! _9 Z0 g0 @9 d$ @
  90.         {. ^$ [9 I# ?8 D; `
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */7 [3 n3 h& x2 M: o- F. R5 Q7 @1 k
  92.           *SectorError = sector_index;; N' K& F9 o3 |  e, a( q
  93.           break;
    & m5 U; k: x0 T# _( E
  94.         }) d0 b9 Y1 n8 {7 n) K, d. `
  95.       }2 D7 j: b; V* h; z5 L2 ]
  96.     }
    / Y; W- s" T% C( s! U" g' h
  97.   }* K2 R& \# {  ~5 ^0 ^( K

  98. 0 }( Q) R. \$ `9 N4 H3 T( P
  99. /* 解锁 */
    ; h/ v1 N% Z: Y1 X  ?3 w. D
  100.   __HAL_UNLOCK(&pFlash);
    7 n7 F% |1 E$ x2 m* U# h
  101. 4 ~; w- u0 M( g1 z- n
  102.   return status;- h+ p; q8 M" |
  103. }# _. S6 ]9 }' H$ ?) m4 T: m
复制代码
4 b# [/ b+ e) `
函数描述:/ U, F7 N) p2 B) \, i* W
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。
- _5 C4 J9 W! v: X, i% ~1 o2 w) B. V4 a- C: K
( Y+ {( p5 E8 ?, l% Q. ?% T函数参数:5 x2 C4 ^! Z' N" F
  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。
+ O2 a+ L  q" T. e  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。
5 |- X9 [! I/ x* e4 ~  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。7 f- y/ F4 s: \7 e
6 m1 b8 t. N) N$ }4 l
70.5 总结
3 F' X( k! A* t9 \# e本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。
8 J0 j- q3 W; d4 D8 r, Q
0 e7 w! {0 _4 p0 z& A7 @4 A( p$ l" z4 t+ K3 _; F" r
2 h6 K% h: ]% t
收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版