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

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

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
4 Y* H4 o6 q, J$ m, ?  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
, n/ l( d$ S& t  \) \3 c  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。0 a' v# c2 ?! ]$ R
  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。
2 k/ S8 x* u! v4 b  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。2 i7 u/ ]: u# F# K/ E
70.2 内部Flash基础知识
& g! k9 e$ T6 y( _$ x1 m70.2.1 内部Flash的硬件框图
0 k5 M  i2 y! D, \' `# T; y
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。- J) N) b" D$ |  V/ C3 {

  {4 r& [; q0 w2 w8 r
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
4 B& Y1 S% B( I; J
/ ~& Q3 ^; _) K" _5 Q7 Y, X
通过这个框图,我们可以得到如下信息:( I% I- @$ {3 l

( R; L: z- Z8 N/ W- n* V# r0 U% v  sys_ck时钟输入
1 X, }4 Y" G- sD1域总线时钟。
3 V  o* S, _5 L* t* s5 L' B( [3 q( z' D7 B0 I% g& m1 I% n
  po_rst输入' }" c# n1 o& ^2 ^
Power on reset 上电复位。
- _  x" l& v+ l( ?; \8 ~* ^
6 k; q) K$ _) A* g  d1_rst输入
5 h: v6 C3 E# k! bD1域系统复位。" L% _/ R1 ^" ^+ a3 G

) H* P/ Y8 W0 F; T5 l1 |% J, j  flash_it输出
- v) X. [$ i: v" `" oflash中断请求输出。0 i& u2 U5 f# [+ l3 {! F
% ?3 J: x( T9 j0 b' D0 Z
STM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
+ h# z) g% O+ {0 q5 H7 Z5 t6 @8 _+ e3 ?- u6 M- r# }+ x7 C! K0 j
70.2.2 内部Flash框架( Z  g+ R7 H# R4 p( t- R4 |/ s' L
关于内部Flash的框架,了解以下几个知识点即可:6 |4 u. Q5 x. C

# I. U  |, Y! B' P: Z1 `  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
8 J: z2 a/ z; i, E  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。/ ], W/ p' y- I4 H) P
' K5 u5 O. t! I& R
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

5 G) T+ B4 ?% @
9 q3 A' M% a4 |, [# b* ]BANK1的地址范围:0x0800 0000到0x080F FFFF。
" S/ w0 L7 |0 J: T- |" f4 C
# N9 z7 p0 I" h- R3 hBANK2的地址范围:0x0810 0000到0x081F FFFF。
6 H' k$ W, p7 e4 T( _* c/ R, \  \
70.2.3 内部Flash读操作
! r/ G; F7 a' C4 g# ]* |STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:! ?  j( u2 ^1 E) I$ r8 `! G

* K) D& j& r9 x/ Z- b
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

6 Z, K8 [9 b. q6 E1 o
$ s1 u$ u3 E& K4 @对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
8 [# s+ ?  Z  a4 ]: _  Q
& x' b9 m) i# f% ^9 `' x了解了这个知识点后,再来看下面的时序,非常具有参考意义:
# _( _! y6 n5 V& l- s7 B7 ~8 o. b" r1 A( m! n$ ?* t
注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。
% I! ~* `. d7 F" y
' t. w0 p+ Q% P& M0 j( Y; G# g8 G
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

7 v1 O4 a* M4 C! }, I5 l/ J- }- m- b% G- `0 W4 Q: V& |
关于这个时序要要认识到以下几点:3 Z) P" x2 |; S, \4 m- m. m8 o! w
8 J7 L% }2 {6 h. o4 K
  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
2 E" g5 f1 t: a6 T  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
/ }# l' B$ |0 i: g" `4 r  如果不开Flash Cache的情况下,连续读可以提升性能。
; @# C! C! w7 p, ~
  X+ A7 B2 s3 \; x# s/ d下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
+ c0 O- n/ m! f' W6 w: C9 U1 G9 E
! H+ [$ ?5 _7 E
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

. Y$ Z" r2 T# w# |. g3 p- Y
. u/ m6 U* {5 T+ ], M7 c70.2.4 内部Flash写入和擦除操作
- M$ W. s3 g3 [5 O1 U0 j最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。
1 H% j7 a7 y' x& H4 B! _) B: w
8 l9 S& M1 H4 q) K5 i这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:* Y& V' e. i% n. D* V* n

! J4 G9 r1 P- s4 F( C9 A0 {' F先保证这块扇区空间之前已经擦除过了。0 F1 h+ Q' f+ h; ^
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
; y  ~+ E' {: y  d检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。+ l  `( L/ o/ g1 K: W4 a
3 b. C; h& t# o6 f* z3 u
Flash的擦除流程如下:5 ?0 {7 o, ]2 A, v: x' d4 B
解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
0 P  W2 m* X7 v6 U& `如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2
0 t' A# Z, @. Y' b6 M如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。
# _: G1 u* X2 c$ |; F6 e) e2 E0 @% r" n5 }9 E. B) O3 r

" N3 [- q1 t0 _* B* a70.2.5 内部Flash读保护
& v  w. K& @6 X7 q内部Flash支持三级读保护RDP(read out protection)。
6 O3 Z! e2 D. k& }3 i+ s3 g
2 P6 }5 |+ D6 R6 t  Level 0(无保护)8 e2 q, r; ~  |8 @& a
默认设置,所有读写和擦除操作都可以正常支持。  o8 l0 D7 c* V6 p, h2 u# \. `
( U* q4 X) O) e' y! [* R3 t
  Level 1 (Flash连接保护)
) z  m- j; i' v  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
$ C* H5 q9 \% e! k2 X, p2 i  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。
' L) r) R" f6 W2 L3 g  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。
! J# J. w, e0 w: R+ w
2 _  f% h0 b: G$ i2 w" p9 W Level 2(设备保护和自举保护)$ i8 n* P# ~* K1 g4 T- v& m5 e/ L
  所有调试特性被关闭。
, g9 t' `3 }7 `2 x5 o: B6 B% W( S  禁止从RAM启动。
; Z  w  M* p) G7 I! }0 U8 @  除了选项字节里面的SWAP位可以配置,其它位都无法更改。
9 |. Y* b1 Q. b% x; P  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。
# w  {$ n, X4 n+ A9 N/ X
+ q4 w: M$ M5 m. p# P7 M3 i: i% u: U特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。5 F/ c. J/ S: R/ |& Z* |

