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

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

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
6 j+ E- u9 U" n  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
: Y7 O) O) Y: Q/ _3 V  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。
5 v; \- `  K) B& e% V4 C  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。
6 f# N: `) M" ?& z  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。
% F* V. b& q# V70.2 内部Flash基础知识  L$ F: N# u8 T/ E: {9 e' x, q, G
70.2.1 内部Flash的硬件框图
* I, X, M! |* H5 d1 F% W
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。% D) b+ u3 H8 t; _8 \
0 Y! A! S: N5 I7 L
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

7 `$ ^% h1 ^0 A  x8 b: C
. ^) E" n, l3 ~& J+ z通过这个框图,我们可以得到如下信息:% j5 V+ y! h) y8 F+ K$ U
- L5 V+ A# }9 I0 p. U
  sys_ck时钟输入
  o6 Y5 @% j( A5 ~* v0 N: L2 u, fD1域总线时钟。/ P5 l& H" e; B/ N

- F1 y) C: I  O* O5 W  po_rst输入
0 [, s1 h% j8 v& |- W6 ]Power on reset 上电复位。
7 D2 g$ `+ Z/ K7 M$ ]3 w6 S0 o# U4 R6 W% B7 e; Y' |) R4 G* K/ ]
  d1_rst输入
; P3 B( s. M. ]1 {, J6 v5 o: F# Y( fD1域系统复位。
: O( Q6 ^4 G8 ]/ W8 s4 w; ?' A: s: E: G' g# H' C( I1 k' b& w( w
  flash_it输出( n  ]" o  w5 h  U
flash中断请求输出。8 J2 F- k3 s0 V% e5 P

. {) X1 B' E1 [/ K1 {- r; F  PSTM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。1 h5 p, o; Q0 i# G5 w
# u' J) q6 q( L6 E5 I6 O
70.2.2 内部Flash框架. n/ D8 g# V1 D' B" Z
关于内部Flash的框架,了解以下几个知识点即可:
# V  D( `8 d! w$ X* ~, n: s' W8 G( r" V3 F  f- J2 w% e( J0 x
  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。; c9 m' W8 J6 x. r* d% W
  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
5 v- Q' W4 s8 j& a7 _+ Z5 Z
) J1 e# ?; R6 g: }$ L) E
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
5 Q) S, w4 z& \6 ]( O

8 q6 G/ x8 n+ Z( E1 jBANK1的地址范围:0x0800 0000到0x080F FFFF。. F1 w" z: I( @, h9 H

& ~8 w4 I! r' @# J/ QBANK2的地址范围:0x0810 0000到0x081F FFFF。
. a1 W8 }# L3 ?- O" W  [7 P1 P' L9 T+ K. y0 W
70.2.3 内部Flash读操作
& b7 z0 x& J! q: |) E8 G1 H: pSTM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:
- U9 h/ X4 f7 |& B" r7 W& K. M
& U$ s& b$ Z% H% s
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
3 f. [, _; C* y7 G7 B0 H4 i

# I) f  C0 |% W7 N& K7 W  L' M对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
: S, p- p5 [% \6 d8 B- X- I; R$ M/ K+ o/ I4 P9 w; x5 G& t4 \8 i
了解了这个知识点后,再来看下面的时序,非常具有参考意义:
5 n3 L* p- e4 z( l4 H% Y8 p
+ r/ L! Y0 o- W9 G- D$ N注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。
+ X: f; }& p! t9 B9 c* W  S# s3 u3 l! S3 j' _
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

8 Q0 l( r9 D  s
' [5 B) Q0 Z3 K6 H% p关于这个时序要要认识到以下几点:
3 N1 ~# Y: f% w0 g1 e& ]6 f# [
  z. u' G: _6 D) L# t- Z2 w  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
* a% Y9 f9 A# ?( B6 L  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
4 P' w/ }" C" f' N' k7 y  如果不开Flash Cache的情况下,连续读可以提升性能。7 [5 P7 l4 W# F0 c9 k
/ O( p$ `9 ^% ~- r7 t
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
2 M( h: E2 H4 Z+ ?. ^& C
7 `& g$ S" M* u
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
; h/ }7 N7 P! L  w( N

) h# _, }+ j: a' ~' U70.2.4 内部Flash写入和擦除操作+ [/ _  I! I% Q/ R% x, v1 p
最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。( v7 I: n7 e8 J2 X3 `; r9 R$ o. H
, g, E( e6 s9 |) Y% B. E5 Q* O
这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:4 h( U9 e7 i" h  f8 m
: @: ~" }+ I) _" N- B, |
先保证这块扇区空间之前已经擦除过了。
" g' n; s, A$ A  }$ m解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。/ X1 J2 d0 d9 \0 b+ U; O
检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。! e# g  |5 C& I3 |7 t# n# O
, A, Z$ M4 y- g, l9 V  `/ a& _
Flash的擦除流程如下:, Q3 F, Y! q" w/ m) |$ k1 ?
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。! e+ D- l% f/ m0 l2 ?: D% ?# u
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER29 F/ P% p# U- J" ~5 v: m
如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。0 W% |& u  J# l+ F; F9 w6 W
0 S  X& ?7 n. C; M! ]' `
, E  u, `- d* T/ s6 Q. U
70.2.5 内部Flash读保护7 S3 V* W+ J+ F- C" g
内部Flash支持三级读保护RDP(read out protection)。
( N6 Q! `* r1 C3 k  }$ s, H+ Z2 y& @$ Q7 p! O: I2 D( m
  Level 0(无保护)
# W- Y6 y4 m0 |# m默认设置,所有读写和擦除操作都可以正常支持。) @9 w- t) Q- }" S
! @9 o" A! ]1 Z  e: U3 U& n' \
  Level 1 (Flash连接保护)( s. C: N; G5 G3 G+ K. r
  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
8 @2 i2 m) Y1 g% ?% H  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。
$ [/ p4 O- n! V, ?" r2 x  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。
5 w( Q% [: H0 }3 e2 S* z
4 Z( m# I/ ]9 l* ? Level 2(设备保护和自举保护)
- Y! Z4 T) W+ b" d. C- ~  N  所有调试特性被关闭。
8 N/ O: G3 G* g+ c! s, O  禁止从RAM启动。
, ^; h( j6 a, M; O' I" @( B" S5 P  除了选项字节里面的SWAP位可以配置,其它位都无法更改。7 H& F; s+ t$ j1 }+ \0 T# n
  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
: k  x, G' i% i: Q
0 V( a: S" L/ g7 O/ I, o! J特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。
7 }7 O! K7 m1 s* C6 Q9 J! f' A; c3 P) p9 t  u" J+ i* N3 o
如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:
) N: d% w. A, o  P$ l% }/ R: f7 X7 [
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
+ s) K  W5 {: |! u0 x* p0 s

/ j+ w% b- l8 \' ^3 q" n+ _5 w" k) n+ n( w( A: Y( m
70.2.6 内部Flash选项字节( V7 f* A! V- t" Y( M) A+ q
Flash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。* P5 N$ \& v+ M1 m

+ O; _' [1 W! }* F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

  h  f$ ^0 r  T7 p( C- g- Q/ T# Q" A( o) ~/ l( }& K! b
70.2.7 内部Flash的ECC校验+ P% i! ~7 Y2 K) Y
这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。
  l) L. e1 s2 M( s! V4 b+ D+ B& b1 y: J3 k. y1 \6 a3 r
对于STM32H7带的ECC校验,一般不需要用户去管理。. B* g2 U. m1 [: D9 }" T

5 i- _& M$ n: ^/ D( Z- f6 p70.3 内部Flash的HAL库用法8 P& C2 E$ `$ }$ r2 e
70.3.1 内部Flash结构体FLASH_TypeDef* o0 O9 B1 ]' ^3 |  q" h; _' i
内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
9 P. c( Z+ c6 A/ g
# ~9 G9 A" Y2 O+ S6 l9 G# r
  1. typedef struct
    2 `4 b) g. p+ W: o1 \4 S
  2. {
    6 \* ]& B0 U# u$ U7 ^! f
  3.   __IO uint32_t ACR;            6 M7 W7 e" G$ \. F
  4.   __IO uint32_t KEYR1;           ; ]/ ^$ w9 h* Q  ~+ L3 k  Y
  5.   __IO uint32_t OPTKEYR;         , u7 p4 z$ y+ [5 Q2 D
  6.   __IO uint32_t CR1;            * B8 B% L" x  _5 H7 u
  7.   __IO uint32_t SR1;             * x/ N8 b: _3 E2 a, `% U4 ~) z
  8.   __IO uint32_t CCR1;          ) F3 A, |, q8 R% j4 e9 y
  9.   __IO uint32_t OPTCR;           % v9 u$ B0 n" U2 r+ B
  10.   __IO uint32_t OPTSR_CUR;       % \/ n' s/ N" d1 o1 L! @4 V* r( [: c
  11.   __IO uint32_t OPTSR_PRG;      
    0 A! ]' J0 k8 T3 H
  12.   __IO uint32_t OPTCCR;         
    - N' u  K$ u5 ^, L! G5 B0 I
  13.   __IO uint32_t PRAR_CUR1;       ' B0 B$ @1 W$ t* V
  14.   __IO uint32_t PRAR_PRG1;       8 F* T+ ]5 g' N" L6 m4 V
  15.   __IO uint32_t SCAR_CUR1;      
    4 p' `! z% c' q! w% F% H7 Z
  16.   __IO uint32_t SCAR_PRG1;       ( c1 V4 q9 [$ I9 b- k9 }
  17.   __IO uint32_t WPSN_CUR1;      
    . s, {9 O5 W' h+ k- u/ b
  18.   __IO uint32_t WPSN_PRG1;         G9 z6 Z) J5 m" |: O* f" ~
  19.   __IO uint32_t BOOT_CUR;      
    - F& V/ q: e* y: r' G# y4 r* @
  20.   __IO uint32_t BOOT_PRG;       " @, }+ v* q. a/ g
  21.   uint32_t      RESERVED0[2];   
    # W) X$ d: S' W, C7 O
  22.   __IO uint32_t CRCCR1;         
    3 M; p& M, h1 h
  23.   __IO uint32_t CRCSADD1;      
    0 q& s  O; X2 s2 l) e* v
  24.   __IO uint32_t CRCEADD1;        
      b1 A1 J' U" k9 H1 n! E; x0 t
  25.   __IO uint32_t CRCDATA;         5 b. p" `2 E% a: U* c5 V
  26.   __IO uint32_t ECC_FA1;         3 p- E! t8 q. p' H3 n$ n
  27.   uint32_t      RESERVED1[40];  
    6 j) j9 H' z6 E. S# ~8 J
  28.   __IO uint32_t KEYR2;           
    % b# d* k/ q& Z* C' u3 |/ M
  29.   uint32_t      RESERVED2;      
    6 D8 K4 Y: P2 a9 u5 r$ A9 \
  30.   __IO uint32_t CR2;            
    8 N0 S; j  B4 T
  31.   __IO uint32_t SR2;             5 |% L3 k+ {# Y: d) j7 Q4 [4 Q; |
  32.   __IO uint32_t CCR2;            4 i" m, m! y* y% g) D
  33.   uint32_t      RESERVED3[4];   ) R( ^% Q7 H# c' K1 \/ i
  34.   __IO uint32_t PRAR_CUR2;      
    3 |9 j( e7 I  [3 n
  35.   __IO uint32_t PRAR_PRG2;      
    8 S' Z5 b: P( D
  36.   __IO uint32_t SCAR_CUR2;      
    ( N! R  ]& {( q3 V! V; m: _
  37.   __IO uint32_t SCAR_PRG2;      " N% `+ L5 }3 z
  38.   __IO uint32_t WPSN_CUR2;       . R1 {' j6 |; d$ P) `2 Y
  39.   __IO uint32_t WPSN_PRG2;      
    / @2 `  W2 s6 V7 m2 i& E6 i7 t" F
  40.   uint32_t      RESERVED4[4];   
    3 z9 k, A' u% [7 {
  41.   __IO uint32_t CRCCR2;         
    - e/ d1 j# [! A) M. s  v" B; y$ M
  42.   __IO uint32_t CRCSADD2;        
    ' X: p1 F+ w0 o0 F- I7 K
  43.   __IO uint32_t CRCEADD2;        ; s0 E& O6 \# B( Q7 N
  44.   __IO uint32_t CRCDATA2;        2 f$ u6 ?7 l2 Q" q3 M
  45.   __IO uint32_t ECC_FA2;         
    / Z# }5 L8 n, c
  46. } FLASH_TypeDef;
复制代码

% g4 R/ X( z/ W, W' n. P8 v7 D( {这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
+ G0 z# ]& G. i$ v, o, U
5 y& T& @8 i- u" K__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
* ^8 n9 A  G* \6 F9 t" M4 Y
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */1 A' W4 r$ L, I  B, p6 c
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
, W& b& V0 ]+ l% B
下面我们看下Flash的定义,在stm32h743xx.h文件。
# P7 C# i& f' J5 {# O; S. d. U6 i3 ~" z" y) I) D$ r
  1. #define PERIPH_BASE              (0x40000000UL)
    5 @' ?. k. e5 i9 p  l  {, M) q1 T
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL), R( `; r% C* Y2 }9 Y5 F* v
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)- G9 d9 B5 h5 S4 h8 O
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码
/ r5 P( N2 i) N( u1 f
我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。
  Z6 i. N4 S% u$ A; T1 I
. w  ^- v) \4 Z70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef$ N8 ~/ U1 ^: ]% Z" j
下面是做内部Flash擦除的结构体,用到的地方比较多:
6 ]6 g5 u  p& ~# k$ H/ O
8 w6 b" G6 b, p1 i1 h5 c; p
  1. typedef struct+ }+ {1 b! F, j) y
  2. {
      F( O; K. G9 p3 o! e& y- f8 [' W
  3.   uint32_t TypeErase;  
    7 u7 t6 v9 _; Z/ }2 i0 R& c: W
  4.   uint32_t Banks;       ) ~' Z# k/ k2 E$ a3 V
  5.   uint32_t Sector;      + S) d- t. j% f5 y) e
  6.   uint32_t NbSectors;   
    1 l6 e9 k, c) w7 b8 g
  7.   uint32_t VoltageRange;
    " j2 m% m' j4 K  b; a+ W4 s$ Q
  8. } FLASH_EraseInitTypeDef;
复制代码

0 ?. g7 u8 y  `% \下面将结构体成员逐一做个说明:
1 [& ]4 g; l5 I  TypeErase
' S7 I9 q% |6 ]
/ f) \8 N( e: ]* b3 [
. Q7 M) e3 z9 p( E用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:
  G1 h: E, q8 l$ A/ z
, x) e0 F8 t9 d6 `9 E
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */
    $ r* {' Z- o4 q
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码

5 C7 L# W9 N8 B1 y! b  ]  Banks/ @7 p, y0 E9 u( X
用于选择要擦除的BANK,或者两个BANK都选择:
3 J1 H$ }. n5 S( A
: V& p  M' S2 |' y/ z! z
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */1 S- @- b; v) H, O3 l
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */# r) u: G! q3 ?
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码

9 i- k6 P3 L6 N; ]. e7 Z! Q( X  Sector
. T" C/ D( X5 I% u+ q用于选择要擦除的扇区:
; E! U+ a" {* G( L5 V
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */
    ) `' ~5 o3 V0 n5 r
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */# n' o1 n( u/ z  Z: {/ P- {3 e- y
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */
    $ s" X3 m, S3 W! y5 `
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */
    - Z  d- v. E3 N  p* E/ i
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */4 c  a3 X9 t- w) e, H# q! _+ s
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */" q+ k4 m% D7 z& D( t
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    - P& S4 n" J, i! ~% i# f
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码
3 `3 ^' I! L, w, N
  NbSectors
+ R; q) D; x" u% Y+ w; T用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。' ^  |! Z2 q" \& S5 J( }& N$ f2 v

4 O) {7 }8 X) @6 a! j3 E  r  VoltageRange
1 R" }6 ^3 S* \. x$ g3 ^  {用于设置编程的并行位数,电压不同,位数不同:$ B4 F/ t0 ?7 [  j
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */! X* I: P/ l$ q) C( ^4 [6 G" E/ `
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */. R4 e- F/ [) I1 e! M  e
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */
    0 a5 U; w  x- F( F9 z! o+ J% S
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码

: ?2 A8 y- K  A/ D/ T7 A* Z* D, L0 Q6 g" J" ^# B0 ~' h: A
70.3.3 内部Flash的操作总结
  k$ \1 ]# w+ y; h; p/ t+ Z6 a) `- @/ B: C3 d4 h
