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

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

[复制链接]
STMCU小助手 发布时间:2021-12-19 18:00
70.1 初学者重要提示
  r4 G, L8 [; d9 X% E  本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
6 R+ d( D* v7 c! w  STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。( T8 }; j( |$ K% u/ F$ p
  STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。. n. ~: o2 k5 i
  HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。
9 E$ G0 m9 @. i( W) u  o* D  ]70.2 内部Flash基础知识
7 C" K; a' ]0 M2 V4 E* Z! R70.2.1 内部Flash的硬件框图

1 V4 E+ @: o0 F+ Z6 w/ F: N& y# l认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。: {, O: \8 f4 X, r. y. V+ ?6 E
6 `0 z+ A, d: B/ G9 O4 p% `, Q
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

: w, w6 ~; a* y0 m' u
" r+ x- N* W9 ]/ ~: v通过这个框图,我们可以得到如下信息:
# m2 x0 G3 `: g0 }. z# [/ Q1 ~& ]8 i8 h  v( Z# T# P, m
  sys_ck时钟输入
" Y' G. x1 q; `; I% L+ }D1域总线时钟。
. ]% z) ~# M7 v& c/ t1 w& B2 O( M' l2 W6 h' I. C
  po_rst输入
1 p) e% c/ ^/ u. m. o" E) I( |% d& yPower on reset 上电复位。5 }7 z) h8 ]5 v+ a5 A/ _
- O1 j2 H* S: O! a  U7 D; I
  d1_rst输入; p* }8 e; S9 a3 Y
