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

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

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
6 C  |) B' K* Q' ]( ]6 y  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。/ t3 H$ J$ f# }1 [: V
  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。5 S: m! |0 [! J) `4 h
  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。
' z+ n% M2 j: K1 O  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。
2 x- ]8 v+ f8 y# d) j- s- {70.2 内部Flash基础知识5 D7 }& j5 w. G' z; N0 Q
70.2.1 内部Flash的硬件框图

$ ]+ k4 H* v+ l# p( y# V( Y认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。
. x! G, I" l( j' J1 Q, J% Z2 W) J& Z# k- D$ {4 |# ~
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

3 U/ y2 R5 L* a# K6 E3 w7 U+ f/ `0 ~5 }% v/ M0 y4 g
通过这个框图,我们可以得到如下信息:6 D2 v$ A$ K" @8 M- ^
+ P5 {' X2 y$ F" q1 B  s
  sys_ck时钟输入& I$ u: ~" S2 O$ O5 Q$ o) @7 l+ W" d
D1域总线时钟。
" H; M3 h. `4 f- z' Q9 p( b" ^* Y4 k% Z' R: r
  po_rst输入2 ]( S' d1 _5 T( M
Power on reset 上电复位。
1 q' t. M+ K9 N) W# L- \) j6 c5 I6 i7 d
  d1_rst输入
' b% U% j" @5 r5 }  d' BD1域系统复位。
! E5 G; g! [4 c! d% d1 I9 P9 W
  flash_it输出" H8 B" [1 {4 C4 `7 c3 @
flash中断请求输出。5 l1 c$ G1 ?4 M1 b! ?- S

% l7 G' \. L; Z/ ]7 {# dSTM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
" o* W5 r1 h& ^  M; m0 b/ D- t( i4 p4 e% Y  j
70.2.2 内部Flash框架/ @; Z7 \/ {& P5 |8 N  v8 O: ^0 `
关于内部Flash的框架,了解以下几个知识点即可:
6 u) D% s3 @5 V# f# }% {2 V1 u  r, d6 A1 }+ E- N7 C: B5 @6 L) Y
  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
: k5 l2 H1 b0 |5 F4 {' [  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
& S; n2 ]8 i3 h3 U5 [7 m0 G/ d3 f: P" Y, `1 u
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

- t3 x# C9 v- F* s, d( M9 D6 ]2 v3 f6 l/ N$ \. K& M
BANK1的地址范围:0x0800 0000到0x080F FFFF。" d, q/ j, r% ?0 E

: r2 \( N1 N# s9 T+ V  U: TBANK2的地址范围:0x0810 0000到0x081F FFFF。( {, C4 U) |0 O- N" \' [
  n$ o' `2 G# v9 S: w9 W. t8 e
70.2.3 内部Flash读操作( I# x' ]5 c8 `- `
STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:
( F7 w. X8 h% d- n' k/ d6 t$ d/ m, v+ g- ~& P. F, f% F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
, I% t  {: N6 \4 _

  A& r/ k$ C2 {, z对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。1 x  |/ `% f# P
! Z7 t) N1 b/ w8 p1 `
了解了这个知识点后,再来看下面的时序,非常具有参考意义:
6 F& E$ u& z% A, O7 a4 h* }* y* E, q* O5 Q
注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。' b/ w; T5 l2 q: M
3 B3 A7 N& F8 ~$ v8 t4 O. n
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

( T6 c6 r& U+ Q' X$ K0 B- c3 F' M1 w2 u1 w
关于这个时序要要认识到以下几点:
8 Z9 h8 ^( U$ r- e; c* n% W' Z* R) U; x' L- m# U% L
  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
' ^  r2 @+ D* ?2 {: \  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。* e8 Y- d" v+ V( ^4 P
  如果不开Flash Cache的情况下,连续读可以提升性能。  }, [& X  f7 a
" P) I$ E* ^4 Z, T  Q- t1 i
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
' D. q( |. \1 a0 r- f5 V0 ^6 v- \5 |: e! d8 R; l' d
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
: s8 I7 n  z$ r* p. U
0 i, I- L  f; \5 I: J  x0 N
70.2.4 内部Flash写入和擦除操作+ F0 v% v7 X3 h% J; H
最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。6 `* D  \7 K. C" P- O

7 p" H/ m2 y2 q. F$ _这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:/ O$ w6 c" r" ?. b1 W
" n0 p: f8 q% B- B
先保证这块扇区空间之前已经擦除过了。7 X) _3 N2 |& D# Y" ^
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
8 p& G2 y- D) l) X检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。
) o# A7 e/ |+ {$ G/ B( F2 E3 {/ e
Flash的擦除流程如下:
: I/ }( j( S* ]+ L解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。' j& o" D6 Z3 _4 ^& V* b9 U
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2
! C& b5 l, L0 [" G4 S. j+ \5 s7 G7 A如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。" E0 [3 N3 e" n/ f' k

: B4 f: K; w' u7 D- T
' k, n' S- C" p! l70.2.5 内部Flash读保护' I6 v+ U, k, [; c, @
内部Flash支持三级读保护RDP(read out protection)。
7 V) Y3 y: u  A% M6 O: T9 x
' ?2 D2 v+ a( H# W! [5 T# C# N  Level 0(无保护), ]+ g3 ~1 h- }0 q  N7 T9 ~! }! i
默认设置,所有读写和擦除操作都可以正常支持。7 V# \" R( [: j8 D7 T
- u  j3 k, B7 h+ ?' e6 Y, _1 m- U
  Level 1 (Flash连接保护)/ O6 A; n: Y* P6 c1 H7 u& ~
  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
; X$ h  m& T6 R; Y  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。
8 D! f/ c" V6 k  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。" v2 l, W$ t. c  C- \

* _1 Y0 b: Q% _* n Level 2(设备保护和自举保护), Z3 |- D% J: |9 s
  所有调试特性被关闭。
+ Z* p1 g! ]7 f  禁止从RAM启动。
" A+ h$ H: X2 R5 A: t* @, D3 k  除了选项字节里面的SWAP位可以配置,其它位都无法更改。' O5 s) ]0 G/ U6 @6 Z9 ?+ c5 o$ u
  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
( k2 C9 |6 E. S0 q
* }" Y6 Y" ?6 r9 }7 `5 [# o特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。# q1 s7 o; F* c4 B' \+ @* s6 A

8 |& G& n( E+ a9 ^+ [如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:
* q# M: U0 ~* m0 b9 V2 ~+ n  K/ z, q- J) q7 ]' y
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

6 s* J' r, K6 T2 \! Y6 D# ?) v
/ {* n3 m2 v3 K* j! i) @# F. C
70.2.6 内部Flash选项字节/ W! t* |8 @  T: q9 C* @
Flash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。- j4 B$ X/ I/ ]" _4 j6 s/ L
. N+ ]! z9 S# a7 A" e9 n
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

. }+ p2 S: H+ j9 G3 E, U' [' |. q9 A3 c& g8 D
70.2.7 内部Flash的ECC校验& I9 l- p) J' P4 ?. @2 I6 g! e8 \
这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。
; G1 y* Y& N: M, a" t  ]7 n/ A# X9 {9 `# t
对于STM32H7带的ECC校验,一般不需要用户去管理。9 f, x! g6 N! ~

( J8 N; ~* |3 M5 j1 w0 b) }" _+ b$ s6 \70.3 内部Flash的HAL库用法
2 U( Q5 O* i: y70.3.1 内部Flash结构体FLASH_TypeDef" U$ u3 J: E3 \
内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
' w/ ~8 y2 B; Z. D
. B- G1 i+ f0 c) l% H
  1. typedef struct& l4 `. R' ^6 ?( W4 P' D
  2. {
    1 K- r% ^# o8 A& l! G2 ~
  3.   __IO uint32_t ACR;            
    , E) M0 y6 _* h; u+ u, D$ }
  4.   __IO uint32_t KEYR1;           / [; G. P: N2 l7 B! X
  5.   __IO uint32_t OPTKEYR;         % o9 O9 x! ]+ ?+ z# i
  6.   __IO uint32_t CR1;            ) Q# Z, d$ I0 j! _/ ^6 c9 s& V
  7.   __IO uint32_t SR1;             4 a9 L1 Y5 }& C
  8.   __IO uint32_t CCR1;          * h9 `$ e; Z2 w- N0 j6 k) ]6 q
  9.   __IO uint32_t OPTCR;           * u2 U$ ?6 U7 ~4 Y. K# m
  10.   __IO uint32_t OPTSR_CUR;       ! q% r* {# Q7 N, p) F5 B' ]) V3 Z7 \7 Q
  11.   __IO uint32_t OPTSR_PRG;      
    # R) |2 D( I* F0 r1 h4 b$ z
  12.   __IO uint32_t OPTCCR;          2 [, F+ U* P( h
  13.   __IO uint32_t PRAR_CUR1;       0 B: _% H; J6 J& N5 h
  14.   __IO uint32_t PRAR_PRG1;      
    4 l7 y0 g+ P/ d- Y3 O
  15.   __IO uint32_t SCAR_CUR1;      
    $ L! e. n" \1 L
  16.   __IO uint32_t SCAR_PRG1;       3 ]" y, I! V  ]. \
  17.   __IO uint32_t WPSN_CUR1;       ) \4 }1 p) M: K1 F5 B
  18.   __IO uint32_t WPSN_PRG1;       ) _& A) F4 |7 w2 O* B: T; v% B
  19.   __IO uint32_t BOOT_CUR;       ( \4 u# c" [5 o8 i+ \' a' G0 R3 a
  20.   __IO uint32_t BOOT_PRG;      
    : u( R$ K; a; j2 k( o" t+ D4 [
  21.   uint32_t      RESERVED0[2];   
    0 p% }! O3 y7 ]9 A' G
  22.   __IO uint32_t CRCCR1;         
    : K" [+ ~( U* u3 M' Q2 U" Q
  23.   __IO uint32_t CRCSADD1;      
    8 @* ]2 R7 n" I* _) `: {% m* m
  24.   __IO uint32_t CRCEADD1;        
    # q- I. [  s$ c) _# r9 k; `- `5 S5 _
  25.   __IO uint32_t CRCDATA;         
    : B" R0 G, V" Z
  26.   __IO uint32_t ECC_FA1;         
    " P  S8 R- m0 N: L7 O" G
  27.   uint32_t      RESERVED1[40];  
    , W/ `6 ^$ \; C' r
  28.   __IO uint32_t KEYR2;           
    - p2 v, p; t3 J/ Y
  29.   uint32_t      RESERVED2;      
    2 w( ^7 X# v3 p: C
  30.   __IO uint32_t CR2;            
    6 A4 U( X  ]2 H( w! ~6 a' q, Q
  31.   __IO uint32_t SR2;             / e) y( }' M- N2 z
  32.   __IO uint32_t CCR2;            
      @# K5 O2 s; x* G5 f) |
  33.   uint32_t      RESERVED3[4];   
    6 K7 i$ q9 u) s7 f! ]: c& V0 s7 N
  34.   __IO uint32_t PRAR_CUR2;       , h8 l/ f6 [5 o& d" a& S7 w
  35.   __IO uint32_t PRAR_PRG2;       6 r7 \+ u8 C1 C# [
  36.   __IO uint32_t SCAR_CUR2;      
    7 G7 p( g' t! F5 j; g
  37.   __IO uint32_t SCAR_PRG2;      9 w) P# c7 A" z5 C2 a
  38.   __IO uint32_t WPSN_CUR2;       ) O& F, P+ I7 L
  39.   __IO uint32_t WPSN_PRG2;      
    2 M# C( m$ G/ h( d. x5 o$ v2 v
  40.   uint32_t      RESERVED4[4];   % c! t& f; X7 R. I% E
  41.   __IO uint32_t CRCCR2;          ' G0 p$ f' d* y/ |! D5 M7 W3 K8 M& V
  42.   __IO uint32_t CRCSADD2;        ' A: [* E  b8 Q3 m
  43.   __IO uint32_t CRCEADD2;        $ b7 B; U& [7 z0 }$ A8 z, x. l
  44.   __IO uint32_t CRCDATA2;        + W8 m. _) Z; d8 K
  45.   __IO uint32_t ECC_FA2;           I* N* H- n9 {  q8 C6 S
  46. } FLASH_TypeDef;
复制代码

* M9 m8 K* ?( i) r+ B: e这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
& A, H3 E$ _& Y/ }4 ?: a9 P1 [% H. V
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
; [# o. S( ~, M! X' f5 a+ j' `
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */0 I7 t: V& p) b) h/ k4 F# q( Y
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
5 z; R- r# }. [1 Q/ ?+ u
下面我们看下Flash的定义,在stm32h743xx.h文件。
; j7 _4 E8 ?; p% \' q! D) }3 Z% c$ E  Q/ ]; r8 g: `0 b
  1. #define PERIPH_BASE              (0x40000000UL) ) z! m; M, ^2 w* q0 G, g# K
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL)
    ( ]0 g5 [1 g9 y# t5 E: k
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)1 A) h( ^. Z& P" U0 O- T2 \- F
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码

0 O: E% `& m- }1 U9 x1 M, R我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。: A' a* E0 a$ d5 K
! m0 O, m; m( ~+ F: z  {
70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
1 A* K$ h  e7 [1 G下面是做内部Flash擦除的结构体,用到的地方比较多:, u$ F4 Y  O1 |8 \: e

! m& _" l' S3 [2 Z/ l
  1. typedef struct
    8 K" i9 i1 D* `4 H, Q! r! H( I$ [
  2. {
    3 y  K8 u$ Z# H: y# o* \
  3.   uint32_t TypeErase;  
    / A- [' ^8 c' C2 D
  4.   uint32_t Banks;      
    : y3 f. e  b, m8 e6 z2 @
  5.   uint32_t Sector;      # Y, W: \" W5 z- p9 k/ k" W! |
  6.   uint32_t NbSectors;   
    3 H4 P1 Z, g* ?- l
  7.   uint32_t VoltageRange;
    / T3 o; |8 R1 P! M) e( i: q( i
  8. } FLASH_EraseInitTypeDef;
复制代码
) \. _: i, T1 k  }
下面将结构体成员逐一做个说明:
& h# d2 f4 W4 H, }( z! D" l  TypeErase  ], n& a9 P# j! W

' G! ~; R  Q8 \% C
! Q) v; L  Y7 N  N' C用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:& D. V; H2 Z$ l- Q9 [2 w4 K! I% V: f
: L, N9 y' y' J4 b0 T# r
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */
    : P  ]1 z+ B+ s/ c% ?! ~
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码
9 \, R! ?7 O6 N' a- O5 ?5 Y3 d0 B
  Banks* v) E6 M9 ]2 `8 v" \3 i
用于选择要擦除的BANK,或者两个BANK都选择:
( R7 c$ P4 y: l2 ~/ Z8 Y
" t# s$ a$ D/ `$ j8 F- \, M
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */
    3 H" s3 \" D$ c, x3 B7 x( Z1 n  v% U
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */
    1 V& C% z, K1 q8 z, B
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码

' o  ?) _! G5 r; Q6 V  Sector
3 n" C( K* `  N# w用于选择要擦除的扇区:7 a9 L! G2 X; i  x* q
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */
    $ {0 x. F1 x4 G# U6 s3 t0 [
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */
    ' `; d" F8 h% V; }! F
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */
    1 l7 W* Y" u) T! H9 f9 y! A8 r
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */" n# D5 j% @8 A. J* k( [
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */
    ( q( s: c, O( _& T! e9 F2 Y
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */; f- U5 n/ ^( N+ `4 k' H3 n
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    # a& l# u- h. p! P$ A# B
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码
' j: j! z" X2 K
  NbSectors1 V6 K3 s5 j2 V
用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。- F6 _' d* h, i' Y/ d) u
3 k# ~( g" f/ m& f  H2 _3 @
  VoltageRange( h# i. K2 b1 K# P3 j+ q
用于设置编程的并行位数,电压不同,位数不同:
1 J6 a- g! L+ V8 Q8 }* m# y" Y
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */
    1 S* L& z  i1 @
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */
    8 [, e( |4 J" `3 I% d. P1 j, A
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */$ T, x. X6 l! K$ _6 v4 o1 Q- X
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码
) r5 D( \/ q' X) H

8 _7 n0 J/ [& f8 o) v70.3.3 内部Flash的操作总结
" E9 _4 M" ?% }& I9 M) ?2 O/ z( l: a# A  R1 `0 m1 i

" r! j; `0 P5 B" E8 A3 e! {8 R使用方法由HAL库提供:7 @9 L8 R4 @. L/ O9 c9 Q+ f( r  p  ]
  Flash编程函数操作流程0 \. V- G/ p+ J& N1 y1 m: K) m" W
  Flash解锁函数HAL_FLASH_Unlock。
4 e7 o( W" R! Y+ }7 L% @0 O3 K& B  Flash查询方式编程HAL_FLASH_Program。/ O& A2 ~0 t. m! ^+ B, o
  Flash中断方式编程HAL_FLASH_Program_IT。5 R0 r, |$ s: g, y, Z8 v, g
  Flash上锁函数HAL_FLASH_Lock。
$ l% _9 S4 s0 x& @6 L0 z+ f  
5 I! K# q6 `# V) u, H选项字节编程流程& w0 N$ U# R$ q& g2 e. t
  选项字节解锁函数HAL_FLASH_OB_Unlock。
. O: \/ \% A0 M6 V/ [  选项字节加载函数HAL_FLASH_OB_Launch。3 P0 b4 n1 U) q" j: E: {- }
  选项字节编程函数HAL_FLASHEx_OBProgram。
5 n( K$ l6 I: M( ?- u" U% ~  选项字节加锁函数HAL_FLASH_OB_Lock。
) m8 N& m' M  Q  g
  L7 R9 y- [+ g' y. b' S Flash擦除流程% \$ O  a* S$ v. v- ?" j
  Flash解锁函数HAL_FLASH_Unlock。
$ S* s+ U, x# O, j" c$ y  Flash查询方式擦除HAL_FLASHEx_Erase。
. p, e5 p5 T) G. N6 m- T$ L  Flash中断方式擦除HAL_FLASHEx_Erase_IT。2 r* a9 V$ h$ x+ ~7 |
  Flash上锁函数HAL_FLASH_Lock。
3 _$ O% Q8 g+ C* y. U. I& W, S, p' p+ n1 J4 \
- r) @' _, h# w& r
70.4 内部Flash源文件stm32h7xx_hal_flash.c3 z# ]% b7 u7 m4 K( P7 X
此文件涉及到的函数较多,这里把几个常用的函数做个说明:
$ d# o' P  w/ ?) e- B
; Y" \% [8 n: k  HAL_FLASH_Unlock
: |; ~% Y! Z% e  HAL_FLASH_Lock
1 P, J3 J& N3 T4 v% l  HAL_FLASHEx_Erase
, F2 Q% `: @0 E, Z  W  HAL_FLASH_Program9 T  W: K" V1 q: h2 G) R5 Q6 m+ C
: L4 S6 A  W' R
70.4.1 函数HAL_FLASH_Lock
' a6 }+ T+ ^. H4 B" I+ S函数原型:$ Q6 K4 c" w. F

( w* u, r9 k4 T4 O5 h7 E3 [. U
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)3 d1 k" Q, o& d; `, |
  2. {$ J, w+ r. y5 _# p0 l+ F7 m5 c
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */9 q% g- B5 b8 p2 T$ H
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);
    , V- a% N- {0 R  R5 ~
  5. $ b2 s5 a4 t4 }9 g% r, p5 d0 N% }
  6. /* 验证Flash Bank1是否已经被锁住 */3 p# ~2 m5 z" x: _4 M2 y+ O
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)
    4 s+ X4 K. U% h- N2 {
  8.   {
    ( }, d( Z( y2 Y+ `$ I: O) p- I" A
  9.     return HAL_ERROR;
    7 [2 `  r# `( y) {6 y4 [. r2 t$ B
  10.   }* Z' F5 j, h7 T/ O
  11. ' G8 k$ u& f5 M/ p
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    5 k, V* E9 P: q  y4 O/ C$ r% w( f7 E
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    ; ^2 a7 x; U1 t5 V0 x" a9 E
  14. + Q8 A* {  r( ^) S5 y) ~
  15. /* 验证Flash Bank2是否已经被锁住 */5 |1 t0 \7 C+ k6 Z  E
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)
    ( V0 b/ `# P+ J& e% w
  17.   {
    9 ~+ X, W  [+ x0 n( k
  18.     return HAL_ERROR;: V* I0 H( Z' k. M# Z$ r- e
  19.   }' C+ c3 q3 G5 i  V9 |
  20. / n& H5 M8 y: s# m' N
  21.   return HAL_OK;& g8 K* o( Q' [$ z  v5 @; I
  22. }
复制代码
7 C# v: S: M' a7 @4 |, a, A
函数描述:& ~! j- }  m5 z. c+ d- @1 }
: V( h) ~+ U$ C* Y3 G
用于Flash加锁,加锁后将不能对Flash进行编程和擦除。
" M9 k; R. u5 V0 J; K* q$ r! N& T; N
70.4.2 函数HAL_FLASH_Unlock  K8 p$ o! H* T' k* U7 u2 L$ i7 n
函数原型:! S& t4 C6 J3 x$ i* |& u5 `6 S
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)
    9 |" {& O8 F! Q$ n
  2. {; p2 J" C& i/ S4 `" H  Q
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)$ F6 w  W! |" {% n3 b/ o
  4.   {8 }+ g$ q9 w7 M6 P0 O! u/ j1 K9 g. }
  5.     /* 允许访问Flash Bank1 */2 O: T/ U; S' y4 @" ~0 |, V' w" F+ `
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);
    4 V$ ^' C2 o3 ]) h! n* }
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);6 P3 J% Q  T. U+ s3 z/ y, x

  8. ' z: S# h$ A) P" U; R8 p+ Q3 a
  9.     /* 验证是否已经解锁 */
      c/ E  A" h+ E% o; ]% m1 E
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)! D% D4 {3 C3 ?9 B2 L* N' k' d
  11.     {" m& r. d" n& w: t: p$ v  H) c
  12.       return HAL_ERROR;
    " ]) z1 w) S  @8 x  {- Y9 @
  13.     }9 u9 ^7 r. F; @0 K
  14.   }
    4 d2 ?- @' `+ U5 \2 J
  15. + `/ d* a* b8 i9 g  p$ }7 U
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    5 J* }1 d8 ?1 Z
  17.   {# j3 N, I! ]% ~8 _9 T
  18.     /* 允许访问Flash Bank2 */
    . i- [2 N7 ^' i# `. o2 a& [  c
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);: y' T' r' c6 Y
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);: I) c6 T4 r) J! A. C

  21. * A  n+ A7 l' E- {' u
  22.     /* 验证是否已经解锁 */: h. ~7 R, |7 U. h4 w  Z4 Y& b; ~
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)  L% f4 v8 f# q! \( t6 b3 M7 m
  24.     {7 c; W+ M" m9 I
  25.       return HAL_ERROR;# k/ |! R, u! Y5 ~
  26.     }
    1 a9 A: s% Y( i( m% A
  27.   }
    ) g. I6 R( B% L* C  W8 A

  28. ) F2 l8 B* }% k( I! i+ D7 H
  29.   return HAL_OK;
    0 a" \2 ?$ g7 r2 W$ j3 F
  30. }