7 L1 q. Y/ c+ X4 |
使用方法由HAL库提供:
0 C- m" A* z3 `; ^) o( P& L' u  Flash编程函数操作流程
/ J7 ~  O  ]# g+ O4 W  Flash解锁函数HAL_FLASH_Unlock。3 j1 M3 ?$ g5 w5 b" T
  Flash查询方式编程HAL_FLASH_Program。
: G1 _( L; \9 ?2 `; `  Flash中断方式编程HAL_FLASH_Program_IT。5 {0 E$ p  @, ?
  Flash上锁函数HAL_FLASH_Lock。
2 F# ~5 m( K) w1 t, w' D) p  * r# c8 f' @6 `- n/ \8 n6 q
选项字节编程流程, E- ?5 m  Z9 ~, R" H
  选项字节解锁函数HAL_FLASH_OB_Unlock。
, `. W1 i9 n  h4 d3 R  选项字节加载函数HAL_FLASH_OB_Launch。
9 O1 b/ ^6 N* @& O4 K9 S  选项字节编程函数HAL_FLASHEx_OBProgram。
1 D( M8 k0 Y& |$ o  选项字节加锁函数HAL_FLASH_OB_Lock。
* A% c3 M7 o2 f  d& e" Q) k- C' J! w7 | % i5 A; a1 z7 {' m% c
Flash擦除流程
8 s* |  z5 c2 d% w  Flash解锁函数HAL_FLASH_Unlock。
7 X* x( W! X8 o( v( Q! j! y  Flash查询方式擦除HAL_FLASHEx_Erase。1 V1 V4 X( b$ e3 G3 {
  Flash中断方式擦除HAL_FLASHEx_Erase_IT。; _8 {: ^  M" p7 s- K
  Flash上锁函数HAL_FLASH_Lock。* d: D! C$ _4 R7 ?7 u  Q. o1 _, s! R! }

: k" T$ `4 y! d# V9 J7 b6 |
+ J, {* r; t8 k3 Q) j$ E" o70.4 内部Flash源文件stm32h7xx_hal_flash.c5 \  t, C( `7 \
此文件涉及到的函数较多,这里把几个常用的函数做个说明:6 Q& N( H+ r& F* L0 n
' N! h7 q# A' V/ F% B9 t0 q
  HAL_FLASH_Unlock
' ~( [2 b1 W9 B1 e- @. u  HAL_FLASH_Lock
# v2 \! P$ H6 |  HAL_FLASHEx_Erase
- U* p+ X8 \; }( T" s  HAL_FLASH_Program; Q4 ]7 y2 ?7 F1 O9 w

( N% c5 \, W0 a! k8 p: L8 k: [70.4.1 函数HAL_FLASH_Lock" S. j" l2 Q: x; \( E3 `
函数原型:% z* Q: l9 W, m

2 s1 {2 J" m, [  q
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)& [# W6 @/ M4 o# `* }) q
  2. {7 M) f- s$ v3 h6 ~8 i: [
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */; x: P0 V2 ]( U; z1 X4 U! Q
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);: a6 ~( M, \, [: W4 i

  5. $ X; k' Q3 ^2 T) C  d
  6. /* 验证Flash Bank1是否已经被锁住 */0 w# w+ Y7 K% D
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)( s0 L+ b. I; }3 q
  8.   {) g  i0 v' n; d% l; @
  9.     return HAL_ERROR;
    5 w9 @: e& P1 G4 v$ c
  10.   }
    - S- s* |8 B' ?5 P/ D6 `1 w

  11. ' R5 `& @: B3 L5 Y! C
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    - Q) h9 M( M- z8 X* v- X1 L
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    * o  |- `' h" _4 G4 p

  14. & ]  Z" b  F/ c1 X7 L
  15. /* 验证Flash Bank2是否已经被锁住 */% `. D  a1 [" w4 r4 W
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)) b9 C5 \  i+ g
  17.   {
    ' S* t0 J% G7 K5 {8 g
  18.     return HAL_ERROR;; }( i. B5 u! f( b
  19.   }, g% C% R: P0 q( u6 p4 y, N
  20. # q4 J0 z& z  q
  21.   return HAL_OK;1 w( G4 w' B9 |
  22. }
复制代码

) f0 _$ P- ~4 s9 u5 q: u& a& e函数描述:
0 B" d: B) ?  o% r( a
* t/ J( i) }' d* [& t用于Flash加锁,加锁后将不能对Flash进行编程和擦除。6 `' g* k7 M7 _3 P5 T

' w! q1 r8 h  Y( B- a70.4.2 函数HAL_FLASH_Unlock+ j" L0 V- q9 K0 P+ m4 V
函数原型:
+ K; b/ r3 l0 X; L% w
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)
    / ?3 d2 c/ R! G# v/ O
  2. {
    % x3 G7 [- v0 y) Q2 X& \# e5 A
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)9 A& f" V  [" H- }! u
  4.   {
    ; O' a  T7 B$ L$ O4 B
  5.     /* 允许访问Flash Bank1 */
    , X4 a4 C$ x2 l. r
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);# Y# G* V; C+ A% ?* E6 f
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);
    & F( G* o: I7 k: d2 E* Q2 h& f
  8.   o' r6 v) z7 l# O( H, h% c
  9.     /* 验证是否已经解锁 */  t8 a) A, ?' x! x
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)' D5 y  }5 J' r( P! T1 W; _/ [& `; N7 C
  11.     {7 B7 [! T9 }9 D4 F1 w
  12.       return HAL_ERROR;8 C& N- j  s9 _7 ?
  13.     }: J  }- u% p$ V0 t5 h
  14.   }1 U, e2 L+ S/ {% b

  15. 1 R+ T4 P' ]* d) e0 |8 ]
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    4 b% Z6 m9 \# Y( ]; t, Q
  17.   {* \6 i, [. ?$ J( ]: v: X
  18.     /* 允许访问Flash Bank2 */
    $ L9 n2 T& t: ~% [
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);8 f3 x' h" A0 v% o. |
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
    . ~4 I7 f; {; D* i4 b. ~
  21. 1 z$ m1 i" H( P, s3 Y
  22.     /* 验证是否已经解锁 */
    5 a; q9 H' X) x, ~$ J: [
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)3 \( t5 e# g; q/ N+ e" n
  24.     {. K. Y* A1 U9 [
  25.       return HAL_ERROR;
    9 |) F6 Z. ~, Z3 ?" w
  26.     }2 }4 p9 I/ c; R- G+ K
  27.   }+ S$ T8 o7 R6 f6 e
  28. . r/ y7 U" R/ E. g
  29.   return HAL_OK;
    * \( {2 v- N9 a/ f5 Y8 M6 B3 d$ |, V+ `
  30. }
复制代码
5 {" x0 p  Z: f
函数描述:
9 D4 [1 R+ [( p: J' g* t1 [2 R
. M, x" @5 y  Q此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。5 F. _) O1 G: u* [7 {# S+ R

* O4 }, S% J7 ~, o, h$ V70.4.3 函数HAL_FLASH_Program
" o# T) x- w1 N& P6 }0 [函数原型:2 W& {: q! v' f" Z

/ X/ S: x: d! j
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
    * y* G7 ]# o% p# G) Z8 L8 o& b, k9 J
  2. {
    6 {7 T$ b6 S, G; F& a$ t
  3.   HAL_StatusTypeDef status;7 r! y! F3 T- l- `
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;7 ^) |3 j# n5 ^& s" ]. ]7 L3 M
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;
    ! J" m: D/ y  y
  6.   uint32_t bank;4 ~# s# Q2 T* K; I
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;% ~0 P, k- }0 z5 D2 |
  8. " x1 |! N! @  B* W* E
  9.   /* 检测参数 */; s' }6 @, n" K5 Q# `
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));1 L9 X. ]# c  q9 H$ N: M. J5 P9 |
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));
    + ~2 r; x4 ^" I( f& Z
  12. . z! g# T! ]4 S  a1 _& m5 F! ]- v# i
  13.   /* 上锁 */! X, E; B. ?7 U& ?7 F
  14.   __HAL_LOCK(&pFlash);7 Z1 }1 C0 P( N. \6 K9 s0 P4 T) x
  15. ( B/ A. I% ]2 b( k$ J/ v4 Z. D
  16. #if defined (FLASH_OPTCR_PG_OTP)! h! Y* W% a) O) u3 u$ |
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress))): j. L! v& ?0 J' c2 y4 a2 J: J
  18. #else
    5 c* y0 t0 ~2 z: x9 w& n
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))
    ) o9 u# U" E) v- H  F6 z# r+ f
  20. #endif ( B" H9 J4 A/ s. p
  21.   {
    ( T$ v2 s) Q9 d) M
  22.     bank = FLASH_BANK_1;
    ( ^& g8 B( g0 M$ o, t7 R
  23.   }
    ) k5 c' c7 S" {
  24.   else
    7 m' h; O" X0 l8 \* A
  25.   {& ]  B" s* N( d- h5 g
  26.     bank = FLASH_BANK_2;5 h# Q  a9 h/ R7 T* `$ E
  27.   }: |% A& i0 o& C# d

  28. + f( {% d; M: E' W
  29.   /* 错误标识,无错误 */4 d+ d, P. K7 n+ E4 E  A; K
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    * Z0 x. {, j: A1 @; V

  31. ) h) V" q: F* x
  32.   /* 等待操作完成 */
    + x* }' t0 e; m$ j* i# e
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);  V: ?4 X9 I! r9 S4 ^# ^$ d
  34. 8 P7 R0 b7 N) ]& [  c
  35.   if(status == HAL_OK)
    ! E$ Q8 {: U4 Q( ^! Z8 M
  36.   {* E- {: w3 d1 d- V% D# x6 n
  37.     if(bank == FLASH_BANK_1)# v$ }: ]4 u: J* K, D
  38.     {
    6 \# {7 [, f" M2 ?& d$ F1 R3 k5 }
  39. #if defined (FLASH_OPTCR_PG_OTP)# }, @1 z! u5 \2 @
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    ; f4 J, t' F! m/ P  P' m
  41.       {
    * F9 }. U8 L$ W: Q+ ~& {% S
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */0 Z* d4 t5 E! a+ R: m# k
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    2 h& M) g$ d+ W! Q5 f5 a: V; r
  44.       }
    5 g5 p+ Z( R6 m7 S6 k5 S9 u
  45.       else: i1 w. D3 q8 ^: r( r5 ?
  46. #endif
    ! b- {7 w6 x  l$ m5 R. O7 B& T+ ~- U
  47.       {
    8 j% s8 J0 O- k2 ^0 \6 b: j
  48.         /* 设置PG位,使能可编程 */
    / {. C# U' _) o$ s) m) d, q3 o8 |
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);- h7 X' i, `" R; Z/ k  q, K# k
  50.       }
    4 d* w( D8 R( [2 H* K" J
  51.     }
    4 B" N- l  v7 u* ]$ t* R: _
  52.     else! ?, }$ s2 m% h0 Y) U  C' p4 y! k  O
  53.     {
    # v/ k- r/ N6 b7 Y
  54.       /* 设置PG位 */
    ' ?0 I4 T6 R; J- m
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);9 Q( Y# d! o# ]1 e1 Q
  56.     }
    3 C" J5 h/ b( K( N- d5 D. `

  57. 9 h5 b2 f+ d1 \! o1 ~5 K6 R
  58.     __ISB();0 |) P. U* L# |4 X4 w
  59.     __DSB();
      y. ?/ w4 f6 f# B& p- l# Q1 X

  60. + ?( n7 o$ ?7 m, L, k
  61. #if defined (FLASH_OPTCR_PG_OTP)
    ! C$ t0 n4 p, x& q
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)% [6 J0 L/ l/ `# e6 b9 B
  63.     {
    , m  o: l. n! m3 A5 y" k1 d
  64.       /* 编程OTP(16 bits) */9 g/ S' W7 w. c" D
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;
    & @& W5 P5 l1 S0 x. i2 d) z- B
  66.     }- i/ @$ @9 X: {9 @, L
  67.     else
    1 d: }% O7 x# R* i' Q
  68. #endif " q: R$ I6 E6 W% f3 Q$ x8 Z4 U4 A
  69.     {
    ! c# F& t$ Y' C1 Z; o
  70.       /* 对Flash进行编程 */  x( O% u2 j# j5 W
  71.       do
    4 w3 W7 R( z8 S. V
  72.       {; Q8 f( H+ q6 P( z. |$ U
  73.         *dest_addr = *src_addr;- R  h2 z6 L4 y
  74.         dest_addr++;
    ( y( x: _4 ~1 u% ?* Y3 v
  75.         src_addr++;$ Z! S- U( g" B8 S6 o
  76.         row_index--;: ~* E" e- V# P% P& U
  77.      } while (row_index != 0U);) t9 k* N! \9 U1 u5 W5 q! n+ |
  78.     }
    ; g( F; @3 ~8 j. g6 |7 Y

  79. . Z- u3 P& g/ k% W% Q' u
  80.     __ISB();
    : M% b1 X; c( i4 Q* g1 e* f
  81.     __DSB();+ Z$ @9 @4 W* F7 O- u2 J" @
  82. ' Q7 E! ^1 N) `' V7 F( r. S
  83.     /* 等待最后一次操作完成 */5 `) L7 v0 l3 R& K3 e
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    : o$ n- N  d( [$ E% G: h4 E, e

  85. ! j7 j) F+ E& a! F: z9 `
  86. #if defined (FLASH_OPTCR_PG_OTP)' v1 w2 ]5 ~" M
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    5 b! ~8 _* K  ^) T, W2 N
  88.     {
    9 B3 r6 {- k9 i" C6 U9 s" I& z* G$ {
  89.       /* 如果编程操作完成,关闭OTP PG位 */+ P+ `3 E, K2 B6 E& _$ _" s4 v" m
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    0 r  G6 l7 W$ Q: k
  91.     }
    7 G3 m3 C0 t* h
  92.     else9 |& M% l2 w) k& y4 r- ~) B5 k
  93. #endif ( ~. p! ~& h3 B3 E! [3 O! |
  94.     {% i) |! q& I- v8 D
  95.       if(bank == FLASH_BANK_1)9 P$ H5 w" S# x6 X0 Y: l& B
  96.       {: o7 q- w2 ~! x7 d5 m! u0 m
  97.         /* 如果操作完成,关闭PG位 */
    ' I; C  N/ E! l; o( U! r& O
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);
    ) d* j' f, Q7 r6 `% X( P
  99.       }9 G( A. r! a, E
  100.       else
    5 n) s8 I. d; R6 m6 W/ c: G
  101.       {* z) r/ c& I$ s4 k8 C
  102.         /* 如果操作完成,关闭PG位 */
    ( |! F+ f, Y0 d! z9 Z/ F
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);4 v. y2 V" F% L/ j8 k/ i1 x
  104.       }% a4 ^; N3 c! o/ B
  105.     }
    ( B+ y3 ]1 s5 y; }" K
  106.   }. F7 }9 R5 s; k! H( f

  107. 8 k3 K) ?; ^0 Z# i1 v6 k
  108.   /* 解锁 */8 i! F* T( q' p3 X) c
  109.   __HAL_UNLOCK(&pFlash);9 A( L" Q9 o8 R8 Q  O7 x

  110. ) s1 o( N2 Z( [4 e
  111.   return status;) n  S: ~6 I- }9 ]; R
  112. }  J# s: K8 W2 ]5 X+ ^$ ~! K4 I
  113. 6 r1 [$ N& O. m8 ?' [
复制代码
: M, k1 J$ ~7 K8 \' D% A
函数描述:
$ ~+ E' R. k& |# |+ \) e此函数主要用于Flash编程,固定编程32个字节数据。: |& I# Z5 V7 B0 t5 p; e, Q

7 R1 O5 d7 [, Y! R8 u函数参数:
: w  E1 w! z, y  \: X第1个参数是要编程的Flash类型,支持两种参数:
1 {: B, U" f! ^7 x. y. K  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。& b8 @& w, }9 `3 p( F' P& F2 \
  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。8 P5 z% x, l0 D1 h1 w9 @( D* Y" P
6 s6 E: ]8 b3 D
第2个参数是要编程的Flash地址。
$ H" e) z) P9 G! w. z) L
1 e4 _  t9 n2 D9 C) w1 ~第3个参数是要编程到Flash的数据地址。 / N  N5 U: A' `, f2 |9 A% E
返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
" }4 P. j) ?3 W1 b. _$ D
3 v& k- E: O7 `
6 p7 Q& I6 O4 z) i; B" J注意事项:
5 |* s; ?6 s4 a3 _4 l  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
( G& z0 {3 q7 S* @$ e2 z+ Z  第3个参数务必要是32字节的整数倍。4 w8 |) q1 m! B( u4 L& T

( [; v: P& N. N70.4.4 函数HAL_FLASHEx_Erase5 _) B: P7 h9 x$ {, L9 [
函数原型:( X% ]# q2 J  D  W, O
2 v- E2 W) F* F3 q- F1 l
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)& F! z5 D1 J. g& V5 R; }
  2. {
    / p; ?; G" e: _1 S
  3.   HAL_StatusTypeDef status = HAL_OK;7 D8 t9 K; _3 b! Z5 ^% }
  4.   uint32_t sector_index;
    7 k6 A9 B4 E# z- N

  5. 0 h( J7 Q( P* |
  6. /* 检查参数 */
    , r$ K& r, S# J$ _$ ]$ K6 w8 M( t" H
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
    3 C* M; q1 Y+ S* B; d
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));
    0 `4 l" a  L! o+ }8 c3 Y
  9. ' w. V7 ^) {, k
  10. /* 上锁 */( m. T6 i& u* [7 I4 ~! H! J
  11.   __HAL_LOCK(&pFlash);. N, w! d7 ]% @  M! Q
  12. . C6 l: h, h7 ?, \+ f
  13. /* 无错误 */" t" |) j: w- w4 L
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    % Y' ]  w+ ]  t) m% e# p5 |

  15. 4 g% o, ]' y7 N1 K! @* f
  16. /* 等待BANK1的操作完成 */
    9 ~7 }6 e6 ?' A  \; Y
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    9 y2 A3 \% k, O
  18.   {) v! C/ s  p8 x, R) i6 z4 ]
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)2 O! \  _5 P2 Y2 M
  20.     {  R$ @9 F7 E, C0 M& G# k% l6 H
  21.       status = HAL_ERROR;! u# b; b( k3 \* _4 l9 Y9 Y. `2 z
  22.     }
    2 I9 S$ Q0 w' R% h5 m% ~. a7 K
  23.   }
    $ G2 d4 f8 x/ F2 {) W+ w0 a5 v

  24. # _, L: U1 P0 {! `: c: p
  25. /* 等待BANK2的操作完成 */- j7 o( V' m0 R$ i% V1 {
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)2 ^; e! s0 i$ y7 z7 ~
  27.   {
    $ t: U$ }' ]& W' a6 T
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    - }7 y6 K& K9 z
  29.     {4 `' r/ q% z* j
  30.       status = HAL_ERROR;+ e: i9 s$ f0 K- T6 k
  31.     }
    ' \% T1 l* l: c! ~# H( o
  32.   }  [9 e1 M; s" Z; y7 f& W

  33.   `9 d0 q/ B4 v
  34.   if(status == HAL_OK)4 Y+ l  v/ ^  Q' g( V0 [
  35.   {
    ( |4 A2 V+ ^$ K7 ]9 j
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE): N; l3 W9 a3 L2 z7 u( C9 n+ i' u
  37.     {/ Y6 \+ k; B4 [+ t& o
  38.   /* 整个BANK1或者BANK2擦除 */; o* C( }* \- e- P9 j/ U
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
    ; p: h* R3 {/ M1 c' g
  40. 2 E3 m9 x; `3 g/ `- d5 }
  41.   /* 等待操作完成 */
    0 Q1 B) B* Q: q9 o
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    ) a* }1 u7 ~, I' ^. D
  43.       {4 F' a# ?2 e4 ?* w
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)- _4 o; u# [% @
  45.         {) `& z- `8 k' E( r) y+ k7 g
  46.           status = HAL_ERROR;
    , T( E' [+ }1 c5 p6 N/ O' E
  47.         }
    # J' [# m9 X$ w/ k  q1 C6 N  K
  48.     /* 如果擦除完成,关闭BANK1的BER位 */
    . P' t' p# L2 ?5 ]7 u7 w
  49.         FLASH->CR1 &= (~FLASH_CR_BER);4 @+ h* J2 V: I# `/ M
  50.       }. W, S' c  k) E" S
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2); B; S% w" S  u% u! W; m& y& q
  52.       {
    ' k# a- h+ D* J! B  }
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    / b- n; n7 z, C! v! j
  54.         {
    5 X) d* U* f0 A1 n3 P! T+ y
  55.           status = HAL_ERROR;" H! a: j& Z, i- A
  56.         }% z5 ^7 G; q8 W3 i5 X
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */) S$ Y6 H' A& g- I7 o8 P
  58.         FLASH->CR2 &= (~FLASH_CR_BER);4 `4 k0 v- a0 \- k' k& r/ H7 ^
  59.       }
    + d% P$ y$ g. S( G  ]
  60.     }
    + J% c- |& N/ U! V+ M: F
  61.     else
    6 E! E1 K7 ~9 G- h; w4 w
  62.     {
    5 d7 J! F! W' E$ M4 i
  63.   /* 初始化扇区错误码 */3 E2 }, T) Z8 A3 W2 t0 |- m5 F
  64.       *SectorError = 0xFFFFFFFFU;6 |  I$ ~  t5 s  d: h' G

  65. 6 m0 @1 M& D3 x9 v, F
  66.   /* 扇区方式擦除 */- r: `9 K) ?7 d: [6 c' Y
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);: I( N0 z- p2 M/ ]
  68. sector_index++)' k& O1 x5 w% X/ R: h) `1 Q
  69.       {
    ; |; {* e. F, u+ B  b* w
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
    ; }) a8 Y; D/ t' ?1 |, s+ K

  71. " S7 _1 ^) T1 \( i
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)" v0 o: J: C4 p- r
  73.         {
    9 O+ V3 w* s  J! j
  74.       /* 等待BANK1操作完成 */
    ) c  u, n& Y2 r: ]
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);* b0 h  n9 b. ^$ R! \
  76. 7 _, D$ I4 w; d' Y" _
  77.       /* 如果擦除操作完成,禁止SER位 */& M2 C% ?) |  o% M
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    / r8 }4 ~/ w! M2 X" l6 @
  79.         }
    8 p' I4 y# I/ G2 ]) w
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)- W: v, v, p' H
  81.         {2 A! M( l5 d! l* W
  82.       /* 等待BANK2操作完成 */
    4 i/ ]' k5 }" R, }7 {2 L* C
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);
    # D6 q' k& ]( P1 J3 ~

  84. - j# N3 j4 D6 t; E, w
  85.       /* 如果擦除操作完成,禁止SER位 */7 D  Y6 ~/ N  H
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));+ }$ B8 K; A: F1 a; c- M
  87.         }5 b% w, A' h! ~3 s$ o& P  X

  88. & P; G  Q: H7 T9 F* t! N$ Q. ]* h6 m
  89.         if(status != HAL_OK)4 v3 C$ T9 s) _7 O: Y! F
  90.         {4 G- e: b  t4 ~, Y; ^+ D% M% y
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */3 f) z# G/ ^' {
  92.           *SectorError = sector_index;$ j; l1 v- c( B( l4 Q
  93.           break;! E% \, ?* @! U  \$ X8 l, X
  94.         }5 {" Z$ w8 Y, }; R: |3 Y) H$ T
  95.       }: v1 X! p, a6 u% X, O8 q
  96.     }
    $ [5 f& O! B5 u
  97.   }
    : S+ S, e6 O6 N1 w
  98. " n! i- D) b2 E( g; n
  99. /* 解锁 */
    5 B  @* @( @# F  g2 g4 r6 E3 f; r
  100.   __HAL_UNLOCK(&pFlash);1 O* j* f# u( y/ m- }7 y, D
  101. + X7 g8 ~" {# a
  102.   return status;5 S: E9 D3 e  T9 d+ h7 b
  103. }, _" w: m& ~: [$ J  a( g
复制代码

+ v1 ~* |+ a# E8 [  q5 h函数描述:2 h. h3 n6 b1 T' K" ^  E, y" q
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。
/ E/ o" W0 ]3 N2 J+ u: H
. [3 m% n! u5 X. O函数参数:
' f/ g8 t* C! D6 K% o* A; d# m  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。
. F3 K  M+ r9 o/ S  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。3 f% N; n; f' i. A, v( c
  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
5 k, k7 c4 r- X# a" A
* J% J! O  g% ]# W70.5 总结  ~2 _$ R! u" Q* x2 ?
本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。" Z4 A1 M( T1 t2 D8 a  H( c6 [
- p5 a, p  I8 O2 b+ _: p
8 a. E% {* G/ k1 X
" ?, d* ]5 x9 |- n
赞 收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版