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

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

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
& L  B- t" Z7 F/ }( m  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。2 h. E* H" c( W1 v9 m
  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。
& Z0 r2 @6 z0 D( X! Y  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。6 E; _; ?5 J  \' n9 l
  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。7 f; k( L7 i  J8 T9 Q6 t( O
70.2 内部Flash基础知识. m" `! R1 w, Y! z: K
70.2.1 内部Flash的硬件框图
% s8 x% i  @' o+ K8 t; e
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。  r9 ?% f; ~: R8 c# \5 X
4 N$ ?! L/ K+ V8 b
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
; \/ D) l7 Q" H; d. _2 V
% m+ M( P$ z/ J+ }$ M. ^
通过这个框图,我们可以得到如下信息:
$ R6 A% U. E0 H# }4 |% C2 s, @+ w8 g7 ~7 g) ^; K
  sys_ck时钟输入
8 h) E9 o/ F, S& RD1域总线时钟。- y( H- S5 |) E& Z5 y: o. ~

5 Z3 `# u/ d# B9 j1 i5 T  po_rst输入7 q' V5 k6 ^5 Y5 s: n
Power on reset 上电复位。
2 p# [5 v) W. [# R( \& z) u; s: C6 ~' Z- q# Z6 z4 p3 ~( `  v0 T
  d1_rst输入
( m- X  u4 ?2 s. T& N) K% V' H8 e) _. YD1域系统复位。
6 J% Y! F( k6 t4 g& I# j, y4 M% b/ v- C' F. K
  flash_it输出" `* X! z0 |) ^9 o* i
flash中断请求输出。/ ]- ^$ I/ m+ a8 U- B$ L

, m5 ~, p* ^8 _0 J' L, MSTM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
- [* U. I0 f9 k, K2 E$ Z/ f6 t. i# u* x: x/ N* R  E
70.2.2 内部Flash框架
  K' P. X- w2 N# L, A关于内部Flash的框架,了解以下几个知识点即可:
9 E( d6 v/ w: P0 x) [) z, Q) Z2 M+ a' d! {- M2 x! M, Q
  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
+ X7 M7 K8 z: {3 `* D$ R  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
1 a6 h) }% h: u# `
7 {8 T8 Y1 b% R; U' r
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

$ I  N9 u- t2 V$ g4 F' Z& [5 Q! {9 K: b& R. `1 v2 S* {" H8 S- R& {3 S
BANK1的地址范围:0x0800 0000到0x080F FFFF。
% ~  J* W. n+ K' x' S3 l- `
) q+ V% d6 L- g6 K8 A' g1 V; ABANK2的地址范围:0x0810 0000到0x081F FFFF。1 p8 l# k! X# k' C, J8 p: V
; a+ }1 q3 ~6 k" d
70.2.3 内部Flash读操作
4 W: V7 F; @' I* V$ l" MSTM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:
* [! K+ _5 g: i& {) x7 ], w9 h7 {% N+ j( d8 O3 b/ P4 f
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

' Z" p+ ?( I6 k' y$ x; g
: v8 e( z6 n2 c' T: b对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
* Q* a; A4 ^7 R
& Z- f8 y: _6 M' A5 K& p. x- @) e了解了这个知识点后,再来看下面的时序,非常具有参考意义:
- p9 F+ L, {. [
3 `2 z' J  T- {' x; {" Z: A1 P注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。" M5 U$ z3 Y/ ?9 U3 \

/ r9 G* g5 _$ E' k
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
* D8 f" H/ t9 u& I( N$ l, t
, `- l  @, H. O' b. u
关于这个时序要要认识到以下几点:0 U8 J" o. L+ H; k5 S; i/ {' k
& |* j2 Z2 W0 x3 W* b" l
  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
6 a  o) q. b( ^8 L4 L5 W4 p  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
* ?* P7 r! b: m7 c* T5 L  如果不开Flash Cache的情况下,连续读可以提升性能。
) [) C$ y' q3 d6 ~/ i, c" u+ p( B& d4 L  x
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
) r$ Z& u/ U; }, C5 o
: G- R9 V; ^; a! D8 e5 s+ {5 V
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

& M& l+ l  o$ A8 |% h: H% j# ?$ k! l2 Q/ S% C3 z- o1 A
70.2.4 内部Flash写入和擦除操作1 v: j; n1 T1 {4 X8 c1 g6 [& _
最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。) Q( h- B9 }5 R4 Q
2 a  j$ U, X7 e7 {+ l1 q
这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:
) Z: q$ [8 E" F5 K; @- |, d" T& ~+ B
先保证这块扇区空间之前已经擦除过了。
% k  `9 n% x2 Q6 o6 p5 L& Z$ l* ]解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
! d7 [: w- t) y+ t; B检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。' n1 Q  {* n2 u3 T7 w" J
' T& f, p# P* G4 Q6 f/ U. _! q  W
Flash的擦除流程如下:% U1 s6 D' p" r7 g/ J7 ?  C5 k
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。. M4 J& g/ t" i
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2# i- T- J; o2 `: a* q5 i
如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。
- W* t& Z' J4 z! K/ |6 O* M7 n
9 f$ \" i* i) {, ?% N- [* D6 z+ W
70.2.5 内部Flash读保护
) v) P( Y$ Q3 u$ M4 Z# D6 o内部Flash支持三级读保护RDP(read out protection)。
7 S) K! T1 g* v  `+ e. q" @: b/ G  n9 N; V9 T( E( J' C* D& x
  Level 0(无保护)
+ D, C& `: M  G& ]& N7 H% P9 z默认设置,所有读写和擦除操作都可以正常支持。7 [9 z- B! }0 L5 S
! f; L& P2 j2 C" O8 f
  Level 1 (Flash连接保护)
  O# C1 a8 Y  H' x+ w" R0 ]  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
8 P) ?. o8 p: d$ V1 ?5 u8 K  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。; r/ ]9 p. s9 e# J) Z, T$ `8 o
  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。/ W* q/ K6 Y6 }* {
7 a/ `( z1 q3 g
Level 2(设备保护和自举保护)
+ M4 ?( s/ D* T/ Z2 d4 N) m4 O  所有调试特性被关闭。
0 b& G4 O& i; P% w  D% y! F1 Y! B( G5 e  禁止从RAM启动。. V/ C" ~9 L5 V
  除了选项字节里面的SWAP位可以配置,其它位都无法更改。0 ~! r3 E1 `' w* T9 @
  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
( j9 q' _2 T) h! a6 U
5 ^) b2 f% N2 W9 B  A特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。, B  M* c% |( |
: C% E3 N: C( d1 @
如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:
6 H8 d" g- h0 b/ U+ t: A5 u! x4 }. X  F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
3 G# |1 ?$ W, b$ F9 E

) K# H' T7 @4 Z0 d% R6 Y0 I# z) G  I" n* w- J& s$ G/ ~& f# h
70.2.6 内部Flash选项字节
. i* G* ], C3 e* L& w! n1 lFlash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。
/ J8 i0 M" E( p1 O+ c
7 s% P4 J( s% V: k: I
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

1 C" U1 V5 }0 g6 B3 \) ^: q; ?! }3 l& z6 O  Y* N4 \
70.2.7 内部Flash的ECC校验
! J; U3 U; e) z' i5 O& e8 ]这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。4 _4 Q9 l5 f1 y

3 M: ~0 D3 H* a. w" p对于STM32H7带的ECC校验,一般不需要用户去管理。9 o7 j5 i' D; L- Y; g! k7 j8 [

$ \  r/ w7 o0 ~6 H70.3 内部Flash的HAL库用法
; e2 `/ W4 K( a( Q: [6 }70.3.1 内部Flash结构体FLASH_TypeDef
6 L7 N9 x2 ^5 ]/ ~+ I. U内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
" ]# m2 B+ ?8 ]& K
1 k4 m& [! i! V, X* c
  1. typedef struct
    " Z2 O2 N8 N; O
  2. {3 n& I1 B* N' C
  3.   __IO uint32_t ACR;            . Q! q& e* H+ u7 s% i0 M5 _
  4.   __IO uint32_t KEYR1;           - q& Y8 @, K4 ]: r1 @7 Q& H1 F6 c( d
  5.   __IO uint32_t OPTKEYR;         
    1 |6 e# Y* I# a1 T( i* V
  6.   __IO uint32_t CR1;            6 p" t0 v& Y; i8 F
  7.   __IO uint32_t SR1;            
    * F: C# B+ L8 v& Q/ T% ?
  8.   __IO uint32_t CCR1;         
    6 Z, P* d) N( M* k
  9.   __IO uint32_t OPTCR;           
    1 l. _! f* B4 w2 ]7 t- k* r$ B3 s
  10.   __IO uint32_t OPTSR_CUR;      
    : M! c' S% H' j( H1 p
  11.   __IO uint32_t OPTSR_PRG;      4 s$ y2 W; B0 K/ G- n( Z
  12.   __IO uint32_t OPTCCR;         
      @- X9 Y. ]+ m& q7 p" E, z2 _
  13.   __IO uint32_t PRAR_CUR1;       8 j# [8 o- s1 y  V2 v; T2 s7 G* E  ]
  14.   __IO uint32_t PRAR_PRG1;       ' F) d" ~; {( K
  15.   __IO uint32_t SCAR_CUR1;       - `# A2 N# @2 J: U/ Z1 y0 t& {3 E8 g! v
  16.   __IO uint32_t SCAR_PRG1;       " u# V- @. S8 ^  b4 @
  17.   __IO uint32_t WPSN_CUR1;       - n) [$ R. h& z, \( q
  18.   __IO uint32_t WPSN_PRG1;       & V6 e1 e1 H- J, ~' E5 }; Y6 F+ }
  19.   __IO uint32_t BOOT_CUR;      
    , }1 N5 }( O! m+ z! _
  20.   __IO uint32_t BOOT_PRG;       2 y) e7 Y+ v; x& D5 X" c' {
  21.   uint32_t      RESERVED0[2];    - X* x8 @6 x( `0 |( L9 r8 b
  22.   __IO uint32_t CRCCR1;         
    3 N1 \8 H( x% |; U  f
  23.   __IO uint32_t CRCSADD1;      
    , c, ]7 {& r+ {" z
  24.   __IO uint32_t CRCEADD1;        
    8 C$ T1 q$ i4 n3 ]; ~: u7 d
  25.   __IO uint32_t CRCDATA;         1 {( ?. A7 N9 L# V  V
  26.   __IO uint32_t ECC_FA1;         3 x. X  l: C* R3 t) P
  27.   uint32_t      RESERVED1[40];  
    & ~8 n# {. g0 s; r7 W
  28.   __IO uint32_t KEYR2;           6 j/ k1 F4 `. I, a3 ^7 P" k# D
  29.   uint32_t      RESERVED2;      2 ^5 b7 V( c; I+ b/ U
  30.   __IO uint32_t CR2;             1 ~  t4 i, T# g  h
  31.   __IO uint32_t SR2;            
    / e( |, r; q5 t. y
  32.   __IO uint32_t CCR2;            , }8 c& b0 K# k$ a$ t% r5 Z! }
  33.   uint32_t      RESERVED3[4];   
    . e/ N) F2 `& A" c& j
  34.   __IO uint32_t PRAR_CUR2;      
    , t  R& }5 ~4 r3 j, @; e
  35.   __IO uint32_t PRAR_PRG2;       1 H; o, Z$ ~* p( O+ K% v
  36.   __IO uint32_t SCAR_CUR2;      
    3 X" m/ B3 d) O; o  q( p; v
  37.   __IO uint32_t SCAR_PRG2;      
    " _1 ]8 f  P( L' D# g- l: J
  38.   __IO uint32_t WPSN_CUR2;       7 b; \2 H( i! o2 ^+ [# B1 E
  39.   __IO uint32_t WPSN_PRG2;      
    " h: @( J! P& n
  40.   uint32_t      RESERVED4[4];   
    $ l! `9 n3 x6 a) a+ c  {& C$ a
  41.   __IO uint32_t CRCCR2;         
    4 K" L6 T0 P2 C, f( r1 M, R
  42.   __IO uint32_t CRCSADD2;        
    0 V7 I* j3 o' L1 b6 }
  43.   __IO uint32_t CRCEADD2;        
    1 r. h3 h/ ~4 j
  44.   __IO uint32_t CRCDATA2;        6 }& P0 _7 I8 s1 ]! [- \* q
  45.   __IO uint32_t ECC_FA2;         
    - ^/ b6 D) y- ]4 P
  46. } FLASH_TypeDef;