复制代码

. `" h3 g6 ^/ Y: N函数描述:
2 P8 a# a! K4 a* q( K) u, V3 b5 [0 o6 f
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。
1 ]! x9 c  k& n
7 W2 _- @# G6 w6 c1 q70.4.3 函数HAL_FLASH_Program9 V9 e! v3 I& U, M
函数原型:
2 ^0 o1 S' \2 y- O  ~! {+ A
, P  |$ {# I: ~! A  Z9 y' x
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)* n/ k/ R/ n* d( x
  2. {
    - G+ D0 @6 Y4 _/ `
  3.   HAL_StatusTypeDef status;# N, e9 z  L% p$ l
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;
    3 r+ p% b; S2 x7 `8 h# L; q1 x
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;
    2 J# }/ C! x) P! _
  6.   uint32_t bank;: d& D6 Z! I* i7 A% c2 y
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;
    3 Z! x1 B' s; w
  8. 0 t2 }, x' O5 g$ \( Q
  9.   /* 检测参数 */2 V  E% F' X% u$ a0 U$ G
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
    - W8 ^. K' m+ R& ?7 c
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));
    / S% ]/ v" R" I/ t1 ]% w: a9 c2 F

  12. # L% G: \: U" o
  13.   /* 上锁 */
    $ d- p6 l' B0 k1 n6 t7 n
  14.   __HAL_LOCK(&pFlash);+ z, C. l5 F$ }6 f  ?0 w3 o
  15. 1 l/ C# _' W( |+ G" _% A
  16. #if defined (FLASH_OPTCR_PG_OTP), P' d! X5 F4 v4 ^9 Y0 l
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))
    0 b6 \0 C. q! }3 C
  18. #else
    2 I6 r% N" T2 _( j$ ?
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)). \# B6 s! j: s1 q/ m3 f5 Y
  20. #endif " J; H% D" H5 ^3 k, ]
  21.   {3 ~2 W; j7 z2 b- M8 K7 L
  22.     bank = FLASH_BANK_1;
    5 p( R+ x4 k  X0 ^0 f5 J& W- U
  23.   }
    $ c* w* _  M2 v; h# o9 ]8 q
  24.   else( S" Z. v3 B' e( d2 N! Q
  25.   {. V3 C. q* ~! u0 c
  26.     bank = FLASH_BANK_2;7 N# s, s: |8 h
  27.   }
    ) B+ W% `  L* c; X
  28. & m0 g  B! s4 E1 ?( c3 ]' p3 w0 B
  29.   /* 错误标识,无错误 */$ a' M2 [# u, b
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    / J) d/ x4 B2 v
  31. " \& f7 L  B( M- N7 N1 r4 S8 K
  32.   /* 等待操作完成 */. L$ A" m7 q6 m2 j$ ^
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);' S. P5 n' Z. U4 c$ V7 _
  34. " q% l  }! T/ L, `, ~. m3 }
  35.   if(status == HAL_OK)3 r( v0 Q' D( h, z4 ?( k
  36.   {
    : j! h* T, c4 p) @  W
  37.     if(bank == FLASH_BANK_1)7 Y& J3 a. q, G; p$ H
  38.     {
    8 C% `* y9 K1 ~9 S
  39. #if defined (FLASH_OPTCR_PG_OTP)
    5 R" {+ w) ]+ M9 x1 A& E" F
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)3 y8 b1 ]2 C' K; N( C5 k! L
  41.       {
    " @4 y7 d0 u$ D" @) e: @& |; k! C. a2 H
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */
    9 @6 ^# w! i& f* Q9 O4 C, X
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    ; o, K1 g9 \* ^3 W7 ]8 L7 q
  44.       }3 ?; R9 m! D4 ?2 Q# }# ]
  45.       else6 M# A3 C  p0 i. n) ^4 M" [
  46. #endif
      k% @; }' R; i5 X/ }
  47.       {' G: N9 ]2 e! R3 ^4 L
  48.         /* 设置PG位,使能可编程 */9 t4 H6 M5 t" E# x, C, y
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);
    1 L2 j" n$ C& e* S! X
  50.       }: j7 y$ @. x* A4 [% i+ G
  51.     }" f5 t8 m9 D- n8 T- I0 O
  52.     else$ O$ J  L; r# \5 D7 m5 r; K& F
  53.     {. E- i1 M$ _* U0 g' N
  54.       /* 设置PG位 */
    $ u  ~1 y8 U# R/ B9 m
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);
    . \6 q9 q/ k9 O0 O
  56.     }& x, F0 Z2 T+ @6 Y& R- v

  57. ; u( u. @7 {: v% i  P& H; X
  58.     __ISB();
    & t2 Q& E! i* f( x+ ~
  59.     __DSB();; G% M" ~7 c1 d- k9 a" t- ?
  60. 3 a4 y. g5 T+ m  E7 L/ s5 A
  61. #if defined (FLASH_OPTCR_PG_OTP)
    7 @) g. Z+ W' O, E/ Q9 E
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)( }/ V9 e# c4 l4 n# Y- i" c% \( n# y
  63.     {
    7 X2 }! Q& d+ @% J. m: a+ [9 Z" E
  64.       /* 编程OTP(16 bits) */
    5 D" {& a7 G, }
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;
    : g! f# d( c4 }
  66.     }" f6 h0 o8 G6 O# E5 A% Y7 ~
  67.     else) m! E, N% D- _4 `; ~
  68. #endif . ?% |/ \! W* d: |9 G: `# `; T
  69.     {
    3 I0 Z% W0 s9 s3 d
  70.       /* 对Flash进行编程 */
    , A: r, v: W  Z" `! g- m
  71.       do2 P+ q; n" W, e# O
  72.       {6 k0 i  |& @: `0 o5 c0 i
  73.         *dest_addr = *src_addr;
    " I2 W# n, a; n6 g; b. z
  74.         dest_addr++;' Q& e  S; D5 Y; u5 y& u  ]* R
  75.         src_addr++;
    0 o+ S: ]6 ?! _# v% Y* F
  76.         row_index--;+ o$ B: W; q; f- o, S0 P2 }
  77.      } while (row_index != 0U);1 h& B2 s- W" }) H
  78.     }
    % }: F8 w+ s* T$ p3 \2 M1 P
  79. # k% p2 a8 G# ?6 u0 P$ `- F4 V; O2 i
  80.     __ISB();# j3 `: ^2 ?* ?$ s7 L
  81.     __DSB();
      M" E$ @" C7 D
  82. ; L9 t# K0 w; k% i5 v8 w
  83.     /* 等待最后一次操作完成 */
    . y5 z) V8 w; I! q
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);% ?  ^+ Q9 y0 j' _* j- d7 G
  85. - w8 O1 V) t3 ^% V# f
  86. #if defined (FLASH_OPTCR_PG_OTP)
    4 ]: b2 T( e% `
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    " L% r4 y2 n5 P, p4 `1 m
  88.     {
    $ H" z8 i2 f( U9 L1 X3 M4 o/ p
  89.       /* 如果编程操作完成,关闭OTP PG位 */
    ) G! [1 \+ a7 p  T" Y# Z7 A
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);$ y; G5 T0 ?1 L+ R
  91.     }
    ; s/ V+ ]% L+ v4 w, ]
  92.     else' @( K0 r. J" I9 j5 ^; ^
  93. #endif
    ; @* P7 t9 g' o, q4 Q
  94.     {
    4 `# Q2 _8 t' r# K2 u$ W
  95.       if(bank == FLASH_BANK_1)( E2 S% W9 Z, T$ Z, }
  96.       {
      @" E6 f6 {6 F; \" l9 F( q7 W) X% F* Z
  97.         /* 如果操作完成,关闭PG位 */
    0 q) a9 f$ Y* n7 R% A6 f
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);' \* L- O  [+ ?5 m8 Z9 Z
  99.       }3 s7 v/ q/ b5 f4 I7 w: N) P1 W
  100.       else) N& h4 l" x0 v0 x3 R1 J
  101.       {
    ) S4 z$ j% B! y. L5 v
  102.         /* 如果操作完成,关闭PG位 */6 A9 h& X+ h' C% A( n
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);0 H5 x. ~3 C5 y7 j3 P% K
  104.       }
    ! r) q0 n+ z4 i2 Q! J4 _# N
  105.     }! i4 M* h' G' {% w/ c, Q8 y
  106.   }1 q+ Q( [1 B* t# C) ~, S

  107. & R2 V6 X3 t" J
  108.   /* 解锁 */
    & l' z; x+ I* U% U" M2 [, V* }
  109.   __HAL_UNLOCK(&pFlash);$ c9 t# A& P( {$ J

  110. 7 I! u  R- `6 ^' _& ], G0 l& W5 q
  111.   return status;
    1 D0 |" w3 r+ c3 E3 \( k9 W
  112. }* L2 J* h: q8 h' t
  113. 1 z" b& I% g) g( u  |7 ^
