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

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

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
+ w9 E: z. H$ @' R. }! e  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
$ q. p3 H4 v8 L9 ~+ {5 u7 d! t  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。
- G4 B3 r. ?0 Z+ m6 M  \+ R  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。; o1 R2 A, x/ y4 H" ?' k. B" x% f
  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。- M. @2 e3 w$ E  w
70.2 内部Flash基础知识
# I' T- Y% T2 u* b: y  L5 A70.2.1 内部Flash的硬件框图

" T) D$ ~. g. h0 _* f0 h7 L" _认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。
. K. D6 U: B- R! u0 P0 c5 ?. |9 T. G4 v; v: {
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
" c6 o$ j" W* b* w9 O
- \' g+ {! T& d! R( {
通过这个框图,我们可以得到如下信息:
! {# U: b2 {# D' h- ~; N8 s% {
( [; h1 @: b! |+ h+ n3 O7 j  sys_ck时钟输入0 Z$ r0 Z! G  h4 u9 ~! [8 g
D1域总线时钟。
3 m1 O, ]" _8 X2 j
6 G/ F0 l4 g, I$ D; b5 U# v  po_rst输入
! [  ?# ^% n$ q! S/ Y% q+ NPower on reset 上电复位。
" V; U. C* p! f3 @  X1 j: ^
+ d; m' Z) X- a) v5 e5 ?( e6 A9 V  d1_rst输入
; n6 ^; j& S8 s" N* RD1域系统复位。9 Y: F; E# j1 G3 I0 T3 J4 e
- K  c. W* c% Q! @4 L( n" H$ W& J
  flash_it输出
; E, W2 n9 E! a. g( f7 i- u  R) `4 |flash中断请求输出。
9 W0 S* V7 ~/ Y1 O0 i4 q+ [) I  q; W( g; {" S. b2 `
STM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
3 q' R4 g/ `" A+ T) e& ~! S2 p7 _# p! |, I) L2 o
70.2.2 内部Flash框架
9 A5 C1 e- d* d3 x/ K1 s" l关于内部Flash的框架,了解以下几个知识点即可:
2 N- z2 `: ?) i5 N0 m
' z9 `" I& ~, ]5 `" t  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
0 p. g0 [2 i+ D) u5 ~; i0 I: q4 `9 m  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
$ o* X" i' C( S8 K( D' h5 [8 f  d2 v. c% h$ j3 L8 z# [
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
- T3 u; I3 s6 A' i9 a+ x

& M+ i# p5 j) Q6 q; y8 TBANK1的地址范围:0x0800 0000到0x080F FFFF。
) ~5 x# @) M6 k/ }* G! x: Y$ v. v
BANK2的地址范围:0x0810 0000到0x081F FFFF。! k" H1 E, H9 P- I2 j' c+ s3 v
  V6 t( `  e1 `1 _# t9 D
70.2.3 内部Flash读操作$ A7 J) E* j+ ~5 \$ Z* I+ F
STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:) n9 E4 h1 p+ A& m& M
+ F7 B, h2 [3 |  |& L) [/ T7 ?
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
9 X, v9 y8 @! h2 \
4 E( D. D/ {7 h1 G
对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
4 r2 P1 [1 _! P8 X$ k0 j
  `: ~$ ?- c% z  I了解了这个知识点后,再来看下面的时序,非常具有参考意义:! q* Z/ ^) W- k& i6 s/ I

% _5 a. @. h8 a注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。
. i+ k6 Z7 k: {- X$ j) y( K1 b+ u& X( i1 f) W( J+ u
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

' M* d* d. }5 I0 e5 ~8 h7 _% z! U* w: W/ X
关于这个时序要要认识到以下几点:- H- ]) y0 k6 z! W; W0 o

4 @- r2 u# K3 X- @, u  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
7 l# L% `* D5 @+ D  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。( s- c5 F2 O2 O
  如果不开Flash Cache的情况下,连续读可以提升性能。
# f9 `) U: N! U# l: e; ?+ F/ d$ N" I9 W0 A
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
: G- F8 Y' ]. P: K. X1 D# ]4 w6 G: g) v+ Q" M
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
& ^4 z. p( e" y: r/ _, O4 ^
( v$ H; ^  u6 C$ D! c
70.2.4 内部Flash写入和擦除操作
0 T% T% H1 b7 X- h& h# c- |最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。
; N* g6 I7 m( j6 |8 e* J' Y) Y8 y% v3 {
这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:2 p$ ]! a* W+ m
! P' E( B& B: i# e6 P0 i+ Z/ Z
先保证这块扇区空间之前已经擦除过了。" h) \/ {4 u, u; O/ j/ w( s+ ~. \
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
( P" f& |- F7 P5 V  J. V+ T检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。/ E4 ~% v0 k# W+ r" [1 i2 v6 ]

/ e' y/ X( _$ nFlash的擦除流程如下:3 d  f' C6 M+ |9 ?
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
7 F! y; K2 d; I  t3 f- k  ?1 t, ?如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER27 l8 v1 t& F5 K1 v
如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。/ Q. F2 ]* @9 ?2 `9 l

# z7 ?* F0 n9 x1 Z$ _
7 ?  R; T  ~6 \0 H% h* t: J70.2.5 内部Flash读保护% [" w, W( j8 s5 d7 v
内部Flash支持三级读保护RDP(read out protection)。
# w9 T) W+ s( y! w4 c' o; t. F  V  o, }3 k. E4 ~! ~, h2 R5 h! |
  Level 0(无保护)
  y) [8 C% v8 p( x9 m# K默认设置,所有读写和擦除操作都可以正常支持。; O: H- u% A+ c7 w9 z( y5 i

( S. d6 S7 }! I! t0 D# e  Level 1 (Flash连接保护)
7 q: ?5 U% J% m. {) b% v6 Q5 I  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
5 i, _" B& p: R7 H" _& J# M  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。" x5 z- h4 U' M" X! ?0 s6 ^6 ~
  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。
& h! P! U" Q  i) |& o 5 @1 t6 y& y* `5 g' i  i
Level 2(设备保护和自举保护)2 P- |. N( U( k. c  t$ E7 V
  所有调试特性被关闭。9 V" w" O6 `" [
  禁止从RAM启动。
1 X6 f/ n. G+ F- O# R# V, ^, Q, I  除了选项字节里面的SWAP位可以配置,其它位都无法更改。
8 U2 ~% r6 U: W. x2 E2 f( r  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
0 n( c' O, N9 N' _) r9 Z8 |1 d! `9 f) m9 I
特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。
2 g6 ~; t2 M* q9 N! [/ h% v  B) B+ a+ n1 a2 N" J
如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:+ Z9 V) K4 v/ d6 \0 I' D

( R, F2 _% ^! B  t3 N* d2 w: ~3 W
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
2 _4 P$ x/ W" @
9 ~4 ^" m2 S/ B! y2 {

/ N# u7 s" ~; Q+ G* `& G70.2.6 内部Flash选项字节
2 ~: W3 ]5 w$ ^5 N4 i, uFlash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。
, B$ I0 d( C- X8 @# J, h
5 q  z' r4 e) z0 S* F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
# W. V. R  I# g
9 `, P  N% p# Q& s- O' K9 f9 s
70.2.7 内部Flash的ECC校验8 N- v9 A( S& N# }: y( ~- ]: V+ W
这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。
/ P3 n- L- A' W+ r
- C4 D: P6 M  B7 ~& O对于STM32H7带的ECC校验,一般不需要用户去管理。
+ m% @% i- ]5 \' P, K2 }. L; ]# c( n& N/ R" E
70.3 内部Flash的HAL库用法6 W+ H2 |4 D* ~$ T4 K2 J) e: e
70.3.1 内部Flash结构体FLASH_TypeDef9 V+ g. x0 l) p1 R% Y# S; y
内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:6 t7 B3 `' V+ W# A% u
' Q5 y9 Q$ b  q2 `7 g$ {6 A. [, H$ x
  1. typedef struct
    6 u& g  }. I, v, w" Y3 a
  2. {+ D  X) z6 r# }  D
  3.   __IO uint32_t ACR;            
    3 h0 E; ^; }# {% u. @" @
  4.   __IO uint32_t KEYR1;           4 q& ~+ o0 Z/ p+ M: q! u3 R) |* E
  5.   __IO uint32_t OPTKEYR;         
    3 p) s! q0 q0 b4 T
  6.   __IO uint32_t CR1;            
    * n! R1 f  X5 _) Y! q3 z
  7.   __IO uint32_t SR1;             7 K* k7 f* S2 A0 k9 h
  8.   __IO uint32_t CCR1;         
      X' F0 s% g2 d" G9 o
  9.   __IO uint32_t OPTCR;           9 g' n4 b9 r& ^3 R- M) Z
  10.   __IO uint32_t OPTSR_CUR;       + A! g8 _* [0 @& I7 |- Z; c
  11.   __IO uint32_t OPTSR_PRG;      
      p! m( n! G$ W
  12.   __IO uint32_t OPTCCR;         
    $ w) S6 `/ ^  {& S5 a0 L  U
  13.   __IO uint32_t PRAR_CUR1;      
    4 T4 D4 H* @6 Y! w
  14.   __IO uint32_t PRAR_PRG1;       3 i) [7 |6 ~; b- {/ O
  15.   __IO uint32_t SCAR_CUR1;      
    1 F; ^) z# e, c9 }$ j. b/ w
  16.   __IO uint32_t SCAR_PRG1;       5 y- F! S) U- Z& Q! V& V
  17.   __IO uint32_t WPSN_CUR1;      
    0 p, ^- u4 M) j/ \
  18.   __IO uint32_t WPSN_PRG1;       # }- k* J5 U8 m; h. ?
  19.   __IO uint32_t BOOT_CUR;      
    " S0 v$ `% w; D: @6 A0 O  E$ o' Y
  20.   __IO uint32_t BOOT_PRG;      
    & m9 t7 d" |. e
  21.   uint32_t      RESERVED0[2];    ( Z5 n/ F# e7 B7 i% Y5 ]. @
  22.   __IO uint32_t CRCCR1;          : U5 q4 S$ U" r: C3 J4 W
  23.   __IO uint32_t CRCSADD1;      
    ; h; |4 t( w7 ?
  24.   __IO uint32_t CRCEADD1;        % D; r& \; V* p% x
  25.   __IO uint32_t CRCDATA;         
    - s! g- e7 Z5 l8 b! T
  26.   __IO uint32_t ECC_FA1;         , `4 M' |  ~# b" C3 l- _
  27.   uint32_t      RESERVED1[40];  
    ' ]( x: J7 A5 |) N
  28.   __IO uint32_t KEYR2;           8 }* R: V. y1 B; ^; T
  29.   uint32_t      RESERVED2;      4 U  P! q+ o7 s* e: i5 `
  30.   __IO uint32_t CR2;             # N& N+ E; D9 W& }) Z( F
  31.   __IO uint32_t SR2;            
    # e# w& Z/ d% m1 K5 |: F
  32.   __IO uint32_t CCR2;            
    7 U! B, r8 H- s: g" e
  33.   uint32_t      RESERVED3[4];   # o+ {' w0 |( [
  34.   __IO uint32_t PRAR_CUR2;         c8 C; }, V  m1 o
  35.   __IO uint32_t PRAR_PRG2;      
    9 {. |) w+ x; f% U& U: z# w
  36.   __IO uint32_t SCAR_CUR2;      
      v0 E" g# f1 s* C: c
  37.   __IO uint32_t SCAR_PRG2;      ; O5 l" U) p4 _+ U9 j; i5 s* Y, v2 X
  38.   __IO uint32_t WPSN_CUR2;      
    . m# G! U3 q8 M+ B$ j  W
  39.   __IO uint32_t WPSN_PRG2;       + _1 i  p6 m/ M2 O& p& G# {+ q
  40.   uint32_t      RESERVED4[4];   # S/ d: u+ x& _3 O4 V7 C1 s
  41.   __IO uint32_t CRCCR2;          ' g7 B- W  n9 ^% Y3 A7 G" v
  42.   __IO uint32_t CRCSADD2;        1 _5 {, y+ G0 l  X2 z& s0 s. s
  43.   __IO uint32_t CRCEADD2;        ) T2 Z$ w7 [( b' b' z
  44.   __IO uint32_t CRCDATA2;        & @% E+ r7 y, Y5 q
  45.   __IO uint32_t ECC_FA2;         " V1 C3 g7 o1 m; [
  46. } FLASH_TypeDef;
复制代码
5 f% J  E1 Q: ^" N- l9 X
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。# W/ Q- y7 W0 D3 K  W1 J

$ w4 G. D1 ^2 N" d2 W__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:4 {3 z5 O1 ?, [( t' k5 V
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    % W* I, z6 w- K- k% h7 M% T
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

  l6 Y% u* v) t6 W! v$ U8 W下面我们看下Flash的定义,在stm32h743xx.h文件。
7 b0 C. u# T% @8 D. C; U- R3 Q' [. [9 g
  1. #define PERIPH_BASE              (0x40000000UL) 9 l" e, P' o( }+ {2 d, B3 m
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL)
    & ~- G( e& F. F1 n. Q( H: V
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)) i' L1 G4 O- Y
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码

9 z/ z! u; q# }6 i  ]9 v' L我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。0 E# g% G, j+ Z  d
% ^4 U, G/ d$ Q/ G. q* s) T
70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
8 U6 V7 b, g4 D: g- p下面是做内部Flash擦除的结构体,用到的地方比较多:
7 U7 w8 |# L5 L% O. I2 a# ?  N6 r
$ ?- g3 Q% v9 Q2 E. Z
  1. typedef struct
    % V6 \) E; E9 r/ _/ B& h4 r
  2. {
    ) {! m5 B$ N5 \" ?8 t* s. L9 k1 f
  3.   uint32_t TypeErase;  3 I' @# P% ?. k* H7 g
  4.   uint32_t Banks;       ; u; m$ w, c& {" q0 O/ m
  5.   uint32_t Sector;      
      X5 \, z5 D  g; f+ |/ G, ^
  6.   uint32_t NbSectors;   
    ' d3 l3 d$ L4 ?$ [* j3 }) w
  7.   uint32_t VoltageRange;
    ) l: y9 D3 P. E3 A( ~9 X
  8. } FLASH_EraseInitTypeDef;
复制代码
5 J/ Q" H+ c" X: b
下面将结构体成员逐一做个说明:
: N2 S; y+ R( H  TypeErase
9 a* Q; Q" L% |9 f  L
* j( o, h" G: Q& {1 \
8 X0 i. m$ m% ~( Y用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:
7 M2 [: N3 n1 U+ G8 @3 Q; Z* x2 E. ^4 {0 E7 a# X% H* T% {
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */, {  t0 z# p# N, u3 d9 Z3 T+ y  g0 [0 K
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码
" S% [/ g) d" P  y
  Banks
: W% ^. T- i, i8 l) U  _. ~1 ]9 E0 a用于选择要擦除的BANK,或者两个BANK都选择:2 _5 ~7 P8 u3 u# Y0 d# X4 A
: r4 a, Q/ v4 y1 R; d. L
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */
    1 ]! |& ?6 k7 ]% j
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */. @/ J- L% [. q6 L$ L$ d6 A
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码

; A: W& y/ Y( ~; \3 P- |  Sector: X2 v# l+ }0 K7 Z( p
用于选择要擦除的扇区:. z& ^/ O$ `; q6 U$ U: }
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */& w9 @( k% H3 c& y& }' U% H9 Y
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */
    . L7 d) T5 k2 j  U
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */
    , Q4 p! @. F/ [- H7 p; h
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */
    & b1 @# R9 Q+ H/ e$ H
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */6 L% t% r4 F9 o6 s' `
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */6 e# i$ \- u2 a+ l+ R; s
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    5 Q/ ]2 \# p0 c. C! a% G! i6 C
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码
3 B# b* w# R$ P$ {( g% N: Y
  NbSectors
  q! h* X2 F0 b/ h9 i用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。
5 u9 J+ l" \1 M  _6 J) z- ?
; U3 q6 J  X2 T: y5 R" L  VoltageRange
/ l4 B, p/ E0 _" X( Y3 T+ X用于设置编程的并行位数,电压不同,位数不同:  D/ g5 @# O$ `: {  }
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */
    5 ~: |7 a% _9 D7 l8 _4 h/ K) M
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */$ g  j; V2 \4 l* E! l* h
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */
    8 U  k9 T. ]/ G( K1 u; o# p
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码

. N+ L  a/ C+ h! M3 I+ i3 ^7 q3 ~% h8 Y
70.3.3 内部Flash的操作总结
1 v6 N5 Y+ i$ T, T) a& V& a  l+ Q  M( i3 @5 ~

: B$ A+ c5 ~+ g& V使用方法由HAL库提供:+ X  A# K; }; W, W) `' S
  Flash编程函数操作流程
7 x, T5 K* k, ?( E: w( u' c7 d" }  Flash解锁函数HAL_FLASH_Unlock。
% A# I- B* y6 {; X  Flash查询方式编程HAL_FLASH_Program。' h( J7 P$ v1 L2 f; ]' L, n
  Flash中断方式编程HAL_FLASH_Program_IT。, R& a# h5 `4 O' j; e( |! Z- o
  Flash上锁函数HAL_FLASH_Lock。
- _0 j% Q8 ^* w* `; h  5 o, k  q. M/ R9 f  S. e# Q
选项字节编程流程
4 H$ P/ u! R, O4 X& _2 C$ ?4 P' U  选项字节解锁函数HAL_FLASH_OB_Unlock。
$ j) }( w6 P* _. x4 ]+ W  选项字节加载函数HAL_FLASH_OB_Launch。5 x" h$ h# c1 P: G  L1 c# ?
  选项字节编程函数HAL_FLASHEx_OBProgram。- d5 u1 u9 M! F$ s3 L7 w' n0 G
  选项字节加锁函数HAL_FLASH_OB_Lock。  t  D( r* ~- q& A# a

" t$ x1 W, }2 a; Q Flash擦除流程, Q5 K, r6 v5 l: }7 x/ Z
  Flash解锁函数HAL_FLASH_Unlock。
* X; q$ U- u" G( m% t. }6 y  Flash查询方式擦除HAL_FLASHEx_Erase。' Z- K" w0 ?! n1 G! _& D9 t
  Flash中断方式擦除HAL_FLASHEx_Erase_IT。
( i& o; x( a4 V5 o, M1 T5 r( v- q  Flash上锁函数HAL_FLASH_Lock。
4 N- R1 R9 M3 i) }9 X, }+ S4 t5 j1 Y2 t2 k8 D9 p
6 n" Y9 a) V9 ~- ?' l
70.4 内部Flash源文件stm32h7xx_hal_flash.c+ n' E4 U0 T& ?% M: T0 M7 M
此文件涉及到的函数较多,这里把几个常用的函数做个说明:, \" Z5 B% a0 J2 q9 Q5 S

# D9 g; _6 T5 G. r  HAL_FLASH_Unlock
. O  `% y- b- J9 S' J* Q  HAL_FLASH_Lock
" e; u, |  V# l# K& ]1 c  HAL_FLASHEx_Erase
) h/ y/ u) I, P6 i" r0 M  HAL_FLASH_Program  l; j- Z" H9 f5 c

/ [' d- A; k6 N2 X' j4 j* |+ M70.4.1 函数HAL_FLASH_Lock
$ M" o1 |; ^! j: T函数原型:6 I: \# w' M- N

" a1 }8 d2 _: ?* r% d3 y" `. ]
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)' E! Q0 n. ?* j$ l6 O
  2. {7 ?/ O! n7 L# i) i9 ]1 [
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */5 ?% I& F  t5 u% b9 s/ W
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);
    8 f. G" F- E8 K; d* m
  5. & A0 ]' h: n4 e' S; d9 C0 W
  6. /* 验证Flash Bank1是否已经被锁住 */
    , x, |0 O/ e6 }6 T" [$ I7 B8 ?
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U). b( f' A8 g0 g- t8 f) K
  8.   {
    / d& Q, _+ s4 {' A4 V
  9.     return HAL_ERROR;" }, L8 M) ]' {8 Z9 K; s
  10.   }% V) R  O; g* E2 n
  11. 0 `2 l9 S* `5 Y  M$ Q$ `
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    7 f  b4 ?5 l8 m: S: f! Q
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    0 G+ |0 j+ b: W6 J
  14. . N! Y& S: o2 O" l& O
  15. /* 验证Flash Bank2是否已经被锁住 */
    + f0 i" F! p- h+ x$ K, M3 h) `5 o1 S6 ]
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)$ U3 g, w1 c5 t% X, i6 e1 N
  17.   {2 P& o3 `  L2 H" [5 @; h# ]$ E" T" A
  18.     return HAL_ERROR;: m8 |* P) E1 _, D+ _
  19.   }" l9 Z( t+ K8 v& @* a

  20. % \: ^7 v/ M) V  a+ }
  21.   return HAL_OK;
    3 d2 W- E; o* R4 _/ A/ _3 L+ p
  22. }
复制代码
5 X0 k* \+ }5 U7 ~7 {# D; a
函数描述:
$ C2 K) n1 J" _" W& U# p' N+ u2 M' }/ p* y
用于Flash加锁,加锁后将不能对Flash进行编程和擦除。7 `0 _8 a3 z" ^' t6 q% J1 n

9 ?  m7 W& ^- G1 n70.4.2 函数HAL_FLASH_Unlock" \& j$ Z! `" U
函数原型:
5 P7 `$ y0 }) M( z4 ~
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)
    & N5 z! X6 e8 Y3 H6 y# w
  2. {
    5 O* s5 V0 P0 W) K5 e3 u
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)" t& F6 V% v! z% u
  4.   {
    & e* r2 y( d' A* Q2 k# L3 t
  5.     /* 允许访问Flash Bank1 */
    1 r- S  b2 @5 m0 Q0 j* K! ]
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);) y% Z2 K- c- }# A
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);
    : A8 M8 I+ x1 K( I% w

  8. 7 P7 @# l. x( A+ ~4 B9 g
  9.     /* 验证是否已经解锁 */
      [/ G0 r: \% ~. r  M+ E* q/ w
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
    8 ~  R. `! _7 e- p3 u, d
  11.     {
    , b4 u7 U8 F7 e. `
  12.       return HAL_ERROR;
    " o3 y0 @7 T+ B% m+ F  \
  13.     }
    " r6 y" v+ J) J/ D
  14.   }
    9 \2 R2 U. Z1 N/ ]8 R2 j4 Y- l

  15. ; n1 i6 p' t& ^& _) l/ I
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)7 V# s) ~1 M- m" {2 d# f8 f
  17.   {# E1 C$ F3 M) @0 y% J' k* E
  18.     /* 允许访问Flash Bank2 */
    5 p; L# i3 j+ n$ B- F3 a
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);+ h( M3 A/ {9 W( T
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
    + c( U, t# x2 c6 m1 c" t: j

  21. 9 c5 K2 _" ^  ]  t4 \- e
  22.     /* 验证是否已经解锁 */" ~# j% j, m! G* \/ h* a" l3 m
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    : R+ _& A1 Q3 Z: W  p5 ]
  24.     {( v) u% b1 T# ^
  25.       return HAL_ERROR;2 t2 m& Q- k. t/ P
  26.     }& o/ L/ i$ H& j+ \& H& j' ?
  27.   }- M5 d# q: E' d: O9 S- q
  28. 6 C1 y5 i- n, g9 Q! X! r2 `7 m
  29.   return HAL_OK;* D. d' n; t) J3 c$ U* x
  30. }
复制代码
+ g* z. I! }4 C) t
函数描述:
) m: `% W$ k1 }: V) ~8 S, p/ o" q. n* A3 K& [! A
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。
" N( Z8 d6 w* m+ O% Z0 f2 S/ S2 e2 q
70.4.3 函数HAL_FLASH_Program9 K# A2 q- V! j/ m
函数原型:/ ]- Q5 M4 S$ J% z' k5 H
  V8 j7 z' V: i
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
    ) `0 N2 R- @$ i# B" u5 b) X) N
  2. {
    + B% m6 F3 R3 f0 x5 b
  3.   HAL_StatusTypeDef status;' ?1 Z( I) A4 a' J# @8 |: L% }
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;% f4 @; s+ }8 Z. q8 E" h
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;; z: x5 A" V9 A7 |
  6.   uint32_t bank;
    / s; f: y' t7 f- D* U$ ]* I
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;( m; Y/ Z- m) \2 t+ i* D0 }7 {3 k/ l: O
  8. ' l/ d/ I" n1 h" Q( E5 B0 m
  9.   /* 检测参数 */
    & L$ R% L) @8 v& D
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));8 l* m8 p* k! }5 \/ s' j
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));& j+ a# E- V5 J5 u

  12. 1 ?9 |/ }. t, h7 b& T8 [2 F: v2 \
  13.   /* 上锁 */
    * t5 s  H  v0 y9 t' \+ U: a$ f& \
  14.   __HAL_LOCK(&pFlash);7 C8 W, a! R8 V- G6 X# B" L  ~" e8 h
  15. 6 x* @3 b! i& p3 C0 t" w5 {
  16. #if defined (FLASH_OPTCR_PG_OTP)
    * V6 Q6 n7 I' b' g" W) y& R) [
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))9 O4 }5 k* K( ^  y- n/ P
  18. #else+ }+ @8 F7 Z( F5 L: A2 ]# a
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)): Y) |" r7 {9 i3 J
  20. #endif
    , `$ L2 [7 X! a" A
  21.   {5 L- N. K( f3 c- ?7 s2 i
  22.     bank = FLASH_BANK_1;1 C8 e+ n! \$ g) S3 q( z; N5 `2 ~
  23.   }
    ' o: \7 H7 l: ~2 M8 C
  24.   else
    , I% _' o6 W; E: A( `
  25.   {2 }" ?7 Y6 u5 g2 H) }' D/ s
  26.     bank = FLASH_BANK_2;7 g' r+ {. s/ L5 k' O
  27.   }# ^. x+ a7 Z: c

  28. ! I0 Y8 N2 A* t0 x
  29.   /* 错误标识,无错误 */
    ; M% u  W" [  K0 q: \2 p) [
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    ( l0 F. b4 W) g% F, W( Q& h* w" D

  31. " M/ W% b2 y5 Y8 s
  32.   /* 等待操作完成 */) p/ g- E( K4 C: m/ A+ P+ t
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);9 `  y9 H" Y  M
  34. # k% R+ t, }) }2 \
  35.   if(status == HAL_OK)
    # \/ B& e8 E5 \" z& Y
  36.   {
    & q. l/ d2 y! Z2 I* H& l
  37.     if(bank == FLASH_BANK_1)) J. e" R" \7 f7 U
  38.     {, W7 P/ b! a) k# I
  39. #if defined (FLASH_OPTCR_PG_OTP)$ N: m/ _' Q5 j
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD): r0 u* L1 M0 m
  41.       {* B/ r6 l# b; [6 e& v& O
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */( z- A( r! X9 z; Y
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);, r9 p# @5 o/ Z" A
  44.       }4 D' _# ?5 H& B- _
  45.       else9 O' n8 G7 I. e: Y
  46. #endif
    0 |$ M, N6 E# B( }' v2 J, _" C
  47.       {
    4 E% U0 O( R, }% k2 ]
  48.         /* 设置PG位,使能可编程 */, C+ Q  q, E" K' C, n6 V8 B
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);
    1 X1 l0 z5 B" A  c( G
  50.       }1 i. R# R% H% R; O# z9 L- b
  51.     }) T: C9 V. b& w9 \+ x, S
  52.     else
    : d. B8 M+ b7 o! O4 i' P/ d, K+ L% ?# P
  53.     {) @9 [9 Z5 e- Z5 W7 \
  54.       /* 设置PG位 */4 Z' h' X. X( x
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);
    # P: H0 p& m, _2 H( J# G* H$ v( A
  56.     }% w7 i/ [& Q- d4 C/ v( Y

  57. 9 M8 R/ y" L- @/ Y" u
  58.     __ISB();) H! c. q+ a' n2 D
  59.     __DSB();# |  o% v% Y4 \/ |3 w3 @

  60. 7 K* s) m$ k8 g0 [
  61. #if defined (FLASH_OPTCR_PG_OTP)0 Q- S8 u# A. ~& A. Y8 J
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD); v3 I+ H9 R  P; v6 e8 h* Q3 C$ r
  63.     {
    % j1 J( K3 |8 l% z' s1 {
  64.       /* 编程OTP(16 bits) */6 c) H2 b  J" c
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;
    4 w' x' D  z' e0 e: l
  66.     }1 L$ U0 [8 e- L" Y) s8 Y9 n" e
  67.     else
    * m. Z5 A" ?' ~6 D" k
  68. #endif - m, _; n: h8 O7 I  S2 Q
  69.     {5 ~4 x0 D+ z8 C
  70.       /* 对Flash进行编程 */' C$ t5 r; m9 f
  71.       do2 |* @3 @- E+ l$ S
  72.       {
    , I- p  x, d8 f" Q  D
  73.         *dest_addr = *src_addr;, Q$ y/ j4 B$ e" Q4 S/ ~. m5 M, d
  74.         dest_addr++;9 R! @) @8 R2 l; P! p& q* o, r* k
  75.         src_addr++;. L. D9 t/ n5 l& n( j% d7 K
  76.         row_index--;7 i: G6 `+ T1 _2 U) D
  77.      } while (row_index != 0U);
    . [$ b9 r8 K; l  i" i
  78.     }$ ^* O8 i7 N. G5 C" x2 t; g4 n
  79. 0 j0 W2 \* P* I1 w; \( S
  80.     __ISB();
    / N2 F1 f8 a- v" F5 {/ z
  81.     __DSB();# Z5 S& t$ z3 g3 R  f0 a2 `" X1 h
  82. 3 i# Z8 M- N4 {: K
  83.     /* 等待最后一次操作完成 */! t2 a* B. @0 {& D) ^- U3 r5 c
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    " Y, Y* l( J( F# s
  85. # M! L# z3 Z$ l% r. J7 \2 B, ?- X
  86. #if defined (FLASH_OPTCR_PG_OTP)/ Q+ `6 f: d7 w9 I0 u
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)5 f, h% [" W$ K
  88.     {
    ; X" E6 k( A5 e2 f/ ~+ e, u
  89.       /* 如果编程操作完成,关闭OTP PG位 */: F# J* _9 C: A8 l5 \" U# `
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    6 [! Y* o# j7 a$ i/ @
  91.     }
    & x+ U# w/ d; o$ l
  92.     else8 B1 [; M0 u* _& S) t/ n7 ^
  93. #endif
    6 U, r0 ^, K/ k
  94.     {' {) W8 U0 R+ ?" v
  95.       if(bank == FLASH_BANK_1): X3 R8 m9 W% @& F9 m' R" o" x
  96.       {
    2 F3 W! j/ x! y* |# h
  97.         /* 如果操作完成,关闭PG位 */
    # P# O7 t1 w) J, C
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);
    ! y# E- r% }# \1 X- d) n/ x* q
  99.       }0 o, ?' O3 O" N. @6 S! S9 j
  100.       else# ]1 h0 K$ d" H3 d3 x
  101.       {) l. ]1 j) W6 C0 Y& o2 A
  102.         /* 如果操作完成,关闭PG位 */
    ! W- M* r4 p& S2 |, y
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);
    & j$ b1 h: _" H5 O6 R
  104.       }
    4 K$ M' ^. N& f. l
  105.     }
    # Y8 L, P0 t" Q- X' Y' }
  106.   }. b+ G8 b) ?  q4 ]( x9 _( x+ ]

  107. - K: n4 x) C' n! F" L! o
  108.   /* 解锁 */% t  D' ]  |1 s7 b+ V$ ?/ d3 t
  109.   __HAL_UNLOCK(&pFlash);7 K3 O. @/ ^3 |! `8 X' Q
  110. 4 D; V5 D) [& R& z5 \0 {
  111.   return status;
    5 o. Z/ t) [$ R# [' \
  112. }
    $ W0 e5 Q+ w" F5 P4 V" i
  113.   M5 d, d  w0 H1 X
复制代码

; a1 F9 ~4 i! y; S- \& l  {4 {7 Z函数描述:
) e3 @0 e9 `* d此函数主要用于Flash编程,固定编程32个字节数据。
) u8 V4 u2 U# a/ ~/ m1 C( c  M$ Z. l  v
函数参数:4 c8 B* ?9 w. d# v  c* Z; Q- m6 q$ q
第1个参数是要编程的Flash类型,支持两种参数:' Q5 ?& r2 D- J' [. l
  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
" B# @2 K1 P& a4 E6 F; ]  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。
, U" f% z, I. J3 s" P6 Z( _& N6 I; K4 h7 R
第2个参数是要编程的Flash地址。
! S8 i) t2 ~$ ^) \! ^) i- q
$ u$ C/ n- F1 b+ A5 a( S5 ~第3个参数是要编程到Flash的数据地址。
5 Q- j3 b2 H" A" P0 g: {! O( c) y) V返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
: F, T1 T7 g4 V3 X7 W
8 c9 [9 f- X: m' N# U; f$ Y5 w$ X: q3 G( {2 \" I1 U
注意事项:$ [* i- \+ _' g8 X9 t5 L) S, J
  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
  D) t1 r5 m* M4 a$ V/ H  第3个参数务必要是32字节的整数倍。: s& l6 a) l4 C- e& v( S
$ ]; t6 J5 ^# _- g$ T# Y
70.4.4 函数HAL_FLASHEx_Erase# v: \2 C( ]6 d" c; o9 w$ b/ z
函数原型:# P, F% p( T% a3 q2 p8 b6 d
; T+ Y  e1 v' q
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)% n+ d1 ]. U7 O! {
  2. {
    - s+ ~) a$ ~2 c- j
  3.   HAL_StatusTypeDef status = HAL_OK;
    , X' n0 D/ r5 Q
  4.   uint32_t sector_index;- G, V+ l" l1 B! y8 q/ N4 R2 ?6 L* B, T

  5. & V, ^+ D5 H) [/ }: z$ G3 {$ Q
  6. /* 检查参数 */
    ( E9 c/ t' W! ^( o( V9 @
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));0 Y2 z. P( E* U2 z% T/ J5 @. C  j7 t
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));
    ) G3 h5 S: e1 W% N: ^

  9. ! Z) I/ A- w! ]6 \$ a8 M3 M* w  d
  10. /* 上锁 */
    & {- d! j/ J9 I% k: o! {
  11.   __HAL_LOCK(&pFlash);& S5 i4 p- V% M" B7 b7 ]3 @

  12. ) m/ l; F( D- U6 f
  13. /* 无错误 */
    2 x8 v4 `, y3 P, ?1 [
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    : @1 k: H0 z, C

  15. $ U3 u! W% |6 g2 k# b  L4 T
  16. /* 等待BANK1的操作完成 */% n/ Q7 @8 n# z
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)6 {9 @$ ]( R0 L$ J  v
  18.   {
    7 Y+ B3 t4 V4 r/ P
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
      ]4 y5 e( B! B  D) L
  20.     {) W+ x# s1 U# ?  g0 a  o1 {  y
  21.       status = HAL_ERROR;
    / Z1 e: a. T, V7 u: @6 L& N
  22.     }9 C$ J% [% k1 r( N' F3 Z# }
  23.   }
    , }  k: q, g$ d$ z2 o( A6 p* V* V
  24. ' p9 G2 q& D/ n+ {" H+ I! K4 O
  25. /* 等待BANK2的操作完成 */
    " M" f3 B2 u; N8 Y
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)" M0 {$ U5 t0 X( Z& Y9 g* r
  27.   {: F: P. M" L5 T
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    8 a; @. A6 h6 x) X  y$ q
  29.     {
    " j" C6 |4 L& i( O5 u; j
  30.       status = HAL_ERROR;
    ( j6 h2 i: X2 _0 L" Y6 V& Y
  31.     }
    0 p) I- o) i4 t
  32.   }
    - g4 D$ i5 B$ b1 @: A1 g5 P4 B8 W: q
  33. 2 i4 O/ U6 `( b" w8 R7 ]
  34.   if(status == HAL_OK)$ f  B4 B" ~1 u# e
  35.   {0 b2 J6 e) x. I; M$ ~, P
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE): A% ^3 C8 r- N' W: p' u
  37.     {
    5 d: W6 Z+ X5 y7 s5 A4 @/ g
  38.   /* 整个BANK1或者BANK2擦除 */
    " W8 j  |9 ]/ ]
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);% w5 }0 I( U9 X8 S, x  H

  40. 2 _9 {7 {7 f- ]) f
  41.   /* 等待操作完成 */
    0 Z/ [, S& w/ N! E, @: B
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    . d  o7 ^$ V9 I5 F
  43.       {
    - y& [6 i9 w% K$ ]( M
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)* U5 r& \: [* J' ]7 u
  45.         {2 G4 i7 `) y0 W: C) v
  46.           status = HAL_ERROR;" f9 ]3 @, ]6 P% K. o
  47.         }( ?6 Z! r$ ]9 a$ A
  48.     /* 如果擦除完成,关闭BANK1的BER位 */: s9 D, \/ R' s4 ~( `5 f
  49.         FLASH->CR1 &= (~FLASH_CR_BER);0 y2 B5 {  B  {; F$ [
  50.       }) q* }0 E, {% R+ a' @. y. \" `
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)! k- z5 C/ t- K4 b9 y
  52.       {$ V+ e+ c( t& K* {8 A( p. B
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    - G6 E+ a3 O* F! _8 i4 _
  54.         {
    - o! U; w( V5 w5 t
  55.           status = HAL_ERROR;; g% I: x1 C  Y: X9 t" W$ @9 _
  56.         }3 B% w! B' \/ L4 d" h0 V
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */
    6 g3 I0 p* {: d& C$ M% z, Z' h1 y
  58.         FLASH->CR2 &= (~FLASH_CR_BER);
    ) e! c8 x5 Y% C, M9 c; Z) H7 T5 K5 x
  59.       }) w. f3 |, P/ N$ ^' m& J( g
  60.     }$ n) q. w- w% d9 |' L2 c$ P, y
  61.     else
    5 V7 W0 a: a( w& b9 O! m1 O3 h
  62.     {: R) H5 o  o$ x; |. a, ^2 J1 k6 W
  63.   /* 初始化扇区错误码 */
      `1 X) y- @) ~: b& o2 a" w
  64.       *SectorError = 0xFFFFFFFFU;, \; a; X! h0 s6 N9 i0 @7 f
  65. 4 x+ t: }& Z* f/ T# b' ^+ r
  66.   /* 扇区方式擦除 */; M, j8 c6 l8 e/ z) U& ~
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);* I0 u8 P" Z6 f9 ?
  68. sector_index++)! [9 t8 c; R  `& w
  69.       {
    1 ?1 B% ^/ g$ [
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
    5 a9 m5 i! @; _' u. P

  71. 4 `2 `2 `& z8 o0 A. Z( W
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)2 {0 M. n) R/ M" i5 p6 L
  73.         {1 k' E5 D* n+ h1 V% Z, k, `
  74.       /* 等待BANK1操作完成 */5 O0 e0 m4 _& `. c4 ]0 L
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);  v' c2 V" G( P. R6 r7 V

  76. 9 Q! O( y1 s& I% ]: M" A4 V
  77.       /* 如果擦除操作完成,禁止SER位 */
    6 ?1 b. {% ~7 F* u2 V/ w" x2 z
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
      p! W$ j3 ]/ s; @& c! c
  79.         }  f9 t$ h* D- x1 r
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2): L0 Y, C0 W0 D6 ?; x, ^- T$ P* r5 V
  81.         {
    : f: y* {1 w7 @& \! _8 F0 B5 t/ A: M
  82.       /* 等待BANK2操作完成 */# [# r* J+ A  ?1 a- P. ~5 @
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);
    - D9 l' z. U7 C8 s( g2 J
  84. 2 U1 k/ d, ~( I! I: G. L
  85.       /* 如果擦除操作完成,禁止SER位 */
    6 l3 Q) V' Q" w* A6 Z' k/ x+ |6 ^0 I
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));2 x- Z* v, B( G  j
  87.         }
    % c( r: [: M% f4 q
  88. 7 |, B; H) ~' y& z
  89.         if(status != HAL_OK)/ T/ Z+ u. o7 C' y
  90.         {
    9 Q% Z( Q* T% M0 j. y1 n. ~
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */
    + i. B% \  j- a% F- e% f
  92.           *SectorError = sector_index;
    . ^5 W/ ^1 K: e4 ~& q/ v3 B
  93.           break;- L6 {" _* p2 m  ]7 h
  94.         }
    ( s* f2 h$ \1 t- I
  95.       }- ]5 G% I; Z5 |  j, q* ^
  96.     }
    , B8 P, u5 `$ m& A9 r! @  r
  97.   }
    / Z5 Q1 f. Y7 c. K$ }6 Q

  98. 3 w" b% S1 Q1 F# G0 |+ o, u+ d/ a3 @' P
  99. /* 解锁 */
    # j% ^0 l# L2 J$ S! \0 e2 E  m% a
  100.   __HAL_UNLOCK(&pFlash);' v# U, }5 U2 F; ]' X2 R
  101. 0 I. Y5 X$ @) V2 v' x
  102.   return status;
    $ ]5 u+ }/ c( S0 x8 d
  103. }
    ' E, q% z. w2 r' x  z+ C$ n9 m
复制代码

* s9 `5 `$ ?: m函数描述:9 k# ~- H! V# T4 k
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。! H, r! }& S! B4 v
0 _5 l: v& U  K2 b, E( ^+ e
函数参数:5 \3 P2 J* J9 n+ }5 D. J# q
  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。
; G. `1 C% _" ]5 v( Y) @" O  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。
% T# O: q( F; i1 H, _! t  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。1 i0 s9 f" L6 Z2 i* k
6 X* }4 p) U9 B: w
70.5 总结
  s6 y1 E, B+ @" U3 [- q本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。
- J* I  j) p9 \  o
% Q. V7 S# G5 D1 E" X
% b6 u6 F; a% }5 o+ p
9 e* N, i6 r* R( a8 p) d5 B
收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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