复制代码

9 q7 O3 p  V) c0 X, E3 X这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。8 e! R7 [  Y, h) |$ d
; z% a6 _- b# q* J: }
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
5 C( |& t, R. U! X  |
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    , J+ i& j( k# X' n( E* U5 p6 [) i
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
  r, E# T- b3 [2 k6 m: y  g1 F. W
下面我们看下Flash的定义,在stm32h743xx.h文件。
: i) N8 q  `6 }5 G; K. d/ b
' x0 M6 x8 H1 m4 J$ [
  1. #define PERIPH_BASE              (0x40000000UL)
    & r* U$ K  E8 X; d
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL)! c- ]# h5 u$ j* ]+ q
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)) R' M; Y1 T( H9 w2 ?) S
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码

- n% P/ X0 M* b我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。2 c: L* a' T1 w5 L6 n) \) W
8 h5 A$ _! N3 R; n
70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
3 P& t( z, s1 t5 D, l& Y% O  A下面是做内部Flash擦除的结构体,用到的地方比较多:
7 ~8 I9 o3 j" W& C) q" d, X5 f% T  s. ~+ s
  1. typedef struct6 b3 |  f' C6 ?# Z
  2. {& I  @# D8 q5 ?/ _/ ?6 U
  3.   uint32_t TypeErase;  
    : h& s( f4 d# ?
  4.   uint32_t Banks;      
      Z3 ]( [/ p# W/ ^" f
  5.   uint32_t Sector;      ' W# X! K* W+ C* T# @% B
  6.   uint32_t NbSectors;   / Q* j- B, ], D9 l% `+ m
  7.   uint32_t VoltageRange;
    % A/ `! m, C. k
  8. } FLASH_EraseInitTypeDef;
复制代码
! B4 h5 Q- f8 U( q4 B) q
下面将结构体成员逐一做个说明:
3 ?4 N: ?: A* k6 i1 c# P  TypeErase+ G8 Y9 x0 S: V0 h: g  K- s7 ^

$ U5 G" P( U+ e1 z4 a
+ }5 B: g* n6 I- @0 I- M7 x用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:% \7 o& H( @0 b
- ^- s% J; c1 y5 T# y5 Q/ r+ ?
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */
    4 ]7 ?% ?0 n7 H; B3 Y
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码

" }. ]( q; S0 m  Banks
" T5 J' L* P4 n1 d4 k用于选择要擦除的BANK,或者两个BANK都选择:
- g/ R& _! d6 q
; n2 j9 s0 s; I5 Q- `
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */
    3 k$ h% a5 F% R! t
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */
    ! F: z) X4 n" U( B& Z/ `( f. _0 s0 k
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码
$ \8 X3 F: ]5 k' W/ g
  Sector3 a2 s* @1 h% {4 A
用于选择要擦除的扇区:# T' P/ K/ j/ w) q1 K' q  {5 O  ]6 x
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */& R4 |1 u, \! _) r
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */7 K4 Z8 A) w5 ^2 Y/ L( T: E
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */+ W1 b  [8 m) z3 T9 E- t6 u4 A+ F
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */: ^/ |0 Z; S2 L1 F2 y/ a
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */7 U5 Y1 r' f- y+ q
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */
    " E5 e; a: S& v9 I7 Y, e. w3 A6 D
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    " E5 y5 I. H! M8 }, e
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码
8 X, Y( M! R3 M7 _. F8 J
  NbSectors
1 c( i  v4 o+ }" V+ }  \" x* ~用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。
: ?$ a) [; ~3 ^* u/ U$ s/ a
7 k4 }& ?' P5 d  VoltageRange) D! P7 v, S+ H0 T5 E2 r% o
用于设置编程的并行位数,电压不同,位数不同:
5 \; |. J( D. F
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */6 G; J6 \# U8 X& C7 `
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */
    * c  E" n' M6 N1 A8 _6 b
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */
    5 F7 ]- x8 |3 T6 S% V' W; e
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码
7 s+ l4 o" V7 d; `! j
; {9 X, x* b! r4 U7 M! j' H
70.3.3 内部Flash的操作总结$ s3 |% R0 g' T- ]

2 N1 Z1 V+ {  a& b# ^) c: X, _# F6 w( C0 f8 l% h" m' D
使用方法由HAL库提供:- f" L* `4 H2 j
  Flash编程函数操作流程+ `* B5 D$ Z7 V/ y1 B- D0 Z
  Flash解锁函数HAL_FLASH_Unlock。
2 k( z$ X$ y7 p% n8 [7 o/ _  q  Flash查询方式编程HAL_FLASH_Program。) g  U5 h" Z& a) s
  Flash中断方式编程HAL_FLASH_Program_IT。
% \1 |' B0 J1 v/ Z& W3 [6 _  Flash上锁函数HAL_FLASH_Lock。
3 r, A" I3 v) F  ! D6 i) @) a0 M3 |5 W# o5 }4 V
选项字节编程流程
  |! K1 P, m) u  选项字节解锁函数HAL_FLASH_OB_Unlock。
6 H+ j; ]+ C6 t  选项字节加载函数HAL_FLASH_OB_Launch。
3 Y1 l. E( E& s( a  选项字节编程函数HAL_FLASHEx_OBProgram。( s* \6 I* C& y7 G5 m  |7 Y4 f
  选项字节加锁函数HAL_FLASH_OB_Lock。
8 E' l+ }- j& i% c1 q
8 T% Y' ~6 B! g% H$ P Flash擦除流程
6 O& V/ s: C) W  Flash解锁函数HAL_FLASH_Unlock。) ?& U4 T- w( x* E" z& I
  Flash查询方式擦除HAL_FLASHEx_Erase。
& y5 t7 @3 Y- X% E9 l. R  Flash中断方式擦除HAL_FLASHEx_Erase_IT。
1 e+ g& ]1 ^" y  Flash上锁函数HAL_FLASH_Lock。
  q+ n7 z4 M* I! n6 N+ \1 Q/ S+ Y3 N! w- q8 Q9 f/ D
9 v5 y+ N% G' X1 `6 Z
70.4 内部Flash源文件stm32h7xx_hal_flash.c
3 ~, i8 p6 H  t' p6 t, R: M此文件涉及到的函数较多,这里把几个常用的函数做个说明:
9 O* t" ?" q9 ]' G0 u9 J! z7 O
' F5 {3 ~4 Q/ u: s2 v" Z  HAL_FLASH_Unlock
, ]1 V8 s) F4 s3 s1 \  r/ X  HAL_FLASH_Lock- U. Z& e! {& H- H  M5 \
  HAL_FLASHEx_Erase
, T9 a* m& i, U+ d9 }5 _  HAL_FLASH_Program. X$ c" `* {7 p7 Q( j( @3 _. L
$ N7 r& f# M8 N: P& o
70.4.1 函数HAL_FLASH_Lock7 q5 h" `/ o8 O8 R, G7 r
函数原型:
7 p$ U" |4 J+ Y1 t8 i8 b+ Q3 f- r0 t7 `; ]1 s
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)
    1 A" a: ?1 Q# `6 [( g8 H) h, r
  2. {
    - I- D4 I  G0 P! Q" q* f. [& L
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */2 s9 T0 b' g0 J0 m' h" U% V
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);
    + F' O% J/ O4 Z% ]7 V: {" g/ n8 H
  5. # x( t6 C' g# X" D$ d+ ~. M" E
  6. /* 验证Flash Bank1是否已经被锁住 */$ t+ w: k. V# L" G
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)/ x8 h# a) j% U7 ]( A+ j
  8.   {
    . Z* K) M4 l% j
  9.     return HAL_ERROR;4 l1 d, S; X- E' D' H9 b3 n! S# ~
  10.   }
    0 w$ n' }4 \; ~
  11. 2 H& i7 V& y2 M+ l' p
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    : D" l. O( O% f. R5 a* h( ^
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    9 f3 W1 E! f, b% u
  14. 5 b8 f* J% a' n+ @6 }$ r9 `
  15. /* 验证Flash Bank2是否已经被锁住 *// m8 f& K, e2 s  Z, D5 ~
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)
    ; E; f* j+ u  t$ w* Y
  17.   {
    ' Z. A) {+ w+ @% r4 h  p
  18.     return HAL_ERROR;( B7 f3 y3 u* y, R0 |( e
  19.   }
    ) L. U/ T- D3 X* m6 \
  20. 8 L, Y3 F5 x! Q$ S  a
  21.   return HAL_OK;
    3 A( N: l- \& z& {
  22. }
复制代码
2 I" }, L- L+ i0 E& G+ b
函数描述:; f; }# s9 C* z1 L) s. F
9 V2 b: t% Q; J2 M
用于Flash加锁,加锁后将不能对Flash进行编程和擦除。. ~; M$ A7 O( I3 j: I% ^

: Q8 |/ p! s# z' k70.4.2 函数HAL_FLASH_Unlock
4 w( u1 a  ]( l4 r7 W( Q函数原型:; C7 p% U6 ]: v: H, o
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)9 Y( V3 @7 M. U9 e5 \* C: w
  2. {
    : _% T4 l7 Z# G% c  J, s+ \
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)& m) S& K+ K: O' B2 b( B3 W* t
  4.   {8 K( O. l* X$ r" L; e3 @0 p* t
  5.     /* 允许访问Flash Bank1 */
    5 F9 _# D- h+ V. W$ F, K) U
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);( e% I+ u( r2 ^. y( ^/ k
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);4 h; U. ~* Y; ?0 M5 ~9 D9 u
  8. * W7 a8 e5 D. M, f9 O9 [
  9.     /* 验证是否已经解锁 */6 r% I! u3 r5 F3 s
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
    # R2 _$ G# r: D8 A/ H2 H/ R+ p
  11.     {
    / U& q1 E: O% Z  U, F0 l  v: `1 v
  12.       return HAL_ERROR;( P% p7 R: o8 T4 w, G% G
  13.     }8 g9 O5 J! ^* ~  K4 ?  g8 D
  14.   }) L% }, ~2 b$ V3 X  ~/ v. v

  15. ' m3 n( B" r6 W6 Y6 O* D( r& v
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)0 O7 s9 S2 \1 d
  17.   {  s. E3 ~& I0 I7 V9 v1 y# _7 u
  18.     /* 允许访问Flash Bank2 */9 E4 T6 }" t& x
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);
    2 C  q  g" r& G
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
    7 C0 T4 Z# W% o) Z# _1 U* k
  21. 3 z' ]% d2 _# C  f9 S$ X( `
  22.     /* 验证是否已经解锁 */
    " b. v9 r7 x. V! L  c% t; d$ e( z
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    - h7 E3 w6 r5 |2 z! L
  24.     {
    7 c( U: E# l( P5 W: t. p" c
  25.       return HAL_ERROR;9 @- p/ a" q+ U* z* F/ Q1 W
  26.     }
    & I& c: k8 I! L& N) D# i. I# ]) n
  27.   }
    # I9 g$ x0 S6 a# Y4 n0 H" i8 R

  28. , a, ^6 C; G( r4 c2 k1 L0 }
  29.   return HAL_OK;: E* u* e2 \- d% l, ~
  30. }
复制代码

& K1 n: G- t5 [% g% b9 n函数描述:8 Q" F  U. Z: V4 g. B. i) u
7 F$ t- E4 P8 e2 P; o: w( v
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。& c0 F# Q7 i2 `/ e
  K- w+ ?. O; H2 X7 ?
70.4.3 函数HAL_FLASH_Program
* _% b) u; c2 @, @" K/ i函数原型:; v9 g2 u/ u5 ~1 z; Z

. M+ u* z# d0 L# I
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)0 e5 w! U2 |' ]0 @8 H0 B% Y( Y
  2. {/ R1 ~" m8 r% N1 V" o
  3.   HAL_StatusTypeDef status;
    7 z$ _8 l: q5 A7 s' g% l/ s
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;
    * Q! j1 [- c  }# |
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;! u6 O1 i# _  A8 k! K# l
  6.   uint32_t bank;1 K" W; t4 p  j' Q8 u5 {- w. n8 u( Y
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;* X' B! O# H9 \
  8. 1 r) |! r3 A3 O
  9.   /* 检测参数 */
    ; h, i7 [7 R: z" X5 ]
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
    6 D3 S0 D/ Y+ Z- Y+ w2 K: [
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));
    0 \' k) `1 z% T& n* a$ U" J9 B$ u0 D
  12. $ r& h% a; ?. V5 g; P( ^
  13.   /* 上锁 */
    , P8 A* {, q! n, X4 @
  14.   __HAL_LOCK(&pFlash);! ^$ w9 g7 F# S+ g- {

  15. 2 t3 X7 B" I! ~; L7 T- S2 I' Y! H
  16. #if defined (FLASH_OPTCR_PG_OTP)
    % N, Z, i0 i4 C, \7 y2 F& G
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))! j' Y5 C$ ~8 r! Y, Q9 N' |: S" _
  18. #else9 T! \. ^7 E* [$ S; g0 x6 ]
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))
    * R( B; e/ t" x+ G& N, G* C/ i
  20. #endif
    # ^7 u/ D0 B$ O2 `& C: `" Z
  21.   {& A9 j2 R% o1 @- M! C. k
  22.     bank = FLASH_BANK_1;. d. M4 t8 M% W& l: M8 V+ F5 C
  23.   }1 w3 J  E" l6 k/ P( g0 w
  24.   else4 v9 c# `% L6 D- J% B9 q
  25.   {
    9 a3 A% ?  L) o: ]" ?/ Y& ]
  26.     bank = FLASH_BANK_2;. C( J) q0 R$ _+ q
  27.   }" ?; _+ ~3 ^  n2 l" e( L
  28. ' w2 H* j* N+ i6 b3 D1 h
  29.   /* 错误标识,无错误 */% h, @! w6 k* {: ~# a
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    4 i5 [4 S% N) h

  31. 6 `- d9 V  N7 {  [8 q( h2 W
  32.   /* 等待操作完成 */7 @8 f5 E7 Q9 X1 T
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    $ @2 t* v+ \$ h4 [& _
  34. ( Y/ x3 Q0 _; [
  35.   if(status == HAL_OK)' F/ W- h6 ?6 \) K8 ?- l0 R4 j
  36.   {& ]$ o  L% o. \) o# Q1 f
  37.     if(bank == FLASH_BANK_1), N& x( p* v9 R- {; V( |
  38.     {
    6 _; g) L+ n' e: N
  39. #if defined (FLASH_OPTCR_PG_OTP)
    # Q- c$ Y, _7 f1 K$ ^
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)! n0 F. m0 ]: J( J  x
  41.       {
    . c# I# T7 \- R) C
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */
    0 n4 F- Q; I* S$ ^
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);8 `* D" l" ]4 x: m3 |0 t
  44.       }
    3 y9 u2 z2 J% ~, J2 V5 M# \$ ~# X, R
  45.       else
    . {) {- Z. |( h0 n) d
  46. #endif 4 P( ~% _; @) M
  47.       {( @5 i) l  Y; Z
  48.         /* 设置PG位,使能可编程 */+ r5 q, B8 y4 p
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);- {6 }' [  |' v9 d* V. R
  50.       }; G* u8 |; N9 A. |
  51.     }2 C3 S9 ?. a' @) s7 N/ z
  52.     else
    ' M  Y( P1 d* L% E- B4 F
  53.     {
    5 u! P+ |. o- j) h2 u
  54.       /* 设置PG位 */
    7 K$ k5 R* @% a5 @8 T, U
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);
    $ _* ?: B8 R3 d; x5 _! ~4 B1 s
  56.     }. f& ^' L" ?: ?0 I9 i2 a
  57. $ ]( _3 r- C' f% a, d' x
  58.     __ISB();
    3 Q0 ^  }0 v4 Q( D( ?" n
  59.     __DSB();/ d) ^6 ^7 N+ ]3 {; D) B' a: z4 G

  60. ! Y# f' g6 C2 Y' n
  61. #if defined (FLASH_OPTCR_PG_OTP)- ], U2 o2 b2 u" y
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    # [# U( Y( _  V; t: U/ ^
  63.     {
    , j, _4 T! Q4 H% W1 X' {
  64.       /* 编程OTP(16 bits) */: O6 ~9 |5 j  ?! E/ M/ c
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;* p  r& C: ~5 |) f/ B/ V
  66.     }
    ) S$ o0 T( Q. ]) ?2 Q$ O
  67.     else
    6 f0 m5 D& t5 v  a* `: v: N
  68. #endif 4 [8 L' B* }% E2 W
  69.     {
    % H: `) M( S5 a1 }
  70.       /* 对Flash进行编程 */6 ~- r  K& L2 [6 \% h0 P: k0 I
  71.       do2 h% P4 l. {5 B: @2 \! z  s. g
  72.       {! U/ D# O# L6 f+ c* m! a" Y1 c! v
  73.         *dest_addr = *src_addr;% o+ G/ i! I# t# \) u
  74.         dest_addr++;
    % X/ L7 r2 t, a( y
  75.         src_addr++;
    5 R8 x' A: ]: h. B
  76.         row_index--;; N) @: B5 n: w2 K* Y" K
  77.      } while (row_index != 0U);
    ) Q) d' n/ N4 f9 a
  78.     }5 L- P; ]8 {2 u

  79. : [, u' t" s. c2 }  k- H
  80.     __ISB();9 Z' H; w3 Y+ X- ^
  81.     __DSB();
    ! L: p3 W  [6 C1 A. K- M1 W; }
  82. 2 _* y- N; k0 u* V3 g
  83.     /* 等待最后一次操作完成 */
    - x4 i) j0 {8 o6 [& ]
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    0 V+ }# ]* L/ J$ R! X

  85. - f0 F/ ]$ }4 B7 p% s* C
  86. #if defined (FLASH_OPTCR_PG_OTP)
    / A& Q2 C- Z1 z+ |& l( \
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    8 k: f6 C' }9 N! w& ^
  88.     {" P1 L. p* s3 w% T+ S) N- o
  89.       /* 如果编程操作完成,关闭OTP PG位 */7 O2 v$ i9 A( ^) t! v
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);/ A3 G& h8 C# s: F& ]& ~7 ]
  91.     }; m; f3 n! k. Q# U
  92.     else
    ( R2 f/ m* T* K; T, M1 `
  93. #endif ' R! i& C  T1 l
  94.     {* X8 P$ w) i* d  a( I8 f7 |
  95.       if(bank == FLASH_BANK_1)- U+ c0 y0 \* G/ I" ~  r- o
  96.       {9 `9 [: m( ]& t1 q# y# ]( t
  97.         /* 如果操作完成,关闭PG位 */* X! {9 Q' f7 H" c; @2 `
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);
    6 M, _0 c9 j3 s6 i2 K
  99.       }
    - v1 U4 q- T, G' k5 l" S
  100.       else& s' D; U3 w4 M5 K
  101.       {5 r. k# M$ \" U' U, a! x8 ?/ `
  102.         /* 如果操作完成,关闭PG位 */' {/ m! W9 t$ \2 q9 i
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);+ a9 I2 }, @8 X8 X+ V5 Q. O
  104.       }
    ) q1 E! P, G, a- v7 B
  105.     }
    1 W  n1 u6 K$ S: H5 G3 @$ u
  106.   }$ B: A  O7 l1 @8 @3 X+ B. e+ g7 o3 J% P5 M
  107. 1 v  Y  l/ v9 W( y
  108.   /* 解锁 */
      V; a2 t- |; R! A$ W
  109.   __HAL_UNLOCK(&pFlash);
    * t2 C/ N4 [3 v6 N; V

  110. 5 g9 K- Z9 h. {" s
  111.   return status;
    ; L# [8 o3 K; c- @! P2 V! L
  112. }; S1 B4 v/ L' g/ u( A4 T9 j$ ^" |
  113. + i: o$ E6 `3 ], D3 k- S
复制代码

6 T! r; H) l* o# f8 {6 {% Q: R. Z函数描述:
, l3 n  E1 p" y5 t此函数主要用于Flash编程,固定编程32个字节数据。
# M3 g0 j0 z  i" [& \7 x/ d  y, u* U- G. ~4 Z
函数参数:
' w7 ?( c) q' Z9 }第1个参数是要编程的Flash类型,支持两种参数:; L5 R) {$ q3 q  U# `! a6 Y5 s% r
  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
6 y, T1 N6 r- H  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。
: A% V5 y% [0 R/ \5 k: a9 C
7 Q. J* i$ C& E+ c' Y* Y" ?第2个参数是要编程的Flash地址。
% n  J  T' A2 @
( P. T# V# B- H% K第3个参数是要编程到Flash的数据地址。
. R4 r( }" K: d6 R6 H, y( }+ z# y5 e返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。  d" {+ s9 O2 p4 q& p8 C0 e4 U+ t
; r+ H! Q1 g8 E4 r4 [

/ K+ P( H# i9 m注意事项:
: [4 M" [, n5 c5 o3 L  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
9 e* q, `6 G& c$ {# ^0 P  第3个参数务必要是32字节的整数倍。
% T6 Q: M& y4 z  k0 Y4 o8 `: O$ v% W3 O* m
70.4.4 函数HAL_FLASHEx_Erase
2 K2 U- t8 @# _8 j函数原型:0 N5 o' @4 M3 G" {/ o
. n0 I4 U, p6 W, y) F4 Y: R
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)
    - @' d# g2 D  ]$ ?0 I( }" W$ S; G
  2. {
    & l  [9 N$ e# \! e( ^
  3.   HAL_StatusTypeDef status = HAL_OK;
    . S( q$ e8 f7 ?5 N6 W! }3 T
  4.   uint32_t sector_index;! z7 R) n3 B0 \+ u/ r) n  ^
  5. 1 k2 ~) i: ]- b, k8 `4 E
  6. /* 检查参数 */
    1 ], X2 Z% I- [- |6 x
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
    ) i1 B- _5 u( q( }5 U
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));8 K5 w7 C0 l4 o! r' X7 \% j

  9. : |/ n; H/ `- I) W# }9 s: n/ E
  10. /* 上锁 */
    - _  h1 Y  h3 L4 b0 l1 g
  11.   __HAL_LOCK(&pFlash);2 ~, \3 [8 C" y* W" C: l: _

  12. : P( I* j( h7 u( X
  13. /* 无错误 */# d, o6 k# A0 P- j
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    - s9 X7 f4 z' Z6 |
  15.   p; i5 H- ?# A/ U: e* r
  16. /* 等待BANK1的操作完成 */
    & A0 Y/ ^- G9 q6 Z3 w# `. {
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    / q( w6 t: f; j: s& z# z) ^0 c
  18.   {+ o* w3 k! U) i8 t2 e7 B
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    . }8 m; I+ ^2 C: l* |3 t. z  G  G# V
  20.     {4 L% i3 ?8 h9 {, j  t
  21.       status = HAL_ERROR;+ D* U& t6 @3 R: I$ z1 p+ X
  22.     }
    1 ?+ |" S' N$ ^) f3 d* U) X
  23.   }
    9 Z; C5 y. k, J" Q
  24. " o- b" _8 W- Q  s- G. z! A
  25. /* 等待BANK2的操作完成 */
    ' b* I" b2 y- n/ n
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
      }6 W1 x% m8 F9 `
  27.   {
    9 h( h  R9 |4 y; |" c  r; S1 W# r
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)" ?. J; w& C7 |* G5 m8 ?
  29.     {
    ( j7 U9 P$ H- {3 Q6 D
  30.       status = HAL_ERROR;
    7 Y- ~3 X' l& r* \2 ^5 d1 x
  31.     }
    $ I3 `2 Z5 Z) l% l: G2 A
  32.   }/ t; ?4 s4 n* v

  33. / D+ f) f1 e5 n) H6 M- _' d5 t  H
  34.   if(status == HAL_OK)6 H  n) s: ~6 ?
  35.   {- k- q1 b" L3 j1 V- `
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
    % }$ ~3 L3 D2 j' [3 u# T9 `! v
  37.     {
    ' O4 h$ `( k# J% W" y. L( @
  38.   /* 整个BANK1或者BANK2擦除 */
    ' f& h9 |4 @; J( `
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
    " q- e5 d( _& I- @
  40. 7 H% v3 M/ @! ~* ^) C& i- P
  41.   /* 等待操作完成 */1 ?' R& S; r2 x5 P" T% h
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    9 @8 W0 z* _# I: c" T
  43.       {% n* z3 R- M% F* J0 ~4 {, I" U
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    5 k4 }# V7 ?" j# c1 r
  45.         {: Q# o5 I0 f8 M; u
  46.           status = HAL_ERROR;
    2 l9 o0 S6 {& n5 m! `4 m) N  a
  47.         }% C- X- F2 M  _/ A
  48.     /* 如果擦除完成,关闭BANK1的BER位 */
    2 K; h4 d+ L0 d+ ]- k8 o- O
  49.         FLASH->CR1 &= (~FLASH_CR_BER);$ L9 W7 S8 L# K3 v. `  \
  50.       }
    ; _, E5 I6 H8 _9 X% e; r
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2): h; x- a- f) o: W) \! v
  52.       {* p  X, g; [, R  k! Y
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    - J0 X8 }, C7 v
  54.         {' O8 K0 }4 D: }( a- _6 T9 X! q% O
  55.           status = HAL_ERROR;
    . X0 `  X  H8 B" M& g0 N/ f' e
  56.         }5 N: C, C& m. S
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */
    # k* T6 W* x# B) `
  58.         FLASH->CR2 &= (~FLASH_CR_BER);
    " m' |+ o$ b8 l+ n, c. L
  59.       }
    % |5 X! ]" K, s# A
  60.     }0 r7 w; p! P+ E" _: ?6 f
  61.     else
    5 ?/ \+ q* a! M1 q, R. P
  62.     {/ z" ~1 w7 _. ?4 x  i
  63.   /* 初始化扇区错误码 */
    ' o* I6 C, F* m6 S; P
  64.       *SectorError = 0xFFFFFFFFU;' f5 {3 m# B- x/ _3 y! E
  65. * }. P2 P1 ?. V! i
  66.   /* 扇区方式擦除 */
    ( H5 G7 q+ R% ^" w3 h
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);  K. f' \, z: {
  68. sector_index++)
    0 V  U/ n6 A3 ^$ a! {- z2 m; m( d' F/ G6 h
  69.       {
    ; a$ m- l, d1 E+ P: l: X
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);5 D( u" m6 X$ h/ H. J, L
  71. 7 C( G5 x" s# o) I/ N! k5 h/ P
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)% U5 R7 d9 \% ^+ X( S4 n! G
  73.         {8 ~2 U; i0 S. u4 M' q
  74.       /* 等待BANK1操作完成 */, z7 V7 W; Z$ E* [, C, p
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);0 s& P9 L6 ~- O: v  g
  76. 6 U, u' C9 w% p' ~2 D0 \
  77.       /* 如果擦除操作完成,禁止SER位 */' H9 C9 F" W) w5 N
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));' E( l9 Q! \: |5 I- \" F1 n
  79.         }( u) k! S& G2 {; {/ e! u. I
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    , p# ?0 F3 u0 l2 W, O& K2 _9 j& @
  81.         {9 v& e: K/ M" S
  82.       /* 等待BANK2操作完成 */! ?! B8 G' L" A
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);6 u1 p& w7 U9 M' s$ c1 Q

  84. 3 ^% l( Y) x3 v5 g- z( x
  85.       /* 如果擦除操作完成,禁止SER位 */7 q, d! y8 \6 W5 u; F; w$ _
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    : w3 F* ]! M1 m; Y
  87.         }
    8 f- T- D/ `# G; |" D3 z  L& v
  88. . ], O& o3 r% @6 w* g2 R
  89.         if(status != HAL_OK)
    $ R3 l# o! D# K  t0 B
  90.         {
    . F  A7 t1 b4 }9 G0 A
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */
    2 f& F' m$ y+ u: A! @: k# d
  92.           *SectorError = sector_index;' C% }* B9 q5 [# J2 N: `/ Q
  93.           break;: C8 r  X2 i3 _% F$ y$ Z
  94.         }/ ^+ Q2 h) H) i* M, g/ m
  95.       }
    9 ~" a* j: W+ `4 m! A* b7 [/ l
  96.     }
    ; ~9 X$ s: W6 p" B/ P& X1 V5 n
  97.   }( M. L- q2 o* W3 y1 A4 G$ f
  98. 0 N2 I; J% `/ E8 `9 p
  99. /* 解锁 */- Q* m0 H8 N& S/ a
  100.   __HAL_UNLOCK(&pFlash);  ~  n6 O7 y/ W
  101. ' ?3 u0 T# f! U+ B: _$ R
  102.   return status;5 g( p  Q& e% [6 Z$ R% ~* A7 d# s
  103. }
    . Q% b0 O; m& c) q
复制代码
7 [$ R. E( _5 J: D, u4 Q  Z
函数描述:! q# x! f5 c' j7 L! r
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。' c) g+ H. @4 |
" a9 w7 N- M$ y' }( U
函数参数:4 L& T, c) t, _* e  g4 e; t
  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。
% i5 Q) g+ x0 {6 P# R  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。( D4 c; \. B8 i. b
  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。6 t3 z8 s2 Z& j+ M) }! s
7 E' Y8 ^7 x  o. {: M
70.5 总结7 f5 Z' e* \5 K) X) s
本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。6 I/ Z2 b1 D3 `/ ~* n- C2 p* {% e

7 ^' K. H  Q$ [& t2 X* x) J) }3 g3 K' M

: S1 O1 O) j& ^& z$ d) \
收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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