, H8 m% z) X5 x$ \如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:' @0 ^2 R& A, p. P* n
1 i6 B- {' ~& Y: M9 R; q
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

! |% [5 z$ R! M
. \; O6 K$ h" {) n6 t4 I
0 q3 T* `9 `8 i70.2.6 内部Flash选项字节
( G" U: f$ S6 E# L5 g- k: [0 FFlash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。
* w: X/ O+ _9 r
; r% Y# z1 [# [! _
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

# ]( \" S8 I2 r6 @: H" [/ S, ]( ^. C) _7 v8 M" E' o
70.2.7 内部Flash的ECC校验  B# L4 r3 l! h* n
这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。2 T6 N) X% b8 M' P2 f1 ?2 j6 K% `

2 w; x$ h4 K# o. m+ ]对于STM32H7带的ECC校验,一般不需要用户去管理。6 `3 t9 z8 F7 u

+ C1 f7 [1 X8 o70.3 内部Flash的HAL库用法  c3 @: K0 }9 J3 F. P1 O
70.3.1 内部Flash结构体FLASH_TypeDef
, R& k% D4 a0 J. `/ j内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
) C7 L9 p8 A8 {' W
. k2 V4 c. X" M" c) }3 w
  1. typedef struct
    & X/ n+ F* o8 g8 G  S2 `4 g
  2. {
    ; w( h  [& o5 M& G& q: k
  3.   __IO uint32_t ACR;            ; L( o7 y  j5 e
  4.   __IO uint32_t KEYR1;           " x6 V9 X$ l' y
  5.   __IO uint32_t OPTKEYR;         / @$ i9 m$ k. R1 a: g, |
  6.   __IO uint32_t CR1;            
    # {8 w( {8 z$ a
  7.   __IO uint32_t SR1;             - X6 R8 A6 Q1 x/ X' Q
  8.   __IO uint32_t CCR1;         
    9 p) e  O* |( b9 d
  9.   __IO uint32_t OPTCR;           ( L+ g. D: Z( g
  10.   __IO uint32_t OPTSR_CUR;       9 `* s- V( O3 T( R- Z7 I
  11.   __IO uint32_t OPTSR_PRG;      
    6 x8 W. @  e* S$ D8 j1 o
  12.   __IO uint32_t OPTCCR;          : a3 H- x9 G2 ^2 f9 c
  13.   __IO uint32_t PRAR_CUR1;      
    / X. W0 e# x! I) P
  14.   __IO uint32_t PRAR_PRG1;       % {) W4 u- |. E! s! I! @/ Q. ]
  15.   __IO uint32_t SCAR_CUR1;       / P$ {' c5 y* |+ g) ^
  16.   __IO uint32_t SCAR_PRG1;       2 D4 {, N) _" A+ `( C6 ^
  17.   __IO uint32_t WPSN_CUR1;      
    " T4 e0 n% N2 t
  18.   __IO uint32_t WPSN_PRG1;      
    4 y+ e) W) X% C" h
  19.   __IO uint32_t BOOT_CUR;      
    2 W3 U% N, M6 C# y2 d: _
  20.   __IO uint32_t BOOT_PRG;       / l, s4 n# L4 I- l0 c2 d
  21.   uint32_t      RESERVED0[2];   
    1 U2 H$ p9 m. a1 C0 o: e" e/ ]: y
  22.   __IO uint32_t CRCCR1;         
    ! D# p! D! k' z: d9 h! S
  23.   __IO uint32_t CRCSADD1;       " w' X8 \+ p2 o+ G
  24.   __IO uint32_t CRCEADD1;        " h1 {# W$ t* S- L
  25.   __IO uint32_t CRCDATA;         
    4 r3 b  J% z) G. B; K. {- f
  26.   __IO uint32_t ECC_FA1;         
    4 I9 z# n: z  C$ U+ I& o6 p5 d
  27.   uint32_t      RESERVED1[40];  ' X- Y7 D, ~8 A2 K
  28.   __IO uint32_t KEYR2;           
    ; Z0 R4 g* I  r
  29.   uint32_t      RESERVED2;      , @. U9 U' B; ~- n+ f; v
  30.   __IO uint32_t CR2;            
    + {! q1 C% f- E' r1 s: [
  31.   __IO uint32_t SR2;            
    + d/ `# Y& [5 ~: k1 _5 c- X0 |
  32.   __IO uint32_t CCR2;            % X1 ~/ S% @* c7 L5 M, c: \
  33.   uint32_t      RESERVED3[4];   : u; m. M! ^. Y2 `8 k/ a
  34.   __IO uint32_t PRAR_CUR2;      
    3 {$ L/ ]$ w9 y
  35.   __IO uint32_t PRAR_PRG2;       , F( N4 q5 N2 Y: s% b$ ]
  36.   __IO uint32_t SCAR_CUR2;      
    2 ~2 G9 ~& A$ _" X+ @
  37.   __IO uint32_t SCAR_PRG2;      
    3 A8 p9 _5 Z, r$ z' @7 q
  38.   __IO uint32_t WPSN_CUR2;       5 Z# U4 o6 ~( T# Q0 [% j
  39.   __IO uint32_t WPSN_PRG2;      
    ( B5 s! d; q; ]
  40.   uint32_t      RESERVED4[4];   - B7 j" J( w9 d- E% I+ m& |
  41.   __IO uint32_t CRCCR2;         
    & m  C" t! @( T" N* t
  42.   __IO uint32_t CRCSADD2;        
    / F1 G9 s; d6 _$ D5 i; a6 y
  43.   __IO uint32_t CRCEADD2;        
    * x" f4 u7 d7 M0 v8 s# M" j
  44.   __IO uint32_t CRCDATA2;        % @! S. [8 v8 l7 _
  45.   __IO uint32_t ECC_FA2;         
    : B' Z$ ?0 ^6 U+ j' Q4 V+ Q
  46. } FLASH_TypeDef;
复制代码

# X$ B. M) ~0 K' q. x% G这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。' q( |6 w2 l7 k; x" ?! p' g$ k* M
& e# X- R8 v+ w, s  E0 T/ a6 w
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
' P" I- O- \- `- o2 O  j7 Y$ u! A( }  E
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */+ y( o2 h( Z5 p, I% A- F
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
8 r9 }: i, h3 Z) }( b+ ~
下面我们看下Flash的定义,在stm32h743xx.h文件。. w4 y* _0 I; G7 G

0 @: ]: m4 l' M4 q4 a; J. e
  1. #define PERIPH_BASE              (0x40000000UL)
    0 ~0 f. D: c/ {2 o
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL)
    4 Y! o8 Q& k$ G. ^5 r- u
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)
    # d2 W  q; z6 C# g9 u5 g$ b
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码

8 f  y9 G; K8 i- v我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。1 c( n# ^7 p$ N7 _0 h
2 |5 T5 E+ P' v: o1 b& {7 n3 ?' i
70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
4 q* K+ C& N. S3 g/ A下面是做内部Flash擦除的结构体,用到的地方比较多:
: v' Y8 Q  R9 W7 ]& F4 r! {0 p1 t2 b' s
  1. typedef struct% G- h8 P/ [7 V: p- ?  \8 ?
  2. {
    % V+ F$ y/ K. l2 c5 J
  3.   uint32_t TypeErase;  
    ! O% P! u. G: J. g
  4.   uint32_t Banks;       1 `6 t: _3 ]# k4 _9 T
  5.   uint32_t Sector;      ; n/ U/ d' q; R; Z8 X: T: F
  6.   uint32_t NbSectors;   
    . k1 b. q8 H: c' m, z+ ?9 R
  7.   uint32_t VoltageRange; 5 X2 I4 g# \1 ?; S6 n, E
  8. } FLASH_EraseInitTypeDef;
复制代码

- W7 s4 q# y0 W$ v) s4 ?- f; ]; M下面将结构体成员逐一做个说明:
4 k  M0 u, ^6 P+ [; k6 c3 |  TypeErase3 @( i  J6 u2 R5 H$ V7 m- @
! Z2 }& Z& z8 a0 i

' d5 o- L( _5 h; \$ H1 M用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:
' u! J! g/ ^' }5 R* D
) P, E% U2 F  b8 |
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */* ^' n  q% k) ?" E1 p; r+ Z1 }
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码
$ `# X3 G$ n/ e/ z# ?* g
  Banks: n2 {+ {, F$ L: h' s2 \, x
用于选择要擦除的BANK,或者两个BANK都选择:
6 J* @) j1 ^# R% c. g; n; D5 s) @
5 H0 ~* b1 Y" U
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */$ h- @  I6 f# d& R$ a) n$ W/ ?
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */
    " f* \( l' r( w5 \
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码
8 f8 ]5 Y" v: j4 \. a/ l' W
  Sector
' z* q) I5 |* h- o用于选择要擦除的扇区:& B' M( G% h  j9 R) p* E
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */
    / V' J! _1 v' Q+ C  {
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   *// h) Q/ S; M, Q+ u( p
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */6 X4 I, z$ |# ?) y  n4 I* ?! V% y
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */( `6 T$ I# V- ^& ^- N' A
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */
    : G5 b0 c0 v2 [1 L8 h6 f
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */- }" S4 J! l1 T- z6 K! ^
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    ' V$ P0 |% |& l. H' S. R2 V
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码
! d1 [. t/ \. K1 V* C0 [
  NbSectors
9 v  g4 P, T+ W. v! H1 r. y1 b, |  Y* R用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。7 F6 A* j' N1 I
1 s( K9 W# j: X7 I0 y4 v) k/ j
  VoltageRange
# D5 f0 l; v& N" y5 ^9 A  Q用于设置编程的并行位数,电压不同,位数不同:
  R! q: _$ d, B; B/ W% B
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */8 r. v% ]0 f( t( H# k9 B
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */, B( q/ t2 w5 _& ?( \% M
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */& x# H3 U5 \8 B5 A6 G  e+ d
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码
; _: U6 M0 d' e+ J; p+ \: S$ |9 }

4 `" e  F! e# w; v* E70.3.3 内部Flash的操作总结& b# ~) o5 E6 b0 U

6 L; @0 s' C2 E1 ]  ~( k7 b
) Y% {! x' A, J. d使用方法由HAL库提供:
/ i3 H; i$ h, O( g' p  Flash编程函数操作流程
1 M: f9 q% y" H& [  Flash解锁函数HAL_FLASH_Unlock。
% Y) Z* X$ T$ ]  a1 z) {$ V7 `  Flash查询方式编程HAL_FLASH_Program。, R) I! z' P! B  s
  Flash中断方式编程HAL_FLASH_Program_IT。2 z: r; V+ j! e6 }( @4 x/ z# h
  Flash上锁函数HAL_FLASH_Lock。- w% e: @$ w' q! F. ^! S. G) Y
  * {1 h/ r  s; L9 b! o7 O3 b2 c
选项字节编程流程
0 u  i' A9 A  V& Q6 ]9 I9 l# _9 U  选项字节解锁函数HAL_FLASH_OB_Unlock。, t) j1 {, u, b1 D2 N5 Y  ]
  选项字节加载函数HAL_FLASH_OB_Launch。, Q, n' ?! V* k- c
  选项字节编程函数HAL_FLASHEx_OBProgram。% y4 z+ t! i( e% j) X& T4 F
  选项字节加锁函数HAL_FLASH_OB_Lock。3 v: S4 W; s, s4 |4 F  t
; H  A, a  [- G" f
Flash擦除流程, u6 c/ ]2 N3 t* F# {' l
  Flash解锁函数HAL_FLASH_Unlock。3 r7 X: q9 G* ]! V$ `0 F% r+ o) ]
  Flash查询方式擦除HAL_FLASHEx_Erase。
+ ]: Z( D5 O, X/ H  Flash中断方式擦除HAL_FLASHEx_Erase_IT。- M# ^: F! u+ O& i- |& n) U; t* ?) J
  Flash上锁函数HAL_FLASH_Lock。$ W0 _+ b% R+ O+ J2 w

: f1 y) y4 w3 E' P; @4 F9 j- K  t  x. {5 N/ q% a6 J, ?
70.4 内部Flash源文件stm32h7xx_hal_flash.c7 }) w: x) ?/ ~+ t7 [( O. t
此文件涉及到的函数较多,这里把几个常用的函数做个说明:
8 [( @0 _" X+ V
# n& v2 L9 [/ r% k! a  HAL_FLASH_Unlock* {3 O. g) q: R' ~6 p
  HAL_FLASH_Lock9 h; F/ }- e8 _6 g
  HAL_FLASHEx_Erase9 ^3 e/ \5 f+ u4 O
  HAL_FLASH_Program# o' @) x4 X+ L# ?2 ^- L

& q3 Z; Z3 e0 \. P7 t. O1 v$ L6 n! C/ j70.4.1 函数HAL_FLASH_Lock
! R6 E- l! h7 A( b! k4 e7 N函数原型:
: {* l0 D" R0 {$ j; j0 |% T
- N* {- s: K; g6 Z. S  ?6 ]
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void). i  e7 V9 a0 {. N: A  I
  2. {9 b/ A: d( v: J& v  E
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */
    & L; i2 Y$ u' W# N/ x+ K6 \8 k6 D2 s
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);- b" i/ j9 c& _& X- f- D

  5. : v5 u6 y3 M  a, u, V7 u/ }
  6. /* 验证Flash Bank1是否已经被锁住 */
    4 G- Q  N+ C% w4 U3 K# O2 ~# m
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)
    6 d$ e7 H' P7 q6 @) v/ w
  8.   {
    $ v  q6 ?" V0 r9 z- F  V3 Z: i& y" ]
  9.     return HAL_ERROR;
    + a( U7 e$ R( W1 m( ]
  10.   }
    4 s/ j! `; g9 ^" n% c
  11. + ?# V9 [+ Q4 H$ [
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */9 j+ I/ |, p% b4 r, p
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    % k# o% k+ i: W
  14. 5 b. m) [8 T0 ]2 H* }% u- l6 X! `8 s
  15. /* 验证Flash Bank2是否已经被锁住 */  q) ?3 Q. Q, U* U
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)$ }2 H4 {1 z- C! u
  17.   {
    ; q- Z. r- ^: H5 J  x9 ^
  18.     return HAL_ERROR;0 c. Z" s) |( @( p9 B- U
  19.   }
    9 ~8 I9 ^: l. Y3 m7 m" Y6 j2 `

  20. ! M& z0 X+ [  D6 |+ ]
  21.   return HAL_OK;' E+ f) t& y; h: I
  22. }
复制代码

# B5 X  K' s  H( G% @函数描述:
3 ?8 o8 H6 v+ n# g% d+ y! _' j8 K" s6 U4 C# j% N
用于Flash加锁,加锁后将不能对Flash进行编程和擦除。
, `  m* S3 D, `; _# G
1 S% M8 T& ~2 A. {8 Q8 Q- Z70.4.2 函数HAL_FLASH_Unlock4 P3 n! o3 \+ H# z
函数原型:
: s0 Q5 k5 g1 o+ i, o/ q" u
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)7 s8 ^4 s3 p" a1 w9 B
  2. {7 L1 P6 s2 e& X1 F0 Y/ ]& O
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)( g' N* u0 ~1 E) n3 g; Z
  4.   {+ f. [: D4 I0 ^6 u
  5.     /* 允许访问Flash Bank1 */4 z9 y( D3 i# e! v% K1 ]. d
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);" r+ Y) M& |9 d+ B0 C# n
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);
    5 F# D9 Z, U( w4 n7 O

  8. 1 B' F* M4 ^+ q2 o0 z5 c" W
  9.     /* 验证是否已经解锁 */
    ' B# ~+ ^0 B7 M4 E
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
    % t" x/ B' t/ w& u8 F' ^4 U  K
  11.     {
    * l) E1 x. z0 Q( Q
  12.       return HAL_ERROR;
      s$ X: j! C! x4 j; F/ I, I( w
  13.     }. [# b4 l) A! `' @7 ?3 J
  14.   }
    8 S/ H, i3 C' I. ^& N6 n3 _

  15. 8 O2 M. l8 z" H  g
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)+ y% N& x% D3 y4 Q3 }1 }  ~
  17.   {
    ( {& f- J7 D2 \9 R& m
  18.     /* 允许访问Flash Bank2 */
    2 q% ~+ {# l  w: L+ V) C0 C
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);
    , V$ B3 }: [. x& i( m
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
    & G  z$ o$ n! q

  21. + }. ^$ M1 N/ W7 B  e. J# U  J1 j3 H" p
  22.     /* 验证是否已经解锁 */5 r: N2 K$ D3 g, f1 Y; T
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    # B& d0 ?9 h, |" t, K
  24.     {# K' U) ]* n% I% t: U: t
  25.       return HAL_ERROR;' H9 c/ e/ ]( p& l/ X: I
  26.     }+ |3 \1 B$ O: ^2 m$ {4 R' H
  27.   }
    ; F3 a. m) y1 P( P, r
  28. 6 ~3 S; H" ?/ X6 x' W
  29.   return HAL_OK;
    + e* ?0 k8 `. V: i
  30. }
复制代码

% ]/ b, h) A; G. }5 j" T函数描述:
# ^( `' q, D; `2 z1 t$ o6 C5 ?8 @# N  n2 a$ C8 W7 p
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。" l0 T& e8 e* Y2 J8 ?9 S

6 F9 q0 y- F+ E- |% I" Z+ f70.4.3 函数HAL_FLASH_Program) v/ L1 T" s6 b8 M  j
函数原型:3 Q+ f, i+ w* E" ~7 }! a' S8 t. p0 S
. o. t5 o! M# T/ o4 r; n7 A5 s( X5 d
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
    8 p3 D5 C5 W, x
  2. {2 x; O! U5 T8 }5 H- ?( _
  3.   HAL_StatusTypeDef status;
    % S! j9 @) S8 _  {% G
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;
    ( Z& i8 Z7 R; J- Q/ Z+ G+ y, x
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;- y- j* [7 w) a) \: [7 R' d' ~. ^
  6.   uint32_t bank;
    8 I! d5 v. i1 Y/ p9 v- `
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;( H5 D) W' @* V- j; |+ g) `

  8. / J6 x9 c4 i& E( X2 }
  9.   /* 检测参数 */
    " X) y0 x1 w0 K
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));! t9 m' [8 m8 p) e6 M
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));1 V' u* p+ n& \: ]& Y* v4 r

  12. ( d* d; c/ A4 |' g
  13.   /* 上锁 */
    8 U$ d5 j  W8 b# F1 V
  14.   __HAL_LOCK(&pFlash);
    / W; \! F( q1 V: a

  15. + c" t1 y4 j; N* R0 k% {
  16. #if defined (FLASH_OPTCR_PG_OTP)! l, c* l# Q0 h9 G# P- J
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))& ^' B7 o% G3 o7 Z* h/ T: B
  18. #else$ b, r0 t+ b$ _9 L& D
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))( R# ]7 `7 l  j3 D6 g
  20. #endif 1 f+ N8 O# v  d$ |4 \
  21.   {
    7 N3 M# T$ R+ _) N- a3 {2 m
  22.     bank = FLASH_BANK_1;7 F! f: e4 k; D
  23.   }1 Z1 v. y/ t" K9 r  a/ |
  24.   else
    1 ]1 Q) N  E! z3 P  F6 g
  25.   {
    ; _$ U  q1 u! s" V0 X% M: Y, ^- z
  26.     bank = FLASH_BANK_2;
    3 x& w9 N6 X( O2 j5 a
  27.   }2 k/ M4 q/ e7 G& u

  28. : O- H0 K( \, v
  29.   /* 错误标识,无错误 */
    1 f6 b  R/ W) p7 b: t
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;: e8 u  P0 d2 k4 S  r, r

  31. 9 g! V8 C( |3 i9 w
  32.   /* 等待操作完成 */8 \6 A( C4 `  B+ p8 [4 k; I
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);3 f& b9 Q3 F# K* q) d7 d. T: B
  34. 8 v; Q9 O/ Z& E6 A% l4 P- O
  35.   if(status == HAL_OK)( z" g& c! N, T7 k
  36.   {
    3 R7 ]# l  ^. Z/ b- g
  37.     if(bank == FLASH_BANK_1)
    % k9 d5 u+ j; ]3 x' N; X1 F8 Z
  38.     {7 u" |8 T* Y- a! x5 i7 T3 N* K
  39. #if defined (FLASH_OPTCR_PG_OTP)- S9 E8 y! r0 l$ _" q: x+ a
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    ) T7 H: P7 Q" Z9 g8 J, U* f
  41.       {
    7 T( ]7 Z- z# U1 W2 P2 }9 V' ], @
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */
    - Q9 E  ?+ q2 y8 P& P
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    $ q; j+ |8 a# h( {# [! W
  44.       }
    / N" C' T( O! x" c( _1 }2 x! M
  45.       else5 v1 c1 Z* H/ n# A( I0 j6 U
  46. #endif 8 n1 T' i  q2 ?! ]
  47.       {6 V! S% Y0 p# s& C2 h
  48.         /* 设置PG位,使能可编程 */8 V- q6 J( u1 P+ q/ x5 U' w
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);6 ~; J% |' |8 `3 f# u
  50.       }6 s0 M& L# o' z8 o+ V0 R$ @! X
  51.     }
    8 a: u$ o+ n! c, \+ `! X9 c  K
  52.     else! H! P( n: I) C5 [; f/ f- B
  53.     {
    9 t, j* l9 i+ u8 `  Q* W. X
  54.       /* 设置PG位 */
    ; K3 N  e& S/ M3 L
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);
    ; h! x- W' f! w" O1 T3 A
  56.     }
    5 q) E, W$ U4 N: a: f" E" z, D
  57.   K4 }8 X% f. Z, e
  58.     __ISB();/ a6 S+ s) l# n5 B  L
  59.     __DSB();' t5 X$ w" J8 W; I2 b  {

  60. / b9 `( ~% m0 r9 U% v
  61. #if defined (FLASH_OPTCR_PG_OTP)
    ( a" g. ~- i1 ~+ W1 b/ f
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)! N3 z* j; E# `) @' }! B1 n
  63.     {
      e7 ]1 p. o; K; M# _; M! C
  64.       /* 编程OTP(16 bits) */
    ; w3 `; Q- x- h: v  ?9 [2 o
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;3 A% \, ?+ A; Q
  66.     }
    " S* \" {2 w  W: N+ @- \9 i- ~
  67.     else+ r) z/ t2 R3 K- Z9 z
  68. #endif
    . Z9 n& ~' s7 b1 s
  69.     {
    6 w  B: u: Z7 b0 Q
  70.       /* 对Flash进行编程 */
    ! C" A# f6 c5 H6 E, k7 ?% d* h
  71.       do
    ; {6 x. H/ U$ w& i; J
  72.       {
    , w- g4 P' Q2 a
  73.         *dest_addr = *src_addr;2 G1 _4 T0 v% n0 }+ F
  74.         dest_addr++;! r4 N; _0 T% w- C
  75.         src_addr++;, }: w1 U4 D! y% k
  76.         row_index--;
    ) q! I) u2 G+ Y+ N; {  Q
  77.      } while (row_index != 0U);0 o  _% N% [. F( ^; Z3 |/ f! z
  78.     }
    ! d) L) I3 k5 q9 M, g
  79. " v7 H8 H1 W& [
  80.     __ISB();
    9 G$ U8 E; v" w9 N
  81.     __DSB();
    4 P2 B6 f( h& i. x( r0 u
  82. * A0 V% _+ s: {/ `( n& D$ v3 K( n- F
  83.     /* 等待最后一次操作完成 */; q% y* o+ I$ g5 W0 {# \
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);' N+ a8 |2 l  Q. c& w

  85. ; f( Z# {: |0 O/ ?5 k* p
  86. #if defined (FLASH_OPTCR_PG_OTP)* O& F* M) G7 w9 p3 r, j
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)7 z, D2 f# Z/ g  v1 G. T
  88.     {
    1 l; Q) H  D2 v- S( }/ S. l
  89.       /* 如果编程操作完成,关闭OTP PG位 */6 y) ?" U; ?! t# o
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    - i# E$ M  C  v* d7 v: L
  91.     }1 B6 g( c- T; `8 T! C# q
  92.     else
    ! \, m  J7 X% [% X
  93. #endif
    . v: u6 s, P4 e
  94.     {- [% D) d& {/ J" m2 ?/ l( y
  95.       if(bank == FLASH_BANK_1)
    % P0 ?0 N  m1 V4 ^5 o
  96.       {
    1 V+ Y) U$ T2 v* n. [: @) e
  97.         /* 如果操作完成,关闭PG位 */6 E! C6 A! h) |- N4 @
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);) o# p* ^8 D7 R9 t! E) k
  99.       }
    $ L) n4 a9 N9 x  m
  100.       else. t1 _' b: a1 \& |0 F
  101.       {
    & h. o) w$ {$ e" r8 J0 {! Y3 f
  102.         /* 如果操作完成,关闭PG位 */8 Y; F& ~/ T+ h5 D
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);
    9 m; o5 @0 {/ h: p: O" @
  104.       }
    3 M9 K' f, f: t  I) D
  105.     }9 H/ o: l: L# ?8 a
  106.   }4 D- P$ F4 m% f

  107. , p3 Q1 B5 x' h! c
  108.   /* 解锁 */1 a; Y5 x# J: x4 u1 W& o
  109.   __HAL_UNLOCK(&pFlash);4 W, g/ W+ x3 ~- e
  110. ( J- R2 x% h5 z8 `! N2 z
  111.   return status;
    6 ]4 J# R- L' p
  112. }) ~0 t& d% _% P( @3 b
  113. 5 @+ N$ |: @, q4 M9 w6 Q8 ?# W
复制代码

: q! k9 I/ ?" z5 q7 a) ^, t; e函数描述:
, f; F: e$ X7 J9 b! O0 m! O, g此函数主要用于Flash编程,固定编程32个字节数据。
1 Z5 Y+ V6 d# T. S4 ?; v. ?. [4 Q# U* ^, t& g- P2 L3 j5 [6 t, t
函数参数:- g' [0 U6 a; u3 i: P% m( N
第1个参数是要编程的Flash类型,支持两种参数:$ Z7 U& T2 i/ N6 R
  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
* ~3 a8 z; i7 A" f  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。
* f0 H# J; O) m! I5 B  u1 k4 t2 o3 E& L& S% |
第2个参数是要编程的Flash地址。% z; q7 i. E- S0 A1 v) Z& B
# k4 h4 z: j  r5 p5 D: e0 N
第3个参数是要编程到Flash的数据地址。 0 D0 [% f) E* z4 `
返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。. [4 ]) z9 t5 r5 ^! l2 ~- u: U
- x* f+ m3 ]" J5 ~3 A. u

+ O3 u! O7 x! a5 R! d注意事项:5 P' F3 f$ o9 L1 X8 e* z) Y. L
  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。6 }4 q7 I& K% n0 C* }4 p( q( V
  第3个参数务必要是32字节的整数倍。
! q9 Z$ M3 z4 G4 M9 j3 u, G  I- q% E2 E7 E1 A, c. |) }
70.4.4 函数HAL_FLASHEx_Erase
( P; P* U& K% [( Y# j: T0 q9 w函数原型:4 s+ Z* b. O# u/ _/ n+ }
1 n/ U$ L  S0 i6 Z' H0 l
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError): M& u% I7 x, R! |/ C5 Y
  2. {8 m+ @& u0 M, t5 Y3 e2 ]1 x
  3.   HAL_StatusTypeDef status = HAL_OK;
    ( R" w: n8 x0 |) g7 q$ B, r4 a
  4.   uint32_t sector_index;- J: k1 W5 l6 Z5 U

  5. 1 _6 O+ i$ l2 @6 Y
  6. /* 检查参数 */
    % D- K8 W+ X% A' b5 q$ k
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
      u& @5 y1 y+ L; ?. b
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));
    ( r+ V+ e  N) b$ R( W4 |

  9. 2 _- i) [/ J9 `, t( l7 Z/ q
  10. /* 上锁 */" X4 x' f) P3 a! D# c! e
  11.   __HAL_LOCK(&pFlash);( H- G. I- U6 M- G, ^
  12. 1 F8 _2 p" g6 e7 j& r. }
  13. /* 无错误 */
    : l* H- b8 y% t4 f
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    6 T5 W$ }* ^; N) Z
  15. 8 c4 T; Y7 A' N1 d7 a, {7 ^" f2 u
  16. /* 等待BANK1的操作完成 */
    * _2 F5 e4 m, J
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)$ O0 e- H5 ^" R/ |& W
  18.   {! \4 p, d. E' q( W; n
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    9 [! R4 \! |3 Z. E
  20.     {
      ^" D1 |9 b& I0 C6 `5 F2 I# \
  21.       status = HAL_ERROR;1 \' [, N8 g% T! }# `- X
  22.     }$ Z' O. c9 A0 v8 [% I* t5 P  B
  23.   }) |% M. ]/ Y: J$ M: M" X; y
  24. 9 Z1 @2 S, F! [6 l3 |, `% [! M0 X  P
  25. /* 等待BANK2的操作完成 */
    9 y# h3 C: w! O# r3 A: P
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2). Z0 c2 v( q. K# O0 e
  27.   {& P9 M" u- g- i6 X# e
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    - Z  Z6 {" w# V/ }/ Q
  29.     {
    % Z. k0 F. I. o# K# _! F1 y( \
  30.       status = HAL_ERROR;
    ) ]  c9 K/ `- H+ g4 v
  31.     }
    8 x2 L: K4 P! Z) _8 M) y& D+ l0 S- D) ]
  32.   }9 a9 x! i' P* g1 v9 }+ I  P5 U

  33. . o! x3 d9 t7 u% f  Y/ r9 |+ C6 M
  34.   if(status == HAL_OK)& I; {- r4 A; [, ^
  35.   {7 W: ~4 I6 B# K
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
    7 ^9 \2 T# ?8 C- l4 U' q6 G: [' J
  37.     {
    ( _. n( q7 A4 A: `1 _* I
  38.   /* 整个BANK1或者BANK2擦除 */5 j6 p: |4 f; T" G
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
    5 |; b5 r! l1 h1 C# q
  40. 5 l, O+ J9 c- h8 D
  41.   /* 等待操作完成 */
    / l. K* Y  w4 h. y6 ~5 d- m" g5 I
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    + }$ x1 a' P! [
  43.       {+ o, x* m5 f' Q; R8 ^  T2 w& G
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)+ x. U* c# u# `) e  O& Y" y
  45.         {
    $ F7 c. m' ]  Y
  46.           status = HAL_ERROR;
    ' m0 J( s1 j+ g" O% j% z
  47.         }, }& Z9 K3 p& @0 F
  48.     /* 如果擦除完成,关闭BANK1的BER位 *// t0 w5 ~. X3 U5 V2 c
  49.         FLASH->CR1 &= (~FLASH_CR_BER);
    ! [; n6 e2 Q& f0 O5 O  Q
  50.       }
    2 g! e) f9 v; U. g" J& x
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)  K0 c7 i( a' E* a/ I
  52.       {& @( P8 P7 T- X0 h. k: U; Q
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)3 a$ q2 c% o) G* b% F  I
  54.         {& n) }' ~& M6 `5 ]
  55.           status = HAL_ERROR;- W+ N7 [& m7 [# S
  56.         }% p" g! D: R% c& S% A
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */
    % S  ~# p( L+ z- k$ B
  58.         FLASH->CR2 &= (~FLASH_CR_BER);+ g2 R2 l* D$ ?( w! e& O
  59.       }
    6 W) `* W, t. n& \' ^- u2 u8 N
  60.     }; f: |5 B$ V* O& p
  61.     else
    6 x0 K: q0 g- {5 H" `
  62.     {
    + u6 X+ N/ Z* Y  u
  63.   /* 初始化扇区错误码 */% m7 i8 c9 B3 z) [- [
  64.       *SectorError = 0xFFFFFFFFU;6 G" f. |0 O8 X" ^2 A
  65. ' Y% B( b  X  S+ B: Q
  66.   /* 扇区方式擦除 */
    , t1 k7 K* e) P2 B# Q" s
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);& U4 e9 ^" X) J: O' G/ U: w. E9 m
  68. sector_index++)
    ' C- L. ]; C; c- E3 _# g: \. V
  69.       {
    6 T, x# `+ ?0 l8 `4 U' @
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
    ( Z6 O) t* ~( ]& v1 z3 r% B; v
  71.   e" S  w1 U# j6 s  ^
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    ! l0 c- `( S3 H. Y$ T! S* u
  73.         {8 g* ^3 F* X9 ]# @4 }* u8 P6 \9 a4 W( d
  74.       /* 等待BANK1操作完成 */, x- E" x5 O( Q
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);
    : }1 R: D4 P4 G; U6 \5 q

  76. ) I1 n- q' x6 s: F
  77.       /* 如果擦除操作完成,禁止SER位 */) [3 u2 m" D0 d3 j
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));8 B4 Q% z' ]& X/ R
  79.         }
    ' f: d; N+ s" Q
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)0 @$ K: `1 \) c5 c
  81.         {
    2 k- U7 Z8 F, e" `# z
  82.       /* 等待BANK2操作完成 */9 u! ?1 p" H( _
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);
    4 X) }! C$ t$ m; b( c
  84. , p  T9 g5 D) e' }" N
  85.       /* 如果擦除操作完成,禁止SER位 */
    # `, P% E8 m& P% h" q# y% l
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    3 t: }0 y( d" e5 Q- O) ?3 Z
  87.         }
    4 P* h4 r% w( B/ b. g& F9 {/ ^
  88. + M5 {" M* E4 i5 |' j, J  p  l+ }
  89.         if(status != HAL_OK)
    6 z/ x$ `$ d9 q: W% c% K
  90.         {
    1 j% k4 D7 Z! }& d3 ]+ d: p5 G
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */  `, v% `- N5 R5 M/ D$ a0 D
  92.           *SectorError = sector_index;
    $ w0 U/ E* L' Q  j( u" m
  93.           break;
    * c% L: u7 @/ w: d: o
  94.         }7 z1 T2 D" [+ V' l; ^! c8 Z' `
  95.       }. M) Q, s$ M5 b+ e1 ?
  96.     }1 B2 ], f6 G6 s  n
  97.   }. U" q2 r9 E' l/ v# U

  98. 6 g) {, R8 H4 t, J! q
  99. /* 解锁 */
    2 M7 {7 C/ d9 i0 g
  100.   __HAL_UNLOCK(&pFlash);
    " C2 P7 h6 m" N
  101. ) `# B/ f1 W  C# C% v
  102.   return status;
    " d+ H! T, T5 V- B6 P: A
  103. }8 O6 x: L, O2 X: C$ G
复制代码

$ u3 j( t6 p' P( s函数描述:
# [. T" L  w4 k+ f8 [用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。
7 W# f6 l2 y3 y, s" G( b& V4 m- c
# J- N# U4 s5 Y9 K函数参数:
( H6 R' T' n  h- f5 @0 P  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。* @5 q+ L6 X7 t% p7 z/ w
  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。/ p0 e) {1 j$ H
  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
) ]) o) Q# Y% S. ?% A  r, t
0 H9 g" a" [: i+ q* Z70.5 总结$ Y" [4 d8 V  u& {# Y1 r
本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。
. X, a; ^7 f( U+ d9 y) d* K
7 @$ U& d( G$ d3 ?( h
) w4 O# j6 b" x( O9 \
) j2 `% ]4 E% {$ M, X2 M
收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版