D1域系统复位。
# ^9 ^, T3 B) h" q/ X* n  ^
3 u6 `/ w2 Y1 w% a3 W8 i0 c8 O! J  flash_it输出
/ v- e* Z& d2 T3 \6 [flash中断请求输出。
( p  i  {- [2 @" v0 h  n; r- N; V/ \4 v# R! f
STM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。
6 L0 T, ?2 F& t& E# n
# R1 w( b' F5 m" ]9 W3 M6 K70.2.2 内部Flash框架
( V8 o( a- x5 W( D关于内部Flash的框架,了解以下几个知识点即可:
& `" M8 G0 V7 a1 ?) m! ~
% p& g6 b( L- I+ E# e) S  256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。( O' E) D1 P+ F& d! F& p4 E
  两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。
: i  F. w& x" T5 I: S9 G# d5 Q; ^7 i2 ]! I! W% U1 s* _0 }) g
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

; W0 W) u2 h+ ~* l; w1 m
& t2 Q* u" H( oBANK1的地址范围:0x0800 0000到0x080F FFFF。
) D) D2 D4 ~4 G, q0 \2 L9 ~. W5 f4 j) y) w% _3 L# z2 _# u
BANK2的地址范围:0x0810 0000到0x081F FFFF。
6 f: g" V- t( u' `! K$ F- c- w' |) `( Y0 g) @
70.2.3 内部Flash读操作4 {4 J, f; R+ i. f+ p# Z0 u
STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:
6 d5 k! B9 l$ H* T/ j: o% Y, |- U* U1 y* R: ?  T
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
7 M! F8 B0 b! u
: k% y- l3 p  [" L6 X
对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。
$ D: R" ~# \- p$ [6 g6 u
. j: P2 m& W8 K, u了解了这个知识点后,再来看下面的时序,非常具有参考意义:6 Z$ V$ k2 o  L

) |# b9 i7 }1 U$ H3 q8 ^注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。
: x4 E& g& [2 X5 z( Y  q; S
) j6 V. W$ E& q, Q6 s' k
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

; N; `/ R; X2 J0 N+ Q9 _! y  k! ?" W' g$ |( L
关于这个时序要要认识到以下几点:
8 \9 L9 k5 D- f+ V/ [7 L
6 B' E0 U# x* P5 u" F  n+ P) [# `  AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
1 g( g& W; O& r+ t" y) v+ z$ |  由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
& G; E1 I9 R2 V# u7 U9 g; x  如果不开Flash Cache的情况下,连续读可以提升性能。  N! y8 g8 Y1 ^4 p
6 U0 i& Q0 V" X/ i8 \
下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。
1 i9 x9 }5 H% |( {$ i7 {2 `& @& z9 [! e2 j$ Y: h. K
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

. ]4 z& V) ]! f' x& o& W# _: U/ p6 m3 E; I
70.2.4 内部Flash写入和擦除操作" R  F, s: b- M, l  A
最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。
# k/ V# e+ @- V  G* b! {/ S
  q0 a* B9 r, R& q4 g/ M, \9 c这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:% T& z0 W/ e! p! f+ _# V  v: }

& M9 _, L& N( A8 P. {先保证这块扇区空间之前已经擦除过了。
( Y% f' R6 _7 m+ g" Z( v4 q( k解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。% z: b, K7 K+ m8 ^
检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。
# Y" A* k6 `# J/ D8 U
+ C# e) R6 X7 P% D/ `( TFlash的擦除流程如下:
# `6 L$ g' W' o, Q& O  G: |解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。% Z* q! [# E+ e4 w
如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2$ s6 t/ T7 x8 j1 a$ \# {
如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。
: t( `3 r; Z+ z. D% H5 \
2 U# F1 Y! s# m- p( p! E  t, b6 y) T  n
70.2.5 内部Flash读保护, c! Y3 C* `5 R. }' `
内部Flash支持三级读保护RDP(read out protection)。$ I6 x0 B0 w- g1 {, l! f

- F3 M1 G  U+ B  Level 0(无保护)# ?4 p1 M8 O+ }  f0 u( D
默认设置,所有读写和擦除操作都可以正常支持。
3 I7 K5 N( y; p7 T1 o1 q# k
5 |0 k- b1 l& S( X0 V: Y, X  Level 1 (Flash连接保护)1 G' e& ?8 u+ _
  可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
; f% `- Z( ^! ^) `) W  如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。
2 a2 \. U1 E6 O+ S/ u3 f- }  如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。
+ {5 `! k8 {" e# V
+ Y1 P7 q4 Y  H+ W; t: B1 d Level 2(设备保护和自举保护)
# b. P3 h, |( q" N, p  所有调试特性被关闭。
5 R9 v1 I8 K6 `' [: _& N  禁止从RAM启动。1 a* o5 ~+ ]% I5 s, B4 E. r/ I
  除了选项字节里面的SWAP位可以配置,其它位都无法更改。
5 P& U% j- `6 r+ L& O$ k; U6 W& p  禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。) g$ ~% U* F, |  r

) g  R* G# K& @/ s, X# ^  _特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。! s9 E) o; {: d) n6 k! X, Q5 l$ W
" v5 J. [3 u! H8 {: n
如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:
1 s. ?* o+ P* G4 j2 d, c
+ w! G9 ]8 x. q3 z
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
5 s4 k& @* E0 j5 A+ _4 B) \

. f7 I1 K" d' E( R" a; U4 H" H, c& V+ q+ t$ R" \* ~1 e5 h
70.2.6 内部Flash选项字节
/ L0 _  @. }- B' J( E" zFlash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。
- i: f. m# f4 q+ a, T7 {
8 s* U- {" T% E1 r4 v
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
3 _& F9 k- d% @' W) ?# a

# V( [+ V7 j0 u" H* G; C70.2.7 内部Flash的ECC校验: |3 X$ A+ i5 F! i5 T! O7 K* J
这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。
/ e# m- [. F+ }$ l5 s, R* t0 u, d) W! y
对于STM32H7带的ECC校验,一般不需要用户去管理。9 M2 O4 e! X, U8 g* y
& S3 [0 C) b$ v! O6 e; t8 T9 m
70.3 内部Flash的HAL库用法" p* j! U1 x3 W  w
70.3.1 内部Flash结构体FLASH_TypeDef, Q0 |1 ^# i( S* B  l
内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
5 i6 l, Q/ `* V4 f& Q% z$ U8 j" i$ [' S" Z2 Q" }$ D* A. N
  1. typedef struct
    % D8 j7 ?  M1 c5 d' `
  2. {
    - i7 B; Y! |% N( k. i
  3.   __IO uint32_t ACR;            * ?* Z+ A$ n& M1 ^% p2 a* \: F' `
  4.   __IO uint32_t KEYR1;           
    / V3 P4 v8 c4 [* h; ~1 P
  5.   __IO uint32_t OPTKEYR;         0 ?7 c5 y% {: w- J; j) J0 {
  6.   __IO uint32_t CR1;            , L$ G8 [/ i7 B# x) J
  7.   __IO uint32_t SR1;             . z0 t' ^( w1 H  I1 z- C
  8.   __IO uint32_t CCR1;         
    ( n; o+ Q/ g4 a
  9.   __IO uint32_t OPTCR;           # U- ?" P0 h5 [- c! U( `
  10.   __IO uint32_t OPTSR_CUR;       ' {; F; }2 n  Q# A0 q" G
  11.   __IO uint32_t OPTSR_PRG;      
    / N; o. ]0 o3 O
  12.   __IO uint32_t OPTCCR;         
    / u& x- q% {7 K1 a2 o
  13.   __IO uint32_t PRAR_CUR1;       ) Z8 q# K4 C" E' k% w
  14.   __IO uint32_t PRAR_PRG1;         T: J, X5 t2 y) e$ Q6 H
  15.   __IO uint32_t SCAR_CUR1;       " p8 R  b9 T1 R" J/ r! r9 V& T
  16.   __IO uint32_t SCAR_PRG1;       * I7 q, t/ h1 g5 L0 K
  17.   __IO uint32_t WPSN_CUR1;       4 Q6 C' @% h  e) D5 H3 K7 {
  18.   __IO uint32_t WPSN_PRG1;      
    4 q2 I# x7 B# J, d8 H
  19.   __IO uint32_t BOOT_CUR;       % I0 M! n% O) ?1 [
  20.   __IO uint32_t BOOT_PRG;       9 w' s" {: `8 I8 @. z4 @
  21.   uint32_t      RESERVED0[2];   
    & w# }) K7 Q% T5 B* f$ P
  22.   __IO uint32_t CRCCR1;         
    " }1 m$ k1 _6 p7 e4 G8 n
  23.   __IO uint32_t CRCSADD1;       & O- L! O, t2 D6 o" ]) _2 J! w9 G
  24.   __IO uint32_t CRCEADD1;        
    ! U) K  Z6 b- G# G. x! e. o6 ]
  25.   __IO uint32_t CRCDATA;         
    & T) Z/ n$ w; N* O( _
  26.   __IO uint32_t ECC_FA1;         
    ( b' h& X+ H( c/ J: L
  27.   uint32_t      RESERVED1[40];  
    / C- o& G1 d& z4 W- s
  28.   __IO uint32_t KEYR2;           3 O5 U" a3 A+ o; Q( y  ^
  29.   uint32_t      RESERVED2;      / q5 M7 A# D$ A+ V! B
  30.   __IO uint32_t CR2;            
    . G- s! V/ G0 M: `
  31.   __IO uint32_t SR2;             ) g0 E+ K$ _& ]% a+ S: I
  32.   __IO uint32_t CCR2;            
    8 @* t6 L4 `8 V' ~5 B' W
  33.   uint32_t      RESERVED3[4];   
    6 S1 `. A4 G- K/ }$ C
  34.   __IO uint32_t PRAR_CUR2;      
    / q7 b* w: t. X5 W9 u9 C" e
  35.   __IO uint32_t PRAR_PRG2;       . r/ {6 Y0 i" F! k
  36.   __IO uint32_t SCAR_CUR2;       # w# ^5 c; P% F8 `; D* U
  37.   __IO uint32_t SCAR_PRG2;      
    " h4 k  ]" o3 C4 @, g+ Y
  38.   __IO uint32_t WPSN_CUR2;      
    ; P3 ]* p9 m9 A+ ^, l- o: U3 J  S
  39.   __IO uint32_t WPSN_PRG2;       8 N; G/ d" _$ K- |. _
  40.   uint32_t      RESERVED4[4];   
    2 {- J& p. [+ w0 L7 ^6 h0 x" w3 D
  41.   __IO uint32_t CRCCR2;         
    . b5 I+ k' b2 C" _! |
  42.   __IO uint32_t CRCSADD2;        
    ) H3 I$ n8 V7 D! K& b/ a
  43.   __IO uint32_t CRCEADD2;        5 i  V1 ], ]# [2 Y8 w- s: O1 Z& M% t
  44.   __IO uint32_t CRCDATA2;        
    3 r- N" L# ^! Q  U# w4 h9 ]0 c
  45.   __IO uint32_t ECC_FA2;         
    " T: }: e' A: h+ F
  46. } FLASH_TypeDef;
复制代码

* }0 u( x* w5 S1 `9 p3 @' D0 P这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
* @0 P$ ?; d6 s+ C8 h1 [; k
+ T# c/ ]; L. `5 q3 g4 P__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
% X( y- J% `0 d; R
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */; s6 e: Y& g, r" Z. Q9 d& R
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
- W" d* a' L$ l% j. V- o5 b
下面我们看下Flash的定义,在stm32h743xx.h文件。
% `3 @3 ?) d5 `5 p8 S9 J* s# X9 i0 ^# J- n9 |6 s6 @4 [
  1. #define PERIPH_BASE              (0x40000000UL)
    . j, p) ?* A# g
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000UL): G  o% N+ O! s+ r8 v& K( w: U6 K8 m
  3. #define FLASH_R_BASE             (D1_AHB1PERIPH_BASE + 0x2000UL)3 i9 P% j# ^! n/ |( a
  4. #define FLASH                    ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000
复制代码

: b: m. l/ J5 K+ l$ P, [5 r我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。9 E0 @9 V& V, u. J" b1 Q4 ?9 H

# U) g! ?: Z7 S- R  x70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef
3 [! ]* F) x8 o9 }8 T下面是做内部Flash擦除的结构体,用到的地方比较多:" \" M1 }6 N. C

( ^: Z, o' Z8 i" w8 k4 Z! e8 i
  1. typedef struct/ @( M. J. m: y
  2. {) v$ N, `' E* R" s7 e: [0 I& `( B
  3.   uint32_t TypeErase;  
    # ]* s" ~9 K1 ]* Z, l( e1 R; h* z
  4.   uint32_t Banks;      
    0 \0 Q: e( H% m% h; D% ?
  5.   uint32_t Sector;      
    + `2 V; T" w$ G0 P+ r
  6.   uint32_t NbSectors;   
    3 o- S/ r5 q+ l3 I. L, d+ p
  7.   uint32_t VoltageRange; / u) m  ~, W4 B% _6 {) Z1 n
  8. } FLASH_EraseInitTypeDef;
复制代码

6 s1 m+ W8 Z+ |- n" p下面将结构体成员逐一做个说明:
* l5 I+ Y) n6 X1 E, A. }  TypeErase
. W  A0 n: x& N/ A. A
# y, p  W5 [; {+ R; t+ c( I2 X6 T
用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:1 \# v1 z: V7 C$ H' d; E0 e) g: \. e
$ ^4 P8 a' Z$ A* k! `& x+ y
  1. #define FLASH_TYPEERASE_SECTORS      0x00U  /* 扇区方式擦除 *// K, S* i! o1 v0 a: w0 D: A
  2. #define FLASH_TYPEERASE_MASSERASE    0x01U  /* BANK方式擦除 */
复制代码

) \3 o1 I9 r8 u+ E5 ^/ e& p  Banks
6 |& p2 O& N/ u% g6 y用于选择要擦除的BANK,或者两个BANK都选择:
5 X8 ?9 s2 O, G0 |1 S3 S! d/ o. m; c+ t; x* I
  1. #define FLASH_BANK_1             0x01U                         /* Bank 1 */# A# a6 c* m$ v7 _- h' x* u
  2. #define FLASH_BANK_2             0x02U                         /* Bank 2 */
      u6 n5 x1 c  T2 ?6 J
  3. #define FLASH_BANK_BOTH          (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */
复制代码
% [% k( i4 e% u* g% ^
  Sector, U' Q7 I% d( ?1 D/ R
用于选择要擦除的扇区:* C6 M3 e5 X, Z# R+ V" z! @
  1. #define FLASH_SECTOR_0             0U       /* Sector Number 0   */) n( [; B; X- S, O0 _, ?1 W
  2. #define FLASH_SECTOR_1             1U       /* Sector Number 1   */* {2 J$ m! F$ D- N2 F7 N
  3. #define FLASH_SECTOR_2             2U       /* Sector Number 2   */+ X% d5 f/ ~; z# q4 }! ]
  4. #define FLASH_SECTOR_3             3U       /* Sector Number 3   */5 l0 C4 c: p* E$ `2 w
  5. #define FLASH_SECTOR_4             4U       /* Sector Number 4   */
    8 i' {/ X. O& I: [- Z. J% e! k
  6. #define FLASH_SECTOR_5             5U       /* Sector Number 5   */" T) \8 V; `% |. A: m
  7. #define FLASH_SECTOR_6             6U       /* Sector Number 6   */
    + o9 E  s# C7 _& T( v: r% x. g
  8. #define FLASH_SECTOR_7             7U       /* Sector Number 7   */
复制代码

5 A* Z, N; U' X/ r4 c* w. U1 a  NbSectors) |1 z9 `# p) Y$ F  m: c
用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。( i+ f" F+ q: A$ `$ M

0 ?8 E  \! ^" j% ?  VoltageRange( ~, E' F& [- b- |
用于设置编程的并行位数,电压不同,位数不同:1 t5 b4 Q' @, ^2 u* u/ \% i6 m
  1. #define FLASH_VOLTAGE_RANGE_1        0x00000000U       /* Flash program/erase by 8 bits  */% Q& Q* O  Z: Y: D- r  ?% @  K
  2. #define FLASH_VOLTAGE_RANGE_2        FLASH_CR_PSIZE_0  /* Flash program/erase by 16 bits */: x* b7 d6 A8 n2 p; D/ Z! f- d
  3. #define FLASH_VOLTAGE_RANGE_3        FLASH_CR_PSIZE_1  /* Flash program/erase by 32 bits */
    2 ]+ T1 q  x$ y3 W0 N/ U5 O
  4. #define FLASH_VOLTAGE_RANGE_4        FLASH_CR_PSIZE    /* Flash program/erase by 64 bits */
复制代码
8 x. @3 N3 d, X8 l" z

7 `. M! {& V/ s; i1 Q7 d70.3.3 内部Flash的操作总结5 V7 }# p8 B; A. A7 ^' ~

5 {  p% R6 ?9 Z2 O& [2 s" [& ]2 K! A- B6 R% G4 }9 A- g6 s
使用方法由HAL库提供:: Z. c! I( w5 S0 L7 l
  Flash编程函数操作流程$ i# L4 k7 g# O  j- {9 H* A
  Flash解锁函数HAL_FLASH_Unlock。
5 l. }9 T, X6 A* h  Flash查询方式编程HAL_FLASH_Program。
" A: A" T2 D2 r& a0 ]4 ~  Flash中断方式编程HAL_FLASH_Program_IT。# l6 O$ V( z" B2 O8 [$ s; ]
  Flash上锁函数HAL_FLASH_Lock。
2 S; S$ F2 _' i" r  9 j. w. c9 _- p/ Y
选项字节编程流程% x  ]% @" Y5 Q9 q6 d( A
  选项字节解锁函数HAL_FLASH_OB_Unlock。
# d$ j" P0 Z$ i* {. d  选项字节加载函数HAL_FLASH_OB_Launch。, S! C' ^- K4 G: N9 ]
  选项字节编程函数HAL_FLASHEx_OBProgram。
  S7 @7 P, e- N4 J3 `0 E  选项字节加锁函数HAL_FLASH_OB_Lock。! b. ~6 K7 d# k* I

+ J: N+ x- P) q  R2 a4 c9 Q* y Flash擦除流程5 I5 z- w5 ~4 y
  Flash解锁函数HAL_FLASH_Unlock。8 O  N7 O: X+ |, i, B; C6 y8 L6 w
  Flash查询方式擦除HAL_FLASHEx_Erase。
0 y4 b! p0 T) g4 Z9 M' e6 [  Flash中断方式擦除HAL_FLASHEx_Erase_IT。& D* `* }  ]3 d
  Flash上锁函数HAL_FLASH_Lock。
8 P# @- U' P. l0 B7 @  N% W8 n# Q/ C: P) `1 A) ], a" n& f

; @8 A- T, W9 A9 J70.4 内部Flash源文件stm32h7xx_hal_flash.c+ K# \) G  \3 }8 S  U. {
此文件涉及到的函数较多,这里把几个常用的函数做个说明:" y" v+ {( v5 `& n( B( s5 l
  z; u9 J/ \; c/ N* N
  HAL_FLASH_Unlock. m3 t& d( s3 Z. z( Q& m3 n" O0 [
  HAL_FLASH_Lock
, \1 ~6 M+ ~% s' F5 Y  HAL_FLASHEx_Erase5 I2 `6 H$ D+ y& K  u% @
  HAL_FLASH_Program% e, W7 `3 \& ^
; P9 ?8 {( ?% ^" Q5 u/ ?: ~
70.4.1 函数HAL_FLASH_Lock
# }* F; x1 L; @- r0 x0 c) D8 K! A函数原型:
3 r8 K7 V+ K' \5 k- w3 L1 {5 J( C% i1 w6 N% ]8 q
  1. HAL_StatusTypeDef HAL_FLASH_Lock(void)5 B7 ]/ s* g- u0 [' E& l( J) L8 K
  2. {
    % U. i+ q) s3 Z+ U  _* D6 f
  3. /* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */1 d7 s& Z2 o! Z+ N5 L* K2 z9 P. d$ ~+ \
  4.   SET_BIT(FLASH->CR1, FLASH_CR_LOCK);# y6 R% h/ L5 y1 G6 y
  5. 8 D: D. A7 x. G( {7 _
  6. /* 验证Flash Bank1是否已经被锁住 */3 @1 `" i: i1 {, y
  7.   if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)! E9 ?$ }" M+ f& r
  8.   {
    & ~+ |2 ?3 X' S' V+ V
  9.     return HAL_ERROR;
    , G0 r7 [# x$ ?# N3 O9 \
  10.   }
    - m' A9 s( p8 p" P
  11. 8 i+ ~* J' M! V, Y& J' G: y
  12. /* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */
    ' y$ R7 |4 I% \$ P% V- J/ O
  13.   SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
    - I# t. R: Y. L: r1 q4 D

  14. * w3 [5 d! d1 O; G" {6 f# i. g  s
  15. /* 验证Flash Bank2是否已经被锁住 */) v4 S" W  ^/ e! p* r  T
  16.   if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)
    4 v. k5 a1 H3 ?% T
  17.   {
    0 k, @% W  X0 O9 Z9 h) N
  18.     return HAL_ERROR;% g+ G/ i, c2 G5 _; H
  19.   }5 p" B% u. L- P: L' F

  20. ( N# f0 d5 ?* ~1 g. @
  21.   return HAL_OK;& W! a+ P2 K$ m9 v/ o" \, F
  22. }
复制代码
) w0 H7 C3 q- u, Y" }
函数描述:) t7 N1 b- ^: K- J1 R) N0 V

% d2 ]8 \6 u' U/ p用于Flash加锁,加锁后将不能对Flash进行编程和擦除。* Z% \" u( ?  ^6 c$ ^  C2 l
3 ?. e: g% V: c# d, T; K4 _( U$ ^
70.4.2 函数HAL_FLASH_Unlock
  m+ M: k6 ^: L& d/ @/ u函数原型:8 Q# _4 @8 o4 _: F4 g0 U) E4 k2 [% S
  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void). ]" k+ `7 E2 P# W
  2. {) _1 S0 |) p$ Y, w
  3.   if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)1 f' B/ K6 S; D' ]
  4.   {
    - U( E& P0 b$ `$ c! l( @
  5.     /* 允许访问Flash Bank1 */
    3 [3 n/ s) k8 [: W3 I0 P
  6.     WRITE_REG(FLASH->KEYR1, FLASH_KEY1);% Q- X/ s# Q% o
  7.     WRITE_REG(FLASH->KEYR1, FLASH_KEY2);
    # v' p7 R* z' h7 w7 r; R
  8. 0 h5 u# S! x( a6 X  K  N
  9.     /* 验证是否已经解锁 */
    8 e( S% |) c: B$ V* Y
  10.     if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)& ^( r" ]( I- Z$ P. |0 N, C
  11.     {$ y1 S" ^6 L$ J( @& N% o
  12.       return HAL_ERROR;
    . j7 T3 r% U! L
  13.     }
    # S7 K3 D6 u4 r8 K( ~5 f
  14.   }
    % i4 K; h, I, `! M1 D! |

  15. 0 f$ O8 ]0 Y; t
  16.   if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
    7 B2 T6 @* E2 Q6 h0 p
  17.   {& @8 L" o& I  Q/ a+ \2 ?% t" w
  18.     /* 允许访问Flash Bank2 */
    / e6 k& Q) {5 ~5 z) K% J" j, M3 e
  19.     WRITE_REG(FLASH->KEYR2, FLASH_KEY1);9 q. I6 h" M7 a) `1 e" e* |- L# B$ @
  20.     WRITE_REG(FLASH->KEYR2, FLASH_KEY2);0 P5 f  f# `" e( y

  21. ) l0 C9 D0 p. X7 G0 @3 [
  22.     /* 验证是否已经解锁 */4 X% p* c3 N/ W$ s1 U9 d
  23.     if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)% g) y2 j; K' V3 ?& d
  24.     {
    $ G6 K& c; l' c+ C: v
  25.       return HAL_ERROR;6 T% |! P/ c& |$ Y. C. r) M
  26.     }
    % d$ L* O- [) C
  27.   }
    - ^9 U7 }6 R- y! U5 n' K+ R

  28. / L) N  ]  {: z8 b1 y
  29.   return HAL_OK;9 z2 @+ H) H! }/ e9 A
  30. }
