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

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

[复制链接]
STMCU小助手 发布时间:2021-11-2 23:53
70.1 初学者重要提示
, @$ _! y3 K1 J$ f+ K9 |: ?' X5 B  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
( c' G, e1 B# \1 u' H  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。
2 b" Z# {' N" p  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。
8 w0 y, ^& J: c* K- a6 T7 M' R  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。; e+ E2 o. N$ F4 h7 ]" w- W
70.2 内部Flash基础知识9 J, Q$ t& }  T: c  n5 d
70.2.1 内部Flash的硬件框图
8 x/ z" e& @' t0 B认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。
9 f% Y- s8 q" _& i7 [) }
3 w. f% p/ N0 _+ _7 i) U. y
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
5 v! _) {/ Y- J% p- M

7 U" j) Z  k8 r) M$ s) P/ F0 R通过这个框图,我们可以得到如下信息:
% j8 b: w2 F+ B( V" @+ J, z, _/ U7 m0 d( e6 k
  sys_ck时钟输入
4 E6 G1 P, J  ?8 t9 QD1域总线时钟。9 K$ Z4 j: G- q2 Y0 }
9 j& E( U4 f( O$ U/ |0 [
  po_rst输入
8 |2 s6 w( `3 f& ^2 o2 i; V$ dPower on reset 上电复位。
$ ^+ O/ g) f  x$ s- F4 a+ d4 q" y: J6 ]2 k$ z
  d1_rst输入
; p; `! v/ k& ~; }, sD1域系统复位。" Z" ]  @- i; J
0 n0 c! e* o+ p4 S3 z% X3 m  V
  flash_it输出( f9 j8 q8 A& O: g
flash中断请求输出。
7 _' b3 H$ R( b) O5 v$ M7 {
7 @$ c% ?3 H8 p. T
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

9 x  `: R9 F, B8 X* V8 ]/ w4 D3 S% S% i' q2 V0 Y& b
STM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
: k" H+ t$ ~; j( m0 R8 G( \" H
+ v3 L' G3 K% k( `9 g# w/ n5 T- F70.2.2 内部Flash框架
" `- A, H* d) Q  M* ?/ S- ?关于内部Flash的框架,了解以下几个知识点即可:
$ h1 d4 {" o8 B$ z) ]& _' Q1 ]+ R) o  m2 q
  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。4 g- r% t& F7 R% Q. |
  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
6 c3 T9 o1 i  s; L* i- I$ x$ c8 M: L! X. U1 y0 ]
1 \, u. k' |" F5 _) C& S- Z
) ~0 `. ^1 _0 }7 Y* o
BANK1的地址范围:0x0800 0000到0x080F FFFF。
  ]# j' O% C" J" F& k, `- E3 o& l8 M! V3 D
BANK2的地址范围:0x0810 0000到0x081F FFFF。
  ?2 B' e  N( t: V7 z
, s$ {8 x, z7 k) [7 p0 q( @70.2.3 内部Flash读操作
) P8 W$ r7 K+ ?/ Q5 {STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:; O3 A9 t- B) @5 H* e4 W
( V  r' s$ v% Q! w
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
: H  s( B) I- D

, N+ h, H" p3 G9 }, |  {5 Q对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
2 [4 {( t6 m  P$ }3 S5 Y; Y) t) e7 ~; h& L6 d
了解了这个知识点后,再来看下面的时序,非常具有参考意义:2 |) \& M/ i; M$ t" k: D9 a8 g
* N# [$ O/ [2 ?( _9 C
注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。
9 w  O8 p* c( Y1 M8 L; b7 d5 S
/ o; K) p  M& Z, e2 R3 K: F9 C
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

& ^" F6 F# P4 |
7 c/ C" r# R- ?' N9 G5 @关于这个时序要要认识到以下几点:* o3 {' `% e1 U7 q
- ]8 B0 X  i" X% h
  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
6 p# {- X0 \+ T2 r, B! k* X  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。8 h2 h2 w4 X' X
  如果不开Flash Cache的情况下,连续读可以提升性能。% c) p" c  r1 i) f
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。* L3 w, [1 f1 Q6 @5 m

! O9 @4 i" v; a7 E0 @* F* w
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
1 i% u& Q. i1 g( G3 G

2 g. D% b8 N' n+ P1 ~; v" B70.2.4 内部Flash写入和擦除操作
: ^" n. C! S2 R最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。
. u* Q5 W3 b- e
( y1 n9 V1 c! X9 v; t这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:5 T% h, e% C+ [
+ M5 L5 \- h# y# @
先保证这块扇区空间之前已经擦除过了。
% @8 E0 N2 e3 L# U* \# _3 t解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。# R$ l" p% Z8 B( y  M# N- S
检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。. }, w! |6 o7 @- ^/ I

9 m  j7 K% q: P# Q* p/ A- K0 }' ?) b1 O' \# J" u6 T6 n
Flash的擦除流程如下:
. H( j1 w3 t* k- w9 G. F" u' O: b7 a4 a
  y8 m+ F0 }4 o( O* B  K解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。6 l& o$ j1 x# t2 V9 l" A
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER25 J7 e: V2 |( h5 V8 R3 i
如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。
* U" X4 O' p# f( s- B70.2.5 内部Flash读保护
7 y! M! ]! H- d$ c8 g内部Flash支持三级读保护RDP(read out protection)。3 P- e- `7 t! E1 f

- h5 q: B7 q% z, R+ k5 g  Level 0(无保护)
5 ?0 ~& l2 x; A4 ^* A( w默认设置,所有读写和擦除操作都可以正常支持。/ I* K* |. d0 L5 z9 \2 ~

4 V" p! z* F  z, s  Level 1 (Flash连接保护)1 T2 e% Z* N, B- Z
  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
5 Y, }( R  j2 {) L  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。
/ Q, _/ o2 s9 p2 h  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。6 M4 ?8 s+ q3 s# N4 k
  Level 2(设备保护和自举保护)/ t; s# }8 u7 v0 I* I' d) P
  所有调试特性被关闭。1 Q6 U4 x1 y+ C  E+ b, ]
  禁止从RAM启动。  {$ j! G4 q! X3 r5 b5 [% w
  除了选项字节里面的SWAP位可以配置,其它位都无法更改。
$ g3 c* P9 J+ U+ c- s- X1 w  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。0 f/ H* V+ e3 d+ V% ~, n* k9 P& {
特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。5 ]* P: I, D5 i1 `" j! ?: g) z5 }  z

/ p0 Z6 p2 H/ W. T如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:: p- h1 Z2 |4 H( B
) \6 d$ `9 g( J# U( x( D; P$ A! g
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
: J& @5 J1 _- G7 T

8 Z  c6 F) y- D- J& O70.2.6 内部Flash选项字节
9 M0 p( [+ C( C, sFlash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。# E* m. M( N, X/ z" V
0 x# @# k2 ?; _) h! y+ f
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
4 x0 h% r4 F5 y' b

, o( ]+ B, v: R* g: a  c% u$ d70.2.7 内部Flash的ECC校验
. r* r, h+ C4 n这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。
8 A, V+ Y$ o% Y! p/ r. I
% o. f' X3 o" v$ _* q对于STM32H7带的ECC校验,一般不需要用户去管理。
* k  W! p& N; s
" _: P( w& [# v5 t. U8 T" y70.3 内部Flash的HAL库用法
5 A$ U3 r5 W6 C! \70.3.1 内部Flash结构体FLASH_TypeDef! w  o% h# ~+ h$ z6 B
内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
. X  R& y0 R, [0 C
3 Y% a, W! Y9 |' A+ W
  1. typedef struct- d, v' B' c: J4 t# Q* B- g
  2. {
    ! L( P4 ^5 k2 r, S! ~$ W' N
  3.   __IO uint32_t ACR;            , n8 X+ s& H' l
  4.   __IO uint32_t KEYR1;           0 W) @: O$ B/ Y& W7 x, W% e7 Y5 D
  5.   __IO uint32_t OPTKEYR;         2 f) W+ |8 C) b$ U
  6.   __IO uint32_t CR1;            ; U. h9 c+ K+ ^; q8 Y* y$ U
  7.   __IO uint32_t SR1;            
      J8 J& x1 K: s3 Q
  8.   __IO uint32_t CCR1;         
    4 d) g9 v: {8 y" w( b. I1 N
  9.   __IO uint32_t OPTCR;           
    2 Q4 P( p3 |3 D' i
  10.   __IO uint32_t OPTSR_CUR;      
    ; }8 t3 v, [5 p, e- G( b' T
  11.   __IO uint32_t OPTSR_PRG;      : x5 k( |8 a  e
  12.   __IO uint32_t OPTCCR;          0 y! \4 E' Z; T* U3 L7 t
  13.   __IO uint32_t PRAR_CUR1;       ! Q3 I- M6 A' q* e
  14.   __IO uint32_t PRAR_PRG1;      
    9 y3 w8 K* F* o
  15.   __IO uint32_t SCAR_CUR1;      
    - s/ ]5 ^% k, e/ N
  16.   __IO uint32_t SCAR_PRG1;       8 v0 L( z6 z9 q$ r5 W
  17.   __IO uint32_t WPSN_CUR1;       + Z. M- E3 ?0 t+ d
  18.   __IO uint32_t WPSN_PRG1;       ) W8 K! f) H( G( _4 k* U& A
  19.   __IO uint32_t BOOT_CUR;      
    1 X% u: K- s# i* x5 t8 Q  z
  20.   __IO uint32_t BOOT_PRG;       1 j6 M6 w- w! K
  21.   uint32_t      RESERVED0[2];    ; O# s) o7 u5 _# R
  22.   __IO uint32_t CRCCR1;          . }0 q0 ?. ~: E3 _% }, p
  23.   __IO uint32_t CRCSADD1;      
    , p2 A  \7 A! N2 A! S: r
  24.   __IO uint32_t CRCEADD1;        
    4 Q2 i0 x& t5 t' R* g1 ?2 i
  25.   __IO uint32_t CRCDATA;         0 z' a/ J. i+ R. c+ ]6 W6 ~
  26.   __IO uint32_t ECC_FA1;         
    9 m- M3 e/ ]6 t3 ?. N4 H; c5 f; D" q( P
  27.   uint32_t      RESERVED1[40];  
    1 i+ @3 W5 A2 ^; R1 T
  28.   __IO uint32_t KEYR2;           
    + c; r6 ^0 K8 W6 V* c( X
  29.   uint32_t      RESERVED2;      / Y# S6 J8 A+ |) K: `, j
  30.   __IO uint32_t CR2;            
    & ^4 |! }6 }. c1 b* [/ Y
  31.   __IO uint32_t SR2;            
    # E0 o% ~, z& v2 s
  32.   __IO uint32_t CCR2;            
    2 B) X( ^* n5 `# f* |2 O) _
  33.   uint32_t      RESERVED3[4];   
    8 c. b- u% E7 B* h5 B( \
  34.   __IO uint32_t PRAR_CUR2;      
      g% r' Z. f0 |) l; u
  35.   __IO uint32_t PRAR_PRG2;      
    8 J+ G7 M: U9 X- N; \2 r- F* U0 k4 t
  36.   __IO uint32_t SCAR_CUR2;      
    - a7 Q$ i* n) h. w4 t& }; {1 ^
  37.   __IO uint32_t SCAR_PRG2;      
    9 D6 l* {) K* E& S5 H* [6 Z1 r5 |/ @
  38.   __IO uint32_t WPSN_CUR2;      
    " \' U8 @; {9 d  @" b1 @
  39.   __IO uint32_t WPSN_PRG2;      
    # |4 m  V: h* T0 ^$ J
  40.   uint32_t      RESERVED4[4];   
    8 j6 t  X, X0 ^5 ?* o) C
  41.   __IO uint32_t CRCCR2;         
    . S# E5 m- Z) ]
  42.   __IO uint32_t CRCSADD2;        $ K% m! Y* J/ `- _* _" o
  43.   __IO uint32_t CRCEADD2;        * p. e9 p% K2 R) d
  44.   __IO uint32_t CRCDATA2;        
    - t/ V" c4 @4 b. S  N) ^
  45.   __IO uint32_t ECC_FA2;           ^/ d+ e* i1 ?5 H1 L: q
  46. } FLASH_TypeDef;
复制代码
0 N, D0 S. T1 N8 w
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
2 _3 R* C* k# ]& V* J* b& S8 M  B/ e# e
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:0 M& E2 W% {4 d% ?6 m: \

" Q  z2 k' g# _9 H
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */5 ~& X3 K$ V" d( T) ~  U9 \/ z8 k
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
2 c- [& h. k; d2 a, C
下面我们看下Flash的定义,在stm32h743xx.h文件。
! ]7 W3 S! D' k4 k/ C  W) K/ F& U( ]  ?* c7 P( T3 `+ U
  1. #define PERIPH_BASE              (0x40000000UL) 4 b% c! ~' c7 W- u
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL)
    ! |" l5 l3 v# j  m+ S  @0 R6 Z2 u' A, @, ^
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)6 f+ h/ Z, _" D7 c
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码
& [0 w- M& i8 z6 @" m3 s( n
我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。( h8 A) M2 E9 h5 {
0 W) H) w6 ?3 D8 r4 m9 P, C
70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
& l9 E- ^5 r7 V6 y' R1 s  k下面是做内部Flash擦除的结构体,用到的地方比较多:
8 J! [- i% N: }6 O& R5 _  M
  1. typedef struct
    + c) s9 H( B3 T8 N) X
  2. {# Q4 F2 h3 y# r" e% \( X( I8 `7 l5 A
  3.   uint32_t TypeErase;  5 V: M9 B4 _7 W% d
  4.   uint32_t Banks;       2 K- @% c" A, J( l
  5.   uint32_t Sector;      
    5 p3 M/ `% K6 e' T, T' b, I
  6.   uint32_t NbSectors;   2 @4 k  w2 Y  ^
  7.   uint32_t VoltageRange;
    4 v+ d5 y% h* f; h0 i& n) M
  8. } FLASH_EraseInitTypeDef;
复制代码
# ?8 b6 t& |4 }- b3 F
下面将结构体成员逐一做个说明:, [# l$ V+ ?9 H3 o1 ]0 `% `9 g( U

: r0 R% I" T5 z! t. i% {0 k$ p  a7 R  TypeErase
" j/ s7 H  g" A& }+ v) A3 c! G! `用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:. Z# [0 F4 y4 Q7 Y
2 k7 F0 H, a( X6 z7 Z# p0 p& z2 G
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 */
    $ f4 ]( @+ `* v) c
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码
% a* i, Q! R" @  q+ S4 z
  Banks
3 E, v. l- A' t. b用于选择要擦除的BANK,或者两个BANK都选择:
  X, R' K* D/ ~- d* U! i5 r# Q% N5 c# O9 E
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */# s4 C/ g! g7 v
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */
    " F5 X% X0 m" [
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码
Sector8 t  e3 C2 t% i; r
用于选择要擦除的扇区:
! ^8 L; `. S3 d2 o7 d0 g+ H, E5 G: r) @  D' _0 o( r
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */
    % @3 y- C% U- _9 S5 h
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */
    : [7 E( O0 s: l  o' v
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */
    1 Z' K6 D; C' ^) f& o5 H+ p
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */
    " z6 v3 d; ^, @' w+ E% q  ?# w
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */; b9 W$ J! T& r2 T
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */
    ' p$ J# ^- D3 K4 i7 Z& K6 _1 F
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    0 Z9 n: X( ~: `9 C6 P; Q
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码
' F7 p& J# C9 F) R
  NbSectors1 a, ]& s! y3 U
用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。, H  U# s, T7 @

# g- d' v, W( e0 W  VoltageRange. d4 l- \+ u* t5 d* {3 v
用于设置编程的并行位数,电压不同,位数不同:9 e. z5 z; |- s; R0 Q. a6 H, w

$ E8 z; V" p, ~/ _
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */
    5 _2 @# u( f6 c( A
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */
    3 e1 u5 o% k+ F$ ?
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */3 N& J( v5 h9 |- S
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码
% Q8 o' z- w' i( |" x3 U
70.3.3 内部Flash的操作总结, a) `/ w9 U: U: r1 Q
使用方法由HAL库提供:8 k& t- n/ y# S
# c- H4 X: b& \8 F: u2 ]
  Flash编程函数操作流程
* J/ T8 a3 M% k; r  z  Flash解锁函数HAL_FLASH_Unlock。3 K6 K# B% C( Y' W& i, @
  Flash查询方式编程HAL_FLASH_Program。- x9 F$ `* E! L8 ~' b- |- C& @
  Flash中断方式编程HAL_FLASH_Program_IT。
% O$ Y6 b% C' f6 Z. q4 k0 {  Flash上锁函数HAL_FLASH_Lock。, O9 v7 W1 |: J; b" X
  选项字节编程流程
7 h# O/ p& h/ }/ _3 `! F1 _! b( T  选项字节解锁函数HAL_FLASH_OB_Unlock。$ \9 t: ^( w8 [0 l1 C: _3 e
  选项字节加载函数HAL_FLASH_OB_Launch。
1 @: Q0 A* p& o: S- }4 Z  选项字节编程函数HAL_FLASHEx_OBProgram。  S( C; L' S. P4 D7 W
  选项字节加锁函数HAL_FLASH_OB_Lock。! X, |- u5 i4 R* Z3 M6 T
  Flash擦除流程
2 q, o; a; L" b( C  |, e& s4 U+ y( {  Flash解锁函数HAL_FLASH_Unlock。/ o; v- y% `, n
  Flash查询方式擦除HAL_FLASHEx_Erase。
: N7 |/ n( r$ b3 t9 ?, O+ a  Flash中断方式擦除HAL_FLASHEx_Erase_IT。
) w# g9 g3 i+ w+ U! @5 \" @  Flash上锁函数HAL_FLASH_Lock。: d* p! Q# H- j
70.4 内部Flash源文件stm32h7xx_hal_flash.c' y6 `/ q/ k2 \' y8 f4 h; X
此文件涉及到的函数较多,这里把几个常用的函数做个说明:
/ `; m& o& \, ^3 K  HAL_FLASH_Unlock, G' P& e5 ~0 c4 k3 h" ~- z. u
  HAL_FLASH_Lock
3 }9 m. T: [1 h* I  w/ ^1 y& x- n) n  HAL_FLASHEx_Erase
" V1 R3 b! [" w. c! z; I  HAL_FLASH_Program) E) T* e0 e1 A5 f3 t% ?0 \
70.4.1 函数HAL_FLASH_Lock
  A  x0 y4 ^0 A函数原型:9 m* R  U' ^" F. F( {

, S& v3 `5 f# B. U. K3 c/ t
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)
    % H8 o5 Q' ?- a; w  I. U7 ~
  2. {
    2 A% h/ u% J, @% |& o# ]6 z
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */
    7 m8 Y4 z- V7 {8 F
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);3 d7 O6 A- q: g* x( Y
  5. 4 e7 K! z6 c$ v3 `
  6. /* 验证Flash Bank1是否已经被锁住 */! d9 |0 |3 q" Z  y- A
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)$ i2 |5 _: @' F2 A9 U+ J
  8.   {! ]8 j' b6 K2 H7 Q5 K. F
  9.     return HAL_ERROR;4 h7 ~: s" l- ?5 }- |
  10.   }
    ) q' K( X: P9 t  l( b6 f% L# q
  11.   d6 N6 q9 ]% A$ D) l( ~6 u
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    ' D) w, e% d3 Z% `" Q
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);- I, Z+ x( o. s, e0 ~0 b  J
  14. 0 n8 K' ~/ C$ H8 h7 n
  15. /* 验证Flash Bank2是否已经被锁住 */
    ' P0 i9 ~; L. [6 v" `& J4 B
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)0 B1 c$ s/ j9 T. y: s. i6 \
  17.   {* o9 Q' e$ h. z$ ?) h) M
  18.     return HAL_ERROR;
    : u% h/ t9 G5 p, B6 A+ q
  19.   }( F( ?! n. u" W5 Q+ l& o
  20. ( e- _2 q6 y2 X9 t4 s; B5 k
  21.   return HAL_OK;
    , d% w3 l3 \  n- ~- [" t$ m
  22. }
复制代码

2 p6 u( I9 g0 Z7 }* ?% }' N函数描述:: V( R- Q) M& i. {- l) D% \( ?+ k
4 \2 l( M' c& U' C" @9 Y
用于Flash加锁,加锁后将不能对Flash进行编程和擦除。
( B" ~- s/ }0 }, S: f/ J! X& {9 o) m1 F2 s; R
70.4.2 函数HAL_FLASH_Unlock3 O: d7 u. m& h- i
函数原型:1 Q  ?1 V8 |7 V3 i6 d
. f  a& N% D: l# O) p
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void)
    3 D) s0 _" N+ ]4 m. j  C
  2. {
    9 C1 m1 v7 N1 s& j+ K0 Z
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
    ! D4 ^; R& D, V1 w( h  Q. `1 h
  4.   {
    ! k8 \5 m8 j+ ]0 N2 P" q
  5.     /* 允许访问Flash Bank1 */
    6 m" F2 R9 l. _
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);
    8 O, [. i0 l* e* W+ A5 k5 |
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);, x. e: d  V! u) ~. ?; |/ F# h- q

  8. 5 ~" w! s1 r' h# A0 h: X2 A
  9.     /* 验证是否已经解锁 */
    ' ~& z8 q$ r2 }& m% H5 D" O. p/ S
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)2 s* `2 A$ D6 O5 q# j
  11.     {
    ' r$ X7 D. h7 e0 Y! @/ e
  12.       return HAL_ERROR;
    . i: v0 v8 L1 l) C0 c% M1 r
  13.     }) r" g+ ~+ }* W" P
  14.   }5 A* _# R" l8 H1 v9 H3 q- P3 a1 |0 G
  15. - r7 c) m+ x/ C' I% j2 N  _! U: c
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    1 s( c& m) O& |" H
  17.   {, J+ S1 Q# K7 z' z) t
  18.     /* 允许访问Flash Bank2 */
    0 \9 i" D2 z& J% |* f, X
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);4 v% G9 Q8 [$ W0 r" o( G& b3 e
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
    4 k3 c- W. r6 p; x# a' B  @

  21. 7 e$ O: w* k% r# G" K, s8 @$ ?6 w3 w
  22.     /* 验证是否已经解锁 */6 Y2 U& R/ t$ e" o
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    " m& g" r+ O# U! T
  24.     {
    6 y6 ^# F- |# r( |% I* D
  25.       return HAL_ERROR;2 @4 m* d5 |3 p7 A5 f2 e
  26.     }
    0 z3 d' W1 \3 w# G5 u0 p
  27.   }
    / g# Q- q9 o5 {- u8 D# L8 r

  28. " T8 x/ c! l* D
  29.   return HAL_OK;! O" A( X3 w) X" c/ ^+ ^
  30. }
    ! O  k5 Y8 i7 G8 g& M5 a* D3 [0 ?2 q
复制代码

3 C' x* X' O& ?1 ^+ T4 O7 J% [
+ U4 ^( V  {# a4 t. O函数描述:3 {, m7 O/ a/ i! ^% }
0 }9 K6 M8 K: `* Y2 v9 S
此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。/ i1 P! Q* i% K( H$ M$ q# ^" m

  q6 B8 }8 P# v* c$ s9 q70.4.3 函数HAL_FLASH_Program
# z$ ?5 {8 B  \- E0 w函数原型:" Y* l8 D- ]2 ~% n/ P

& i: x4 ?0 F7 w# v  J! Q! U
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)- Z, i1 `9 z' ?, p+ f
  2. {
    " _7 z+ r' u0 t! w8 W
  3.   HAL_StatusTypeDef status;
    + b! N+ r, K( f0 D- O7 B3 b, A
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;
    % i9 h# d* z% `' ]
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;  ~6 J: P8 H) R9 S0 d. Y9 O) V/ ~
  6.   uint32_t bank;* b  B% ^* c9 u
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;' g$ o% P- g% l8 Y- F: u, [

  8. . n9 O1 |; P6 V" M9 e
  9.   /* 检测参数 */3 V* F, d' ~) K2 g0 l9 [: f
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));& H4 y8 C* Y1 V/ n, Y, C
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));
    / D+ O4 G! v0 Z! h' r

  12. ) o* r" h1 _) _, a/ `3 e
  13.   /* 上锁 */  U: o- `" D' i* h9 R! Z8 |3 D
  14.   __HAL_LOCK(&pFlash);
    + X# I$ V- _( {; n# E& e# j: z, c
  15.   A) T: a7 ^- [/ X
  16. #if defined (FLASH_OPTCR_PG_OTP)
    7 K6 `( b. K8 }4 L0 v$ g( M' e
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))# L# y! U8 Q& i* ]$ I% ]
  18. #else
    ( D# c, {0 u$ c/ ~% Q* \- k$ I# }
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))
    5 N4 e5 n0 P9 P) j# T! K* ^
  20. #endif ' j, J- e/ [" N0 _
  21.   {5 e& g* k! K# G- T: k3 u, c+ b
  22.     bank = FLASH_BANK_1;
    1 H& M( [/ z! |8 m' `
  23.   }( n4 e& c, Z$ w2 ~! s
  24.   else
      w' Z5 R: h- v3 v: u$ B2 o3 L
  25.   {
    4 q3 \" ?0 Y, P. A# E8 B
  26.     bank = FLASH_BANK_2;4 Q0 U8 Z0 Q: r+ w
  27.   }& Z0 g! O2 X4 |' `  r

  28. ! i% K) y& b( Q! l, h8 h% D
  29.   /* 错误标识,无错误 */+ W' _% v4 r9 Q* n
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    8 m* p& X7 i' l" {5 ]8 a! t
  31. & v. W& k9 p) m3 `1 Y
  32.   /* 等待操作完成 */( U0 K# x2 ^: _
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
    $ s3 A- y# t0 I: Q% ?

  34. . k. [+ O3 p; j0 [: f7 i% t
  35.   if(status == HAL_OK)/ U" y4 ~( K( v8 {  I
  36.   {
    % p5 U& v- l: k# y
  37.     if(bank == FLASH_BANK_1)( H. d% o1 D* l; a
  38.     {
    3 L& `- ^8 H6 O6 g5 z5 J
  39. #if defined (FLASH_OPTCR_PG_OTP)* z* e- O3 l6 }9 r; ?
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    ( H% i5 a+ w: v# w: c: u" P) d
  41.       {
    : O% m6 D, b2 Y- y9 D
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */
    8 @% k; L) j+ c' ?5 u/ X
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    + \& p, q# e& B3 j
  44.       }, R$ F9 D1 f8 \, S) O9 u) i
  45.       else( f& P: Z3 K# p- Y- K5 F$ q
  46. #endif " m8 y) Q' |! e- O6 o/ z
  47.       {
    " u/ L) B5 t: \5 z% `3 P5 }2 z
  48.         /* 设置PG位,使能可编程 *// n/ U5 V. _- F( z" h
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);
    % a- c; `; b7 j9 c" J& r
  50.       }
    & z, W7 Q/ f- k0 Y2 e
  51.     }
    5 N4 c: Z5 k" s
  52.     else( s2 B  l1 S9 F3 r2 I" f
  53.     {
    0 s1 G2 N% J; V/ z. C% S
  54.       /* 设置PG位 */. I' z4 G2 v" Y# w. I. N5 V
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);
    " \: w6 B+ q+ L" {) P/ F9 b6 m6 c
  56.     }$ k" a1 h1 f8 X1 l4 k+ o: h
  57. * n. |& L, @. S# Y4 l) p+ `) u
  58.     __ISB();
    % ~9 a/ Y* W9 m. B# |$ u! E2 \
  59.     __DSB();2 I$ ?1 N: }0 m
  60. 8 s3 G8 \- v7 L5 R! n8 a& t8 b  L
  61. #if defined (FLASH_OPTCR_PG_OTP). k1 ^. V) L& M" x, G* ?  X( w
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)% @1 n# h) q; W, D
  63.     {
    # H$ w% w7 H8 @
  64.       /* 编程OTP(16 bits) */
    : F6 Z& Y8 i1 G; v$ U1 e
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;6 a! Y' ^1 ?* P2 W/ l. }$ S2 m
  66.     }
    - ?; F% W  I1 d' N; i
  67.     else2 Q% T7 o/ B4 X0 n
  68. #endif ) y: G8 X, A3 `4 x
  69.     {0 q' O( f" _7 M" T
  70.       /* 对Flash进行编程 */+ z2 f" O: j3 v# [
  71.       do6 J' y+ |+ Z7 u0 H
  72.       {
    # e/ v7 y$ M  V/ V8 R0 [1 F' e" P
  73.         *dest_addr = *src_addr;
      j: ], W9 [5 m6 g2 y& B. X7 u& ]
  74.         dest_addr++;
    ' Y; d" [# A) I# j- h
  75.         src_addr++;
    0 X# ]2 t. X; S* Z
  76.         row_index--;% C9 A1 l- Y0 Q$ T+ f
  77.      } while (row_index != 0U);6 o6 B* \; Z% z( o6 y
  78.     }: ~" f5 n  @/ j4 I% i
  79. * [3 ]7 p2 v% M& e
  80.     __ISB();
    $ s8 l& W9 l, H2 K4 `5 o
  81.     __DSB();, [+ `2 m% d& \
  82. # m/ A) o; |. F; Z( K6 H7 S
  83.     /* 等待最后一次操作完成 */6 v- T! w) M  T) f! ~$ J1 d4 g
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);
      Q. c# B  C' Y

  85. 5 l8 x$ b9 I# Y
  86. #if defined (FLASH_OPTCR_PG_OTP)
    # M7 |6 |7 x6 t3 E" h. u
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)0 B" h9 G3 C$ P, ^
  88.     {
    # v$ }5 t- ^" u( H! Q
  89.       /* 如果编程操作完成,关闭OTP PG位 */6 k: [& T! E8 i1 e2 d0 |, W: W
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    / n0 r! h+ t$ Q  R7 x/ |# a+ Z! H
  91.     }
    5 o: J* }4 U0 u, {9 n, [  Y
  92.     else" K* i0 E6 \0 c0 v
  93. #endif / ]4 J8 v- e3 \' d, Q
  94.     {# p/ t! X' V' E0 O
  95.       if(bank == FLASH_BANK_1)* J1 W5 z- u* Q: e$ N( }
  96.       {" ?$ T( a1 F4 O- s
  97.         /* 如果操作完成,关闭PG位 */
      G9 F0 U- Z0 l, d$ T, x  }. Y' t
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);: S# ?' B0 O6 s, b- j. g1 Z
  99.       }
    1 P  D+ ]; ]1 K5 v1 q
  100.       else( b- j2 I, h# t$ w5 C* D0 q
  101.       {% n! x( Z( l: u$ s% G
  102.         /* 如果操作完成,关闭PG位 */1 j1 u  u" ~% }- i$ r% e4 T3 ~
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);
    ' c1 H; a' C, S+ S
  104.       }
    + J0 V! F  @0 r, E* @1 n
  105.     }; n: N: D, z- a. X( ?
  106.   }
    6 `( t0 V; o4 j- ~

  107. ; ?5 Z+ c. [& Q' k$ y
  108.   /* 解锁 */
    3 g' m1 U- |+ v- k: t
  109.   __HAL_UNLOCK(&pFlash);" ]- h6 z: t5 @; a+ [5 C  ]# r8 ]

  110. + G" {4 H" o% h- W, Y; E9 d
  111.   return status;
    4 H. F  q: G) Y! O. i' z+ i
  112. }
复制代码

) |5 I6 h; ^5 u, i  ~9 c7 G+ L7 }! l8 ?

- f: S- Q* t( g( @2 m6 p/ |8 r$ a函数描述:
9 J  M0 B0 T+ e1 j4 B- X& C
9 C7 |. L7 C% ?% P$ {/ y此函数主要用于Flash编程,固定编程32个字节数据。2 U8 l7 H" F) j; z2 F5 y

9 j3 g! ?6 X, I; A- Q( Q" m函数参数:# g9 M1 i! m4 r& [% o! Y

9 ]- f% E8 A2 C1 Q' n, {' o, q  第1个参数是要编程的Flash类型,支持两种参数:
* Q4 [7 c9 F+ Y- d! A; U1 B  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
: @6 w8 }+ {% {: R( N( v  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。& K' x% s# Q- q# Q$ D
  第2个参数是要编程的Flash地址。2 ^# D2 {- {* A: k
  第3个参数是要编程到Flash的数据地址。
* g, D# a! c) F+ P+ m  K/ z  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
  N3 g- E: g3 B2 K# x4 m3 \注意事项:
% z  {$ w6 q  z5 d$ X" I, r' r
  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。0 H+ l# N. O! u
  第3个参数务必要是32字节的整数倍。
5 m* u; Y3 Y; s  M/ Y% P+ R70.4.4 函数HAL_FLASHEx_Erase
9 g1 a5 Q: Y8 G1 C函数原型:
$ M4 r" |  \8 f. y
; t% j' d5 \% L3 `# X; c/ C
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)0 u# c' L$ g0 a5 ~' K
  2. {" E0 z9 w/ \/ {
  3.   HAL_StatusTypeDef status = HAL_OK;
    8 E# u3 q: t  O1 L% V
  4.   uint32_t sector_index;8 I( Y. m, R' K* D
  5. 6 ]$ }( c7 ^. r. t. A1 s  m% S5 H
  6. /* 检查参数 */* B+ W! ?5 c3 ?3 r/ m+ o
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
    ' d! {* U3 b0 c( U
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));
    + H$ R/ E+ M! }
  9. 8 l/ g: X" O% h% [; B
  10. /* 上锁 */- ]4 h, h( D' ?$ U
  11.   __HAL_LOCK(&pFlash);
    4 J5 E1 H- w3 i0 N

  12.   A0 F" U: w% T5 K$ S  O
  13. /* 无错误 */. d% d6 b  j( d! Y' z
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    2 ?+ B% m' _+ h+ u7 z" K

  15. 7 t- W+ i! p% }9 e5 G
  16. /* 等待BANK1的操作完成 */
    & r* m7 H; F; S
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    1 S5 @9 S3 L+ r% |0 h! F
  18.   {
    ! M9 Y: ?8 \8 x7 _9 F: ^/ O
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    % y) c5 R' a; C6 R1 C
  20.     {9 u! g! g% _( ?. [3 T4 @4 ~3 W7 M
  21.       status = HAL_ERROR;0 Y" B0 u8 T- h5 Y- t6 j
  22.     }) I1 c/ ^. G( X5 h
  23.   }
    ' m% U) K2 k1 S0 R& d
  24. $ a7 X8 `- [4 Z6 B
  25. /* 等待BANK2的操作完成 */
    6 R! [3 k+ m# b/ }+ M" p6 R4 C3 I' x
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)3 r0 m! I2 Q  A$ B- y1 f9 g
  27.   {: U1 v% ]' v/ Q3 ~0 R9 |
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)1 `/ O" R) }  P  t$ I; H
  29.     {
    # q8 m# Q. E/ E/ y4 M
  30.       status = HAL_ERROR;8 z+ e* |+ K; e- z) b
  31.     }- K4 C( y& w& k  ?
  32.   }- Z1 K" s' c( c+ A. X3 r( F7 J' y

  33. , @6 h1 n  U1 `6 @  q9 j: d; h
  34.   if(status == HAL_OK)3 J2 ^7 g- }; D3 c% y" }: M
  35.   {" y5 r0 O7 Q" V9 x$ A" k  [
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
    & D; V& V: i: N* h
  37.     {" s  |! z0 y# j* [" m/ C
  38.   /* 整个BANK1或者BANK2擦除 */0 M' M) u3 ]- P$ \2 K+ i- i* E
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
    . u9 q+ L# P" y" n( ^4 A

  40. % o1 Q- D5 O6 m5 ~4 p. w3 P6 t
  41.   /* 等待操作完成 */
    , I4 {$ S; b% _1 \4 {: X# W
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1): k1 K$ q. x* W9 C  @! I4 S
  43.       {
    $ o& a' M; O# a& ?" J8 l9 {/ u( H
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    " a2 U) g5 K. P2 [% s
  45.         {
    ! [$ c+ S* J! o: r$ U  ?$ _
  46.           status = HAL_ERROR;2 Y7 k5 l( V4 s2 Y
  47.         }- k' U! v6 X: D4 V4 }
  48.     /* 如果擦除完成,关闭BANK1的BER位 */& z" \! H4 t, d* u' J* S
  49.         FLASH->CR1 &= (~FLASH_CR_BER);& Q4 Q8 F; G1 ]8 u
  50.       }
    4 C: i) `! {* C" s+ @7 t+ G
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    + J' `7 p- g9 h) o6 r- ]
  52.       {! i- i! X: \8 ^. S* z5 E: o
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    ( [. M! D3 H2 A( t" q( G$ v
  54.         {; g8 ]: G. e( M/ j% {" G
  55.           status = HAL_ERROR;
    5 }5 X3 p8 ?, |' r! W  D
  56.         }, c2 _) h; g7 m$ d' K' o
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */
    ' l% a9 }5 @8 V& p. d1 j- M
  58.         FLASH->CR2 &= (~FLASH_CR_BER);6 o  z. o& S, \1 T
  59.       }
    & P. P! q. U2 ]* n* b; m
  60.     }, M* F$ m/ e! m# P: U, l
  61.     else* F% D  Y7 \4 n  x5 f& w
  62.     {
    * a% B6 e1 Y; p0 w7 S) \7 f
  63.   /* 初始化扇区错误码 */
    * B. q8 G' }( T# }
  64.       *SectorError = 0xFFFFFFFFU;
    5 I! Z1 }6 m$ [+ s4 d

  65. " r* V! ^- ]  W7 m
  66.   /* 扇区方式擦除 */; h0 ]. z$ d) l* A5 |1 N( j/ R
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);
    - x0 ~$ J. {$ t1 Q  l- ?
  68. sector_index++)2 x# @. T: W* x
  69.       {' D0 [- q2 V+ j( ^; V
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
    3 a2 v4 X0 L0 s3 o& I8 z: R* @) k5 u
  71. 5 f9 n6 P" l' U) K9 a
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    0 R) @; ]" y4 O* E
  73.         {1 x- i6 C( k7 J
  74.       /* 等待BANK1操作完成 */
    - P. B& [. b* e) D- J6 h
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);, R3 y5 ]3 D, O1 ?
  76. * C1 R+ R6 \$ Y
  77.       /* 如果擦除操作完成,禁止SER位 */
    + x9 B- Y( B+ s. ?0 q2 E
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    $ J8 A! h* l: V! X3 D% |
  79.         }
    / L: i( B  J4 K) C
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    2 k. p" l7 [" [( `
  81.         {+ P* n: ?3 ^# F7 ?( H  O: [
  82.       /* 等待BANK2操作完成 */5 z* S5 V5 t& Z1 |+ X
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);
    ! r9 C6 }9 X2 d" J: Y
  84. 5 \9 T7 b: E# c; S
  85.       /* 如果擦除操作完成,禁止SER位 */& F( I  R: W3 [
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    9 o! P% O9 ^8 n" G9 T; q6 S8 ^
  87.         }
    - C: H" |* e5 z# Q* x, t; q; y
  88. 2 Z, |4 \4 ]1 `
  89.         if(status != HAL_OK)9 m2 b7 H0 ~- e- C
  90.         {9 E# }1 d, E: Y- h
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */9 O, P5 @' P1 [# c! I+ _
  92.           *SectorError = sector_index;
    + p( }0 `0 p" n2 S# M$ l$ G5 n
  93.           break;
    2 o. a% W4 O4 f
  94.         }' ?( {% f6 X" t2 g2 c
  95.       }) O/ s" @8 D7 @% v* J
  96.     }
    0 X  e0 C. B; l* k& Z. k
  97.   }
    7 c4 r6 O# n, f$ G- G# J

  98. - r' B$ s9 |( T8 i# n# I
  99. /* 解锁 */. S! i# z: B$ `# q
  100.   __HAL_UNLOCK(&pFlash);
    ) L. G3 r. h7 ^; i4 o/ \0 N% V

  101. ) \8 [8 y) f) m& K- d
  102.   return status;3 n) A: m2 _$ E' |' |# G
  103. }
复制代码
0 V5 }1 ]8 \( M( M) m& Z
函数描述:
, k' F8 ^# |( n) N- x5 U4 s! _  N- C
用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。* A7 J  v3 X/ v% l+ _
: \1 P6 a( `9 H! ~
函数参数:" z& u7 l/ X' V* O8 w- i. r
& a# p. [0 E6 B7 U2 [( R  |
  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。% L9 k4 ]4 z7 [" f' H
  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。' J. x" }" D' ^" g3 ~
  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
4 z# q/ K: h3 _1 ]; N9 l% l70.5 总结4 j3 O0 t: ?0 a( W" o% g
本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。
* d4 H6 O" l$ Y5 j
2 Y( v  T) e6 R. N' {% u+ ^
$ O( |" }  ]; A+ n. H
赞 收藏 评论0 发布时间:2021-11-2 23:53

举报

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