复制代码

, `6 Z6 v# K; {" N) m  e函数描述:
- P( W9 L' X; t" e1 }- u/ d+ m- l此函数主要用于Flash编程,固定编程32个字节数据。+ S6 Z8 e6 Y9 S2 S. N6 j
" ?. G5 X/ @2 Y" v
函数参数:
  t) W* ^. |/ H, a! X第1个参数是要编程的Flash类型,支持两种参数:- w* ^- H4 e% i; {
  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
# U* p. p  C  e  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。& C& C9 M4 K5 C, Y
2 Q+ O8 |" q2 p, b9 t" B/ U" z) {
第2个参数是要编程的Flash地址。
6 E7 y! m4 `( Z  ]
1 Q; h4 s' T* K5 O第3个参数是要编程到Flash的数据地址。
8 I2 [! G4 ~. Y! l0 k* E返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。; S+ F; d% m6 w. B# J5 R
6 c5 _+ `& o: I  L

+ g: ]* E& t. n注意事项:: W# c6 c/ h! M8 ^, E  `8 q
  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
2 J* b; H* G6 s  第3个参数务必要是32字节的整数倍。: o2 ]( J* j% U$ T# {3 t

2 z8 z5 E$ D/ Q2 ^8 t& [70.4.4 函数HAL_FLASHEx_Erase- f7 z* j# F8 u% T* l0 m* D4 e
函数原型:) R* ~0 T. S5 q  h
( N7 v* K5 e6 w% h; U+ X, {( \) ?8 i
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)
    3 Y5 F# u/ o$ m6 |/ g- `( |# B
  2. {
    ! P! I) ^% l: b% j, k$ @) ]
  3.   HAL_StatusTypeDef status = HAL_OK;
    ! T# K# n  S2 \4 v$ }
  4.   uint32_t sector_index;
    4 v5 {" {. l2 b% C% ?* p

  5. 5 B# R; F6 V% X) K
  6. /* 检查参数 */
    & N. T) |1 l, V, Z
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));6 x9 b0 Q4 i/ ]/ i  z6 i7 a
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));% Z* i# I! ~. \5 m
  9. : a) k: {1 p0 T# S
  10. /* 上锁 */. d* P# Q4 }/ e$ u+ ~7 I
  11.   __HAL_LOCK(&pFlash);
    , b% S+ c1 w2 |, h. j* b# Z

  12. + v2 E1 f8 m3 W+ E
  13. /* 无错误 */! ]' {  h8 I: M- O. I- W, i# V- e
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;8 h* y. f$ D/ k
  15. # [' e6 N+ J. H
  16. /* 等待BANK1的操作完成 */) M4 r5 s% {5 P/ m: R: a* A0 l0 l
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    ! v0 _/ K5 E0 J; M; b4 O7 S
  18.   {) ~. i% z3 W+ D. D- k6 }0 V
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)4 G& X: _1 N! s
  20.     {
    * |: Y1 F2 U5 _; E3 n
  21.       status = HAL_ERROR;  s& @% Z1 {# I- y
  22.     }
    ; F5 {0 j; `; [8 c* ^8 D4 G/ {
  23.   }2 a7 c+ S6 u  t0 r) h5 @
  24. 1 C$ C+ ^# m# B6 ?) b
  25. /* 等待BANK2的操作完成 */
    1 Q) Q% C  Y  J+ k6 c
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    0 x8 D/ }: N, k; f: u7 b
  27.   {" e  R  D% R$ ]- }$ U
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)' [8 h1 t; j! G+ v" h1 T
  29.     {
    * v' z' m7 w6 K
  30.       status = HAL_ERROR;/ E$ {- M0 R, Q$ P" B
  31.     }9 Y) H" u/ X, h
  32.   }
    % \+ N" D: y- C) z' M2 f
  33. 4 y4 G2 B! `/ w, j+ }  w
  34.   if(status == HAL_OK)% F& l; m5 U2 L5 A
  35.   {2 e/ y# N: D) s. g
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
    5 r) p% S4 @: a3 v
  37.     {
    2 V* j0 M$ F5 t- G' q7 ]
  38.   /* 整个BANK1或者BANK2擦除 */- t7 z, e3 ?. o; _& E7 T: J5 d2 N
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
    * Z9 d" F1 Z1 G2 o# d0 `! ?

  40. / R2 _- S1 K/ H* {% H
  41.   /* 等待操作完成 */
    # W4 E3 D2 _* ^* q! B# s
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)) j( o! y8 Z* T$ d$ l, X2 @
  43.       {( G0 |& v$ O5 z6 q2 ~
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)$ y  V; _4 ~2 b" {
  45.         {. S0 s  F! B, F, J  I
  46.           status = HAL_ERROR;0 [0 O5 g8 P( `8 J- C
  47.         }6 O" G- k5 |2 @' t- F; p
  48.     /* 如果擦除完成,关闭BANK1的BER位 */! S/ S: a: S7 _+ U( W
  49.         FLASH->CR1 &= (~FLASH_CR_BER);" p) ]: U0 d1 a8 z+ J
  50.       }* l9 A1 h9 ~/ x
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    - u7 b+ o1 N7 I) `6 W0 v% Z# G
  52.       {8 X2 R! ]" T6 Y* i: M3 B
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)0 u3 y5 m+ k- M) Z+ j5 [* ?* }
  54.         {. c* Q& q5 s+ V5 K2 E- N' ~" W, t" r
  55.           status = HAL_ERROR;6 o% |  u& i) n! L% P  |
  56.         }
    ! P- S1 u8 {) K' X* o) ~8 n+ H2 R
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */
    , m; }- Z( R2 @
  58.         FLASH->CR2 &= (~FLASH_CR_BER);
    $ j. n" J1 D" |$ I6 z/ t/ ^
  59.       }+ Y$ H# @# _/ C2 H- `$ z6 O
  60.     }* ^6 U% F/ b; n; l4 Y
  61.     else3 E5 w, v& S( M; j/ J  V8 V
  62.     {
    $ ?1 ?8 g( S- B0 J- m" H" a
  63.   /* 初始化扇区错误码 */) k2 o* r  a) c6 g) `* d& q5 E
  64.       *SectorError = 0xFFFFFFFFU;
    9 ?4 k2 @8 V8 v* k
  65.   N# C. C) Q# z8 A  h: F; Z# R
  66.   /* 扇区方式擦除 */' n5 M9 k+ b8 X' K
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);
    + Y9 }' I. F/ p' z. _+ F7 ~4 x
  68. sector_index++)7 \* z$ P: o1 ?2 {
  69.       {
    : T1 l8 ?5 W( U* y
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);2 z. H3 c0 J& Z* @& G

  71. 2 t2 z" }7 W8 c5 L0 X4 o) n
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1); j- N9 S8 H" s- @: ]# a% z
  73.         {: z" P( F9 \  D: F; `4 C
  74.       /* 等待BANK1操作完成 */6 ?* }/ W8 t$ t0 f  _
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);
    9 r9 M# h  _9 l( C5 v9 V2 A8 b( n

  76. 0 x# [5 A% |. I- z4 |
  77.       /* 如果擦除操作完成,禁止SER位 */
    4 [, j$ R% i& G3 [  ^4 u5 U
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
      Y+ P, J' o1 g$ X0 s# m# {
  79.         }9 v: t2 X0 Z. b2 [* L
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)0 B1 A2 R# T) e, h
  81.         {
    * N/ b# `* Z' o+ P2 V" w# q
  82.       /* 等待BANK2操作完成 */
    1 X. [- a+ B. s+ B0 `0 F2 E
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);
    ( v# v( Q$ Q) s2 h6 X6 Y9 B
  84. 1 V! ]0 j7 R! l
  85.       /* 如果擦除操作完成,禁止SER位 */: m7 k* s# ^, [* o& k! p
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    4 V6 h  a7 u3 d# [0 h
  87.         }
    4 Y. c# Q3 _% ?& q; s7 k& G

  88. 5 H4 v' x+ B0 w2 y
  89.         if(status != HAL_OK)
      l* M6 g! L  o, @
  90.         {
    " J  |, Z8 u6 Q" Y- s8 z; y
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */6 ]9 z0 V$ R# A* S# E' [! G
  92.           *SectorError = sector_index;3 b8 m) R' b0 w+ v8 I
  93.           break;
      m0 \- h6 ?! }/ s  x
  94.         }
    . [- F% W4 `2 K. _$ v9 Y; A
  95.       }6 O) ^& n' `3 }- L
  96.     }
    ( r: @% a  c! D! N  ]) d8 d
  97.   }# g. z/ l& W9 r4 \

  98.   S2 G" T7 Z" i  J- g: o# `
  99. /* 解锁 */
    3 N' g3 t; r* R
  100.   __HAL_UNLOCK(&pFlash);9 e$ j! h$ U4 `; O1 q
  101. 7 X& S+ ]1 e% h9 V+ Y/ {- d" R
  102.   return status;9 @3 o/ o0 u7 P" W# g" ]
  103. }
    ( G- [# l. P( {1 U9 m
复制代码

7 `& }2 q# |. f" h! y! P; f函数描述:/ c# [1 M8 q. r" r
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。6 Q7 n7 w+ T+ X
: e  u* D: S  S8 |( C9 Y
函数参数:
. @) s* ~" |; H* }  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。2 t; d) Y; z( Q1 v3 _/ k+ v5 }
  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。, s. R; U3 b2 s# }% p9 C
  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。+ c) E; w9 J3 y3 b; T) |, L7 n
" k& c! V0 N& A8 t
70.5 总结
6 c, r5 U$ u/ E2 H本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。0 |4 q, m3 g# Y% d" g9 x0 `

  V$ a& L' \% F7 B( t. @  Z: x# R3 `5 x: r- T
, h* x! i9 l! A1 k1 i2 m; B2 c
收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版