复制代码
: X: \6 v4 _* u+ |% l3 o3 W+ E6 `
函数描述:1 @4 `( y/ z/ e# ?9 `

7 _  E+ H3 B( s& c( W% X  k此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。
) M6 }$ ?+ X. Y8 r2 j6 Y* f2 t- S6 b* X4 ^: p
70.4.3 函数HAL_FLASH_Program8 ~7 n( J. ^- V( X, x
函数原型:
7 b1 X# E1 S" W& h! d
6 j+ Z0 H1 o: g9 e( d% k" c; k
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
    % S" R2 K- K" C& D
  2. {
    + o2 w0 _% X. {& q1 _
  3.   HAL_StatusTypeDef status;
    - X) P) C4 _7 O( N
  4.   __IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;/ W3 ?0 P, b" k# E. X
  5.   __IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;+ M8 C7 D. D- u# X8 Z
  6.   uint32_t bank;
    * v( }& B5 C; N/ ?* L
  7.   uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;# |: k) p4 ^% ^6 d1 {) f6 D! ?

  8. 8 O% F" F7 u0 q8 F+ d/ I% m2 o
  9.   /* 检测参数 */
    ( Q( x1 a) |! K2 c7 y, f/ j, R
  10.   assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));- L+ K. Z. v  a! t$ `
  11.   assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));. Z- l2 t4 r: i9 u0 N# S" t8 c7 H
  12. & h7 {. @- q  _4 d
  13.   /* 上锁 */
    4 {* N7 W4 Z; k
  14.   __HAL_LOCK(&pFlash);
    2 j; o7 |( X1 g. M7 {/ }

  15. 0 }6 i, X  v$ t9 x( ?
  16. #if defined (FLASH_OPTCR_PG_OTP)
    5 V: O' P; N, b2 v- a5 ~2 |4 y/ g
  17.   if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))
    5 h0 L& `! Y' V4 K7 ?
  18. #else
    - H1 P4 S+ [3 c8 b% K6 B& I
  19.   if(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))4 S  @2 i* U: k/ S9 t& {
  20. #endif
    # X0 ]' }1 \- @8 S" T
  21.   {4 j1 o* [+ `) \; k1 o) V3 h
  22.     bank = FLASH_BANK_1;
    ; ^! h8 |( u7 d8 t. Q
  23.   }, ^# o# @4 y: g
  24.   else
    / }. V5 g% t' v) ]/ [. ?) C
  25.   {
    8 D5 S: {5 l# W) R
  26.     bank = FLASH_BANK_2;+ m6 q1 r6 R% W+ X$ p/ j% G  J
  27.   }
    1 K; F0 D( j3 i1 M& S
  28. 7 w- N; j/ K: P; |+ u6 R- B
  29.   /* 错误标识,无错误 */
    ! _* m1 u* i7 c+ K5 F
  30.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    ; M: b% V2 Q, `' _" o5 Y
  31. 1 k4 F" R, \5 i0 x
  32.   /* 等待操作完成 */
    1 S; T. E$ }$ C) [, y1 y
  33.   status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);$ B0 x2 n1 n5 ^* I( M2 I: |  }

  34. 1 L, \5 `/ L1 b$ Z% G. m
  35.   if(status == HAL_OK)
    0 T1 w$ T1 C: ^0 B7 u
  36.   {
    4 y" m& P- d1 C# U
  37.     if(bank == FLASH_BANK_1): F7 X7 t$ V. T; Y5 \
  38.     {  J8 a& P. Q5 D. k" m
  39. #if defined (FLASH_OPTCR_PG_OTP)" Z- ^7 T" S  x6 s, W
  40.       if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)0 _  j0 @' G& B; Q
  41.       {
    7 [6 G3 s. e- C' H* h
  42.         /* 设置OTP寄存器的PG位,使能可以编程 */
    1 P# z0 b- }0 A
  43.         SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    9 d/ p2 `# f7 `; [; o1 R3 v  R( @
  44.       }
    6 p3 k0 z8 ~$ E, v
  45.       else
    % z: U$ n/ n) V7 T2 r2 a, W
  46. #endif
    ( \% q- Q3 o! I0 b+ Y# `/ }" a
  47.       {7 S1 c/ Y$ I- ]  r
  48.         /* 设置PG位,使能可编程 */9 L8 r, |" y, v8 n2 O
  49.         SET_BIT(FLASH->CR1, FLASH_CR_PG);
    - P1 D/ V& J/ ?+ O" f
  50.       }
    / H2 A7 y+ t6 ]& f& X
  51.     }
    ! t" ]: M) f0 {# A$ h
  52.     else$ N% l0 v8 V5 z; k
  53.     {
    " ^! L+ ^% Y0 P/ Z
  54.       /* 设置PG位 */
    6 o% F# z( J! @& i
  55.       SET_BIT(FLASH->CR2, FLASH_CR_PG);8 M2 R7 I' Y# I# S* g$ f) a
  56.     }3 R7 e) h0 S: K

  57. ( G* d; \! @. t' f3 @
  58.     __ISB();
    0 o$ J* F6 A. Q9 L
  59.     __DSB();
    2 v7 _4 o% Z% }/ k& x
  60. , j' [# B2 d) `6 J4 l/ S$ Z2 q) T
  61. #if defined (FLASH_OPTCR_PG_OTP)
    $ u+ A2 m8 e1 `# o" ~
  62.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)8 W  T8 C& X) _: c  W: ~  ]
  63.     {6 g7 z# C1 ~9 D5 H) ?
  64.       /* 编程OTP(16 bits) */
    4 p8 L: g6 K& E% }
  65.       *(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;
    ! d" l8 g) x, U4 \
  66.     }
    7 J" B/ V. E* U9 _# ]. U5 |
  67.     else
    ; p# |# s& Z. Z6 H6 _# ]
  68. #endif
    / }( i2 h# R7 T3 a0 U
  69.     {( O+ p4 N4 \; z/ J+ T
  70.       /* 对Flash进行编程 */. v+ ~! I, F8 f3 y
  71.       do
    , j" Q" D; \4 [( @1 T7 ^' p
  72.       {
    5 I% x7 t! _! K- T* U: h
  73.         *dest_addr = *src_addr;
    # R' J- D8 Z& E, y: S
  74.         dest_addr++;! x7 x; |8 X7 N% [1 U: T6 j* D
  75.         src_addr++;/ I( _$ ]. B* Z5 a0 r
  76.         row_index--;' Z. z, N6 v# @
  77.      } while (row_index != 0U);4 E& g( @/ I. \6 A- [
  78.     }: w1 B- P, p2 c
  79. 6 c3 `, u5 \/ B
  80.     __ISB();
    + p# X  R- V3 T; g" N0 |
  81.     __DSB();  H" i- R- \+ R
  82. ( _% G; K8 D( X
  83.     /* 等待最后一次操作完成 */
    % i8 F+ b% k0 G( R# ^% s$ X
  84.     status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);( {- ]+ G/ a7 p6 J+ j# A

  85. 4 u* p4 n% C. r& l2 j! ?5 N6 e1 z1 M
  86. #if defined (FLASH_OPTCR_PG_OTP): l8 G: @: m5 v8 k3 j% i& ]
  87.     if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD)
    ( l4 w2 M1 U1 j( d; e/ g
  88.     {( a8 A6 I6 U6 T% I
  89.       /* 如果编程操作完成,关闭OTP PG位 */3 n. Z. O3 A# N9 m
  90.       CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);
    ; p( m" |& ^8 i* }' t1 b
  91.     }
    ( u% I$ q5 R8 _6 z
  92.     else- d6 P! I1 [; Y) H# T
  93. #endif # N3 g% ^- c- h/ A4 O9 V
  94.     {
      P# o4 x+ L# f% M: ~
  95.       if(bank == FLASH_BANK_1), a) {# j  h1 h* @
  96.       {
    ; K  w& F0 [  G8 z2 I/ A& l
  97.         /* 如果操作完成,关闭PG位 */
    0 g. k  m- t$ |7 y+ ]" @# V
  98.         CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);
    3 X- H& l7 j9 }* U' _* `9 B
  99.       }
    ; ~& j* F; t1 b: F; N
  100.       else1 j" s  W* |2 G; |; z$ I- R# R4 b; \
  101.       {
    ( ]! }+ }$ |5 v3 P7 Z
  102.         /* 如果操作完成,关闭PG位 */
    # `& ~6 O4 E/ f, m
  103.         CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);
    0 w8 d) i3 t- i2 F7 V
  104.       }: A- F1 r6 b( {, S# S5 }0 y
  105.     }" _* h1 U' ~. I: Y( o: }9 H
  106.   }
    , J, D% B! H1 a

  107. - Z& t" g4 P) U3 x
  108.   /* 解锁 */( G8 u: i. l5 Z: B* Z
  109.   __HAL_UNLOCK(&pFlash);8 o  ]7 E4 \* Y' @1 Q
  110. 6 {9 u* Z1 U& W5 ^% s+ t# X
  111.   return status;9 N- O+ Y# R; O* p: q7 k2 C
  112. }
    " R2 o& T, g: y0 _# m& \

  113. 7 P' d! B5 {4 W; }, s# E
复制代码
& o8 ]4 s+ N" U
函数描述:
* M: P( \: t# H此函数主要用于Flash编程,固定编程32个字节数据。  Y& j' E. I/ d0 I% M; C

7 |0 ?3 d$ O3 u函数参数:  k, a+ Q# b7 D5 w1 A! `) p8 @
第1个参数是要编程的Flash类型,支持两种参数:1 y- f6 @6 |' Q9 V) o
  FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。: M2 n5 r! u  k# T% ]: `/ @
  FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。3 t) E. v, [/ p  y, o3 P

! S9 T, O+ c# z. e第2个参数是要编程的Flash地址。
, Z+ n5 ~" b$ V, X$ X( j* Y- N# d) `6 w) b! K% W/ |
第3个参数是要编程到Flash的数据地址。
! L" b& w; e& p返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。- I( v9 A- {4 f. N# K, X

+ e$ s. M2 P! n; T6 E! c
' E0 s' i3 K( I( D  A3 _5 @0 f, ]注意事项:
0 m, {, \; a0 o/ I# i% m2 i  第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
& N  I+ q2 K7 A6 ~: w" s9 @& C  第3个参数务必要是32字节的整数倍。8 r1 B0 H; W0 Z* ~! J, p) h

: ?4 S6 P4 n$ o70.4.4 函数HAL_FLASHEx_Erase
* k$ V3 G& N0 O, E; a5 d* R函数原型:
: J) m% V* o% v$ y+ ?. D# ~1 u1 ~5 Y' m; w" `- L6 ^: u% E
  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)- ?' j1 s5 ~& V1 z" I3 ?5 t
  2. {4 W% r) \$ W1 K# g/ F. x
  3.   HAL_StatusTypeDef status = HAL_OK;: ?' }) J; X& h2 L/ ^! E
  4.   uint32_t sector_index;
    $ u8 I, W5 W% w

  5. " L# f( k. K4 G+ x: I/ w3 }
  6. /* 检查参数 */
    3 D3 E, u/ V8 l( z; P' g* W) f
  7.   assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
    4 p, _9 @" E# m
  8.   assert_param(IS_FLASH_BANK(pEraseInit->Banks));; \: ~1 \# y, Q3 |1 _2 n

  9. & [: C! ?% g4 e) T, M
  10. /* 上锁 */* }0 w( K2 O* t+ [) H2 `1 w+ @
  11.   __HAL_LOCK(&pFlash);
    3 ?* t: K  M* @+ y7 h+ S

  12. ) _: F7 P# C: T
  13. /* 无错误 */
    6 S/ q3 E2 S7 k* S7 ?
  14.   pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
    / F& A2 p% V1 F
  15. & U( V; y1 v# }8 w7 ^2 s! ^( h
  16. /* 等待BANK1的操作完成 */5 f$ d9 W7 D8 }) k% [" ^
  17.   if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)+ T$ w; _( H% s( a' R( O$ l, [
  18.   {
    - c' G+ m  N0 K4 T
  19.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    4 P& j3 J7 v( H; Z$ u9 T; P
  20.     {
    9 j5 t- A! f" t
  21.       status = HAL_ERROR;" b( z; A+ P5 i3 e) U; B1 r2 S
  22.     }
    2 K+ |; `* C& w9 e+ f. H1 P
  23.   }
    ( {; H+ V, Z7 R; L! s5 E" c8 E
  24. ' e* g# d/ Z! e2 a2 d! S
  25. /* 等待BANK2的操作完成 */
    1 M9 q  F6 l' z' D
  26.   if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)8 o& z) ?  S1 b) c
  27.   {' G! `- R  v! J& ]; W3 `
  28.     if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    9 K+ \6 R4 c: h6 u
  29.     {- S( U% f2 M3 g# U1 D5 z1 q3 |1 C
  30.       status = HAL_ERROR;
    ! c/ Z8 \1 g) a
  31.     }
      q8 T( H8 Z7 B0 @" J( p
  32.   }
    ) R7 Y' W3 u4 M5 i) ~% q( y" R
  33. $ B$ Z# T+ [; h% R
  34.   if(status == HAL_OK)
    3 _! D7 W# e( V! c& d2 B0 g& c2 f
  35.   {. B- I' v4 f" @- I) @. r2 f# x
  36.     if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
    9 i3 e( Z# l/ [5 E
  37.     {
    # U6 N% g1 Z* k* _; ?0 A
  38.   /* 整个BANK1或者BANK2擦除 */
    5 ^& g( \, ?7 P$ D  e
  39.       FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);
    1 y' B0 B& M/ Y0 v; U# B" P# N
  40. - K7 w7 U1 j; Q
  41.   /* 等待操作完成 */
    1 C% S9 e$ s& M5 L8 N
  42.       if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    6 j* e; D/ e0 c; F' ~* i- a% N: B
  43.       {
    ) a* U- Q5 o, |; S1 q
  44.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK)
    - l& c( q( t8 `; M- `7 |
  45.         {
    + g! J; I' R9 t$ U+ j3 O# K9 O
  46.           status = HAL_ERROR;# Q1 c, X! ~; B0 ~2 f3 F' G+ H5 V) z
  47.         }7 K8 i) M2 }! A2 l: S
  48.     /* 如果擦除完成,关闭BANK1的BER位 */
    : y8 Q, g0 ^) W1 D, T1 k
  49.         FLASH->CR1 &= (~FLASH_CR_BER);$ i+ G5 Q, s. v! K3 P$ ]
  50.       }9 o& c- C5 p5 z
  51.       if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)8 W+ E% G. `! O- n  q
  52.       {+ q* z# }9 \0 s6 G$ e, ~
  53.         if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK)
    & t* J- ^7 C! F  }" |
  54.         {
    : k6 {4 W& D2 ]7 X# H, ]* P8 W9 i
  55.           status = HAL_ERROR;
    & N8 d9 ]  h# N2 h, O1 ~( h
  56.         }
    5 {2 x0 C, x1 X- x1 C8 O: }( P
  57.     /* 如果擦除操作完成,关闭BANK2的BER位 */6 y$ C1 R( r( W; e$ o: h
  58.         FLASH->CR2 &= (~FLASH_CR_BER);
    6 j0 |& d7 V- a
  59.       }! t* i+ E7 ~$ y
  60.     }2 I' \, u& l% K9 O* Q/ ]
  61.     else$ }/ h* p! I" i$ i3 R2 F
  62.     {
    % f1 a& M2 t( R- Y0 g7 x
  63.   /* 初始化扇区错误码 */
    ) l* ~  ^( @; v- J& u' d# Q: {/ }; u
  64.       *SectorError = 0xFFFFFFFFU;
    ; X) ~$ a9 r0 `" Z' F5 j
  65. $ B& w8 W: a" K/ S0 {
  66.   /* 扇区方式擦除 */0 G9 I3 x+ @- j  [3 s3 O4 }
  67.       for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector);
    + m5 ]  X0 K1 {1 o
  68. sector_index++)" R& z" N' w% i. L
  69.       {+ J7 @4 v0 R! K1 E5 }: ]' G
  70.         FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
    & P- e$ l7 G( w5 _$ E( w; P" W
  71. ( @& u1 @( `- _6 i4 T
  72.         if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
    $ Z# b. F/ f2 J1 R% y8 [
  73.         {3 Y, n$ E* E* f6 F+ P
  74.       /* 等待BANK1操作完成 *// @+ Y5 h( r: G& h- H1 P
  75.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);1 `$ a" P& R% W/ O& g+ r. I
  76. 4 ?2 Q) ?. H& o$ [- g
  77.       /* 如果擦除操作完成,禁止SER位 */# o. @: Y* L% ^: q
  78.           FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    4 `6 ]! _4 K& z$ |- g
  79.         }
    ! |: @* m- V3 M# Z* K* t3 {
  80.         if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
    % ]" s: e: V, G5 a+ l( R
  81.         {
    8 R/ f3 L5 Z1 K/ r. M9 i
  82.       /* 等待BANK2操作完成 */
    8 O: u/ Z. U/ a  k3 ^3 v$ H0 b
  83.           status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);1 _& N" I& M' h  @- z- f0 t) T0 F$ j
  84. - ~# v1 R. [4 o5 i) {$ j
  85.       /* 如果擦除操作完成,禁止SER位 */
    % A4 T5 k& Z2 h/ D
  86.           FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
    - c  s9 Y0 Z, H$ o
  87.         }
    $ Y  u, c/ p6 N# v* W- k# H
  88. ; g, u$ e6 v  Y$ A& F
  89.         if(status != HAL_OK)4 `9 T1 Z8 s1 x: w% ^
  90.         {
    + M! n! g: R% u* q7 a, v
  91.       /* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */
    # o) O+ {( C8 K, r6 H/ [3 x
  92.           *SectorError = sector_index;$ F# k" y) g' z! W. ~
  93.           break;
    1 m  ^0 s2 B# W! y' S' p1 j
  94.         }7 h/ p. G; i8 n. h. h
  95.       }9 T* t/ {2 _$ O
  96.     }
    " V4 V7 I3 W8 d$ S
  97.   }
    3 C+ Q, F2 t# B6 f. p) x9 O
  98. * D7 R; j8 k% Q) i& n9 B
  99. /* 解锁 */
    " v% v* T" F# i2 O& }) {
  100.   __HAL_UNLOCK(&pFlash);& G+ [: [$ z; e- w
  101. 0 o6 o6 Z; h9 t7 z3 F( t5 ]
  102.   return status;
    ; P2 ?9 I1 I2 D# ~" d& X! h, l
  103. }
    ( {& t6 ~6 L9 S
复制代码

6 b; I0 }" R; r: d+ |( }函数描述:
5 S- }; V# \+ T' ^! B0 f用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。
7 j! A) Y9 n% d4 S' i3 ]
6 w; N- s5 V  E# J* l7 g函数参数:0 Z6 ?" t4 w$ U
  第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。* M+ U7 O  o  L2 [3 T
  第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。
! v5 ]8 h( x5 k' \& b+ W% k  返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
2 J3 x0 A6 I" \) q
2 e7 d' J* ~7 q70.5 总结2 {7 I. {+ r1 G7 t- {# `% K8 u6 E$ [
本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。' ^8 E! I1 ?0 d

% D4 h" a1 R- e7 e2 z( j5 @# l# w/ t/ ?. h9 X0 _( a
8 F/ b& b" a- A
收藏 评论0 发布时间:2021-12-19 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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