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

【经验分享】STM32H7的QSPI 总线应用之QSPI Flash的STM32CubeProg下载算法制作

[复制链接]
STMCU小助手 发布时间:2021-11-4 23:27
81.1 初学者重要提示
8 N8 E2 J1 u* x# S* p  QSPI Flash的相关知识点可以看第78章和79章。; t( ]0 ^; T/ x
  QSPI Flash下载算法文件直接采用HAL库制作,方便大家自己修改。% v0 r3 N2 S& L' I& B- \1 H
  STM32CubeProg下载算法制作和MDK下载算法制作基本是一样
7 r& R- |- _# u- ~  本教程的第68章USB DFU和第69章串口IAP章节为大家介绍过STM32CubeProg的用法。
: x% ?% V, [) e; R) _81.2 STM32CubeProg简介( F5 k& M7 ]; j9 a3 m( s: f
STM32CubeProg,此软件实现了之前的 DfuSe,STLINK 小软件和 Flashloader 三合一,并且支持外部 EEPROM,NOR Flash,SPI Flash,NAND Flash 等烧写,也支持 OTA 编程。
  S' f5 P  z8 N& X& g
" }* @$ P# ?/ q
1bbabf500126f58ff1439b6bc36014be.png

3 F$ ?* y8 m% b4 `& Q/ [: i1 M
( B+ k+ L$ d( y+ Y! w: |81.3 STM32CubeProg下载算法基础知识
5 g' o- y1 t( [7 l% T9 {% M! C3 c( cSTM32CubeProg下载算法是一种用于擦除应用程序或将应用程序下载到Flash的程序代码。ST自家的芯片都自带下载算法,存放在STM32CubeProg安装目录里面,但不支持的需要我们自己制作,本章教程为此而生。; I$ Z/ X% g6 |0 W: ]

- T4 F5 b9 O0 J5 Q81.3.1 程序能够通过下载算法下载到芯片的核心思想
9 b3 V# h6 }  s- {- R$ A- o4 \  d认识到这点很重要:通过IDE开发环境创建一批与地址信息无关的算法文件,实现的功能主要有初始化,擦除,编程,读取,校验等,然后STM32CubeProg下载阶段,会将算法文件加载到芯片的内部RAM里面,然后STM32CubeProg通过与这个算法文件的交互,实现程序下载,数据读取等操作。4 W) c, k, l5 t$ L4 M
- i* F: ~  D/ T, P0 q
81.3.2 算法程序中擦除操作执行流程
) B: s4 @; o- ]& Q( q3 [- G( h; B注:下面是MDK的算法执行流程,STM32CubeProg是类似的。4 k4 W8 p# Z7 y  u5 m. a
& [5 ]; W! D) Z  g1 H
擦除操作大致流程:. C& s% H" z* j5 o5 {
7 |! C* {& [8 o/ D7 D) U6 s
161f92ebd9b1dbf9febba815fa091b8b.png
! L: Y' M/ Y. w( \* D4 v/ ?& Z

& b; Q7 ~# r& p  加载算法到芯片RAM。" k/ c3 f2 R3 K/ w2 q  e
  执行初始化函数Init。
2 p0 g* V8 B( |) V  执行擦除操作,根据用户配置,这里可以选择整个芯片擦除或者扇区擦除。( K/ p" [' D: Z6 s( V
  执行Uinit函数。" Z5 p' `/ P. Y. F, L
  操作完毕。" O2 L( x" J8 d2 h' |) ^: D9 }0 C
81.3.3 算法程序中编程操作执行流程
+ q* O" ^$ _' O3 a" }注:下面是MDK的算法执行流程,STM32CubeProg是类似的(没有Unint函数)。! h& J/ ]! @; p- v* y
1 t6 }: d, r3 E" n4 g, U" K
编程操作大致流程:
7 P% L+ N+ O! B4 i* Y
1 T( t2 f" ?9 ?1 j8 U* a' E  y
d80dfd755411aa0d0565f1c56f10e66a.png
  Q2 m+ W3 O' i. b4 f

  N7 R, T  J7 c1 j3 [" _: M  针对IDE生成的axf(elf)可执行文件做Init初始化,这个axf(elf)文件是指的大家自己创建应用程序生成的。5 B1 Y% K4 j/ @
  查看Flash算法是否在FLM文件。如果没有在,操作失败。如果在:2 ~. i' V- i- p
  加载算法到RAM。6 o9 M, O. I  S' T) k( }; Z5 a
  执行Init函数。
9 y$ h3 `$ b- b3 b- v1 ?/ F  加载用户到RAM缓冲。
1 z' Q6 e, _& h! {  执行Program Page页编程函数。
! j  J4 s( a0 @0 d  执行Uninit函数。
% ]! @1 U2 s4 }; b5 ]/ V; i1 `1 V2 J  操作完毕。+ M, y5 H0 p, J# z) }. k+ [( r
81.3.4 算法程序中校验操作执行流程
$ y% c" p( R& _$ Y8 A7 Y& C; H注:下面是MDK的算法执行流程,STM32CubeProg是类似的(没有Unint函数)。+ M9 d" w) o' K0 Q1 x& M/ a

. Q1 Q5 R6 x8 `2 ~校验操作大致流程:
: `9 h! t. {9 i
' G, b% o, G( ~. O% b
f15191090ab169d48a203ea3617af9b4.png
$ j/ c  T% T' V! k8 A
: [# K) B" E( L) m$ V
  校验要用到IDE生成的axf(elf)可执行文件。校验就是axf(elf)文件中下载到芯片的程序和实际下载的程序读出来做比较。6 O7 @: k, t' ~( Z5 ^
  查看Flash算法是否在FLM文件。如果没有在,操作失败。如果在:1 l- z! o) n& z+ L5 V% Z0 K
  加载算法到RAM。6 N4 S  u0 _& I+ P
  执行Init函数。9 n: J; E0 l4 ~' x1 p# }- t
  查看校验算法是否存在
5 n, K# K$ m# {/ }7 Q  如果有,加载应用程序到RAM并执行校验。. c) }9 q% R! A8 F7 v- B. j2 Z& d2 v
  如果没有,执行计算CRC,将芯片中读取数据出来和RAM中加载应用计算输出的CRC值做比较。
- Z0 h# N9 k- a5 C2 L7 w5 Y) F  执行Uninit函数。
- G& X) W, \4 G$ R! \; J  替换BKPT(BreakPoint断点指令)为 B. 死循环指令。
1 b. r+ Q1 ]' B1 {8 g, m7 z  执行RecoverySupportStop,回复支持停止。7 t3 v& D+ `5 y0 }1 {6 x) E9 @# y
  执行DebugCoreStop,调试内核停止。  X9 B7 `4 O. l9 B
  运行应用:
) ]: z3 c! e- {; V* X1 G  执行失败
, c- a/ |+ c( s  执行成功,再执行硬件复位。
1 A' P' Y+ q: f' g  操作完毕,停止调试端口。
9 T' M' t1 W" `2 I% u( f- ^81.4 创建STM32CubeProg下载算法通用流程, H- {/ x. U7 r; @* D. c
下面是STM32CubeProg给的一种大致操作流程,不限制必须采用这种方法,自己创建也可以的。. Q* P3 ?+ n; H2 M5 H" I/ ^  b. e  |
" \0 J# l$ A( ^; H, _# {
81.4.1 第1步,使用STM32CubeProg提供好的程序模板7 N7 P, `) l" t' n1 Z! n
位于路径:STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader
$ Q4 t. T! W( y- Y- p) O8 t# x/ }. R" ~+ q. [& a9 v
4fbfb0047e29fe23083224607059d97f.png
' t  ]; I( n6 U; N3 |* X3 u6 e

. |7 C/ }$ \- v以M25P64为例(注,其余步骤就以这个为例子进行说明):
2 \2 l# x" r4 w/ X+ p0 {
% o8 m# q% Z; y
d1b1a340fdc655c1030330a7dad2abba.png
1 u) Z( d5 D/ }1 V8 B! F
" O' H# o7 N  U6 B
81.4.2 第2步,修改工程名8 K# U" d9 a* S
STM32CubeProg提供的工程模板原始名字是M25P64_STM3210E-EVAL.uvproj,大家可以根据自己的需要做修改。比如修改为MyDevice.uvproj(MDK4的后缀)或者MyDevice.uvprojx(MDK5的后缀)。
4 o- q) B0 ?: Y# Z4 d  a
* b, m' K. [" ~; ]! [$ N0 L' g81.4.3 第3步,修改使用的器件
. |9 u) g( ^- H( m: M! q在MDK的Option选项里面设置使用的器件。! g' F3 {. z; g4 A/ G" }

7 P7 H5 S9 P0 N
092174ad976a8ce9c7fca533049e2dd0.png

. {" }, C6 d: W" v" u. U, A1 ?2 W8 m; C& n& y7 p- t
81.4.4 第4步,修改输出算法文件的名字
9 m! G% e7 c1 W, Q0 i/ h这个名字是方便用户查看的,比如设置为stm32h7,那么输出的算法文件就是stm32h7.stldr。! q' Z6 Z2 }& T4 B# P4 @1 n7 O4 d

1 C& |# x/ R* [  x
79c42251311dd3892fc7d6b8ddde68b8.png

% |( c  g$ D9 U  r# s
5 x$ N, e  `% Z* J" F" O注:STM32CubeProg软件里面别的文件名并不采用这个,而是由用户在文件Dev_Inf.c里面定义的:! q2 S  D5 ~$ z) `5 R5 s2 H
e2fe61fa7ea99b25b178341b7350558f.png
5 s& O$ _" ?1 {0 Y' A
0 E- K* j/ d7 q5 K
81.4.5 第5步,修改使用的库文件和头文件路径+ s! g. F" Y+ D# k" j" y
根据大家使用的主控芯片,添加相应的库文件和头文件路径。; p5 e' Y! n0 {

+ T6 y+ M8 S# Z; @4 D  H$ }81.4.6 第5步,修改编程算法文件Loader_Src.c
1 R9 e, e: b& O6 B* n" b0 k模板工程里面提供的是M25P64,部分代码如下:
4 h) y9 U0 T9 y/ l; z) j: h
1 v# F! S3 X5 i2 {% s* p
  1. /**
    6 ~% B6 u: m' O9 T
  2.   * Description :) G$ @7 q. n- ]  H: t5 b/ c
  3.   * Initilize the MCU Clock, the GPIO Pins corresponding to the) M# t2 k$ o" j+ z
  4.   * device and initilize the FSMC with the chosen configuration
    # D' X, @9 o5 i  B4 g2 u
  5.   * Inputs    :
    ) P1 G% P! w  A2 X0 ~  A" W0 ^
  6.   *      None' t  ]2 Q6 W' l3 G2 z, r% l
  7.   * outputs   :
    0 X1 y. r% E7 @& r4 m
  8.   *      R0             : "1"             : Operation succeeded
    3 V" _6 g; g, J" z7 u1 q
  9.   *               "0"             : Operation failure* O+ z, w+ M: S/ W
  10.   * Note: Mandatory for all types of device
    " x! J  o, A- O/ x- T) W
  11.   */
    8 I  H' e) V& H
  12. int Init (void)
      h9 g% h( k: X1 \  K; w+ x
  13. {  % q# O3 B0 V- J3 r. c8 i
  14.   SystemInit();  N. b+ j0 l  g0 D; N
  15.   sFLASH_Init();
    - M: W4 `3 s' k
  16.   return 1;
    3 p1 v" m" j; I  n7 {# B2 M& {$ r
  17. }
    . [8 G3 U& a4 G1 p, [8 g! u# I. K

  18. 9 y, X3 @" K# h5 A7 V; ~1 S
  19. 3 O  T/ S/ Q/ l) y$ z3 e8 b
  20. /**3 \5 ]1 f* \1 L; J
  21.   * Description :! M$ {) d8 m2 k4 a( f. X
  22.   * Read data from the device
      M2 U; [5 w% C: s# E6 ~5 r! F
  23.   * Inputs    :. B% h3 u5 }1 R! B% x$ n5 ^
  24.   *      Address       : Write location
    . {3 _: t8 s6 u- J7 {
  25.   *      Size          : Length in bytes  " l+ \, A$ e/ o2 I, V5 ?. J
  26.   *      buffer        : Address where to get the data to write# O0 `( k5 f4 e, k
  27.   * outputs   :) W# ^+ w' \. Z  j  k
  28.   *      R0             : "1"             : Operation succeeded7 ^, }1 p" X! z0 Z8 L1 Q
  29.   *               "0"             : Operation failure6 K* L+ I* I' H& G4 P# ~" A
  30.   * Note: Mandatory for all types except SRAM and PSRAM   
    - f7 O, ]( H& `, Z8 V: \7 U( ~
  31.   */
    5 h7 g0 @/ K8 d: M
  32. int Read (uint32_t Address, uint32_t Size, uint8_t* buffer)5 {" M& I2 P2 h
  33. { 3 s) M3 |9 L$ _* M
  34.   sFLASH_ReadBuffer(buffer, Address, Size);$ Y# ^, M% X. A  [
  35.   return 1;
    $ m4 S! o+ [4 f  i
  36. }
    3 ]3 }1 S, t& L2 {" q
  37.   m6 O' ~2 q% g6 v" V

  38. % V$ s. k5 E' |! b% c. B1 v0 V, U
  39. /**
    ! X0 {( H% P- @9 F
  40.   * Description :
    1 a0 u; }5 E" z% p, d1 G% p
  41.   * Write data from the device
    + U2 j( D) @) M% F
  42.   * Inputs    :( e/ t* Y6 q$ W* q& \
  43.   *      Address       : Write location
    , @8 ?5 {2 H" z# O, ^1 @
  44.   *      Size          : Length in bytes  & c& [" e+ J8 }1 Z
  45.   *      buffer        : Address where to get the data to write% ]: T, Y5 S( T  N: F
  46.   * outputs   :
    " [" f5 D9 A  Q
  47.   *      R0           : "1"             : Operation succeeded
    / K' V& P: W1 n* L0 x0 a
  48.   *                     "0"             : Operation failure
    * u9 L, W$ o: T3 }! w
  49.   * Note: Mandatory for all types except SRAM and PSRAM    / h  b. e, @, v& O  G# W
  50.   */9 d8 k$ [$ Q* Y  }" W" x
  51. int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)) [3 x. _/ K, m: `4 u3 ?
  52. {
    % k8 x2 Q" F9 p% B
  53.   sFLASH_WriteBuffer(buffer, Address, Size);
    : [& R9 Y# Y4 q+ @. m1 O
  54.   return 1;
    + q# L. R2 A8 C& t1 q% }/ y
  55. } + i9 o* D6 d8 D: E, ], v& J6 @

  56. 7 ^  z* j, x9 g2 z7 k- s, U
  57. / P' A7 J6 f4 U5 Q. z
  58. /**4 E( C6 i, n2 a7 O% D, V
  59.   * Description :1 ]7 m! i) K$ I( R9 e
  60.   * Erase a full sector in the device. F. E& p; V5 a+ @
  61.   * Inputs    :
    1 U$ b* j/ v5 @
  62.   *     None
    ) T! z! A, L+ e3 G2 I. ?
  63.   * outputs   :1 o4 Z8 i! C' _2 L& z: o0 f
  64.   *     R0             : "1" : Operation succeeded
    ) T/ l( E! F: e8 A$ y/ {0 X: d
  65.   *              "0" : Operation failure
      d9 F0 e- a. W
  66.   * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH4 s6 ^* w7 h( W7 {. C) i
  67.   */
    ' K5 n  c( U7 \5 O# d
  68. int MassErase (void)
    8 m: l( P* B, e9 _3 ?6 G4 \
  69. {  * L. `4 a' D$ i1 X2 X/ }
  70.   sFLASH_EraseBulk();3 h( i: h+ B5 U9 O1 D
  71.   return 1;      F" \6 X) _3 N4 F: ?
  72. }
复制代码

& @7 D1 y. I: T6 s: [5 |) R81.4.7 第6步,修改配置文件Dev_Inf.c
- w0 v2 l/ t  k" f# U5 M模板工程里面提供简单的配置说明:
1 b$ K" u) v+ L; M. i" o! l  n' F- }2 q9 z* p( n/ T% L" a
  1. #if defined (__ICCARM__)
    7 `4 o5 T+ w4 @- ]* [0 S  g6 F& {/ K
  2. __root struct StorageInfo const StorageInfo  =  {
    & a1 U, c* z4 H
  3. #else
      Y7 L8 g3 B, T* X
  4. struct StorageInfo const StorageInfo  =  {
    2 _6 O" c5 m4 e8 Y  L, k
  5. #endif
    : l0 s7 G1 j0 B" X, Y) F7 f
  6.    "M25P64_STM3210E-EVAL",           // Device Name + version number
    " q* M3 b( |: I" Q7 u2 c3 {! N; s8 n+ B
  7.    SPI_FLASH,                       // Device Type
    & ~8 Q0 h* N/ f- p' H
  8.    0x00000000,                     // Device Start Address
    % d8 a  V  S8 Q% ]
  9.    0x00800000,                      // Device Size in Bytes (8MBytes/64Mbits); ^) k# T: ^3 k! I# o
  10.    0x00000100,                      // Programming Page Size 16Bytes( a8 d5 }; `) F6 B
  11.    0xFF,                            // Initial Content of Erased Memory
    : \0 a9 T2 j( P! D( I
  12. // Specify Size and Address of Sectors (view example below)2 ~3 [$ d6 P8 q: @& A. M
  13.    0x00000080, 0x00010000,          // Sector Num : 128 ,Sector Size: 64KBytes
    4 [5 t6 a4 J; p& y- m% L" M
  14.    0x00000000, 0x00000000,
    5 @0 |: _- O: i- y" l7 X4 G; t8 Z' n
  15. };
复制代码
. Q3 m6 e2 k- }/ ^
注:名字M25P64_STM3210E-EVAL就是我们第4步所说的。STM32CubeProg会识别出这个名字。
, T/ Y7 L' k1 h6 c) d: _+ ~* d; v
; Q7 z' }) W8 A

$ L8 ?: a- d* l+ ~0 X81.4.8 第7步,保证生成的算法文件中RO和RW段的独立性,即与地址无关。3 d: O8 U- R/ ]% r
C和汇编的配置都勾选上:# l- w6 V# P" A  e" m

0 Q6 r3 K' p4 H5 U( J
8f2ba38db4c1f685f131e7f1f4e98551.png
+ W2 B0 D" D7 k* R
/ K) q. D9 K2 b" y( Y5 @8 q+ U
汇编:
0 j$ l. Z) V* h' k
4 k0 I+ S, A6 |8 A
0d264153b167afa2303144bdd378d501.png

4 w7 o( g$ f1 C7 ^4 h# {
+ m% Y' E7 E2 t) B+ ]3 H  x" s! s如果程序的所有只读段都与位置无关,则该程序为只读位置无关(ROPI, Read-only position independence)。ROPI段通常是位置无关代码(PIC,position-independent code),但可以是只读数据,也可以是PIC和只读数据的组合。选择“ ROPI”选项,可以避免不得不将代码加载到内存中的特定位置。这对于以下例程特别有用:5 I2 U- |; d6 J* M$ v# Q

3 i9 W5 {* J% `: z8 D5 E(1)加载以响应运行事件。
, \# \+ }4 b- m/ ]5 K5 t8 x# A9 L) d* S; l4 [% O5 y! B) O3 w
(2)在不同情况下使用其他例程的不同组合加载到内存中。0 s+ W# l; C; s: V7 u. h% W

% m" _9 p0 z" D5 n* _0 t(3)在执行期间映射到不同的地址。; Z- q0 ~* x" @  e

- V- H7 r$ j( j+ R; [使用Read-Write position independence同理,表示的可读可写数据段。
6 v/ Y" s: [& z% K3 K: J
6 y7 |1 s$ e9 {* a% d/ _81.4.9 第8步,将程序可执行文件axf修改为stldr格式& V: J& `# _( R! l. O! x
通过下面的命令就可以将生成的axf可执行文件修改为stldr。- @0 o1 _% N% U+ D$ [% c7 U) H
6 ~& g4 h5 _. d7 O# r/ K2 k# _# K
f50b1594f3741e77b4fbd5523564d3af.png

; |) y/ N7 N" v, F( ]  b8 G) V& h5 z! Q* Z/ W
81.4.10   第9步,分散加载设置
% w$ s' i7 u) s2 G* `* x0 D. [我们这里的分散加载文件直接使用MDK模板工程里提供好的即可。8 ]- }9 e- S) W% D) G

8 `: l4 S* O. Z& C% ^& D
8a01cb7c9be38519d4d0510a218447e2.png

8 F; A; }5 g7 H( u+ F9 A& i
& V7 h# R' L; c/ u# Z& J5 _分散加载文件中的内容如下:
4 P  L6 z/ U3 k2 l7 ?
6 A# v2 O$ q1 f8 y: N1 S; Y
  1. FLASH_LOADER 0x20000004 PI   ; FlashLoader Functions$ A1 w/ z/ r1 a& k
  2. {
    ( N7 d$ D) \6 r' N" D9 ~
  3.   PrgCode +0           ; Code
    0 d2 Z' ?8 d+ p
  4.   {; }3 U$ f7 [, U$ E. a% n( c5 h" o. {
  5.     * (+RO)
    1 `* d! g' v$ M( W7 j. @5 I
  6.   }
    7 `4 _( D/ B; K' C
  7.   PrgData +0           ; Data" D5 W: h7 u* Y
  8.   {; A, L$ {) C) D8 M3 ~
  9.     * (+RW,+ZI)
      a6 u5 C) c" J2 l4 E2 o
  10.   }
    % d( O" w' }% ~) m3 S# j
  11. }& [& B8 {5 ~4 N5 w% `: c* {
  12. ! i  \, W3 X5 ~+ j  z7 M, U# U. d! [; k
  13. DEVICE_INFO +0               ; Device Info6 t4 g/ R1 j1 y4 @7 S" @
  14. {! U, l* y2 H/ }
  15.   DevInfo +0           ; Info structure
    / V' s9 Y6 V: J( I
  16.   {
    2 V6 U% r- i0 I& ~9 u+ X  w
  17.     dev_inf.o
    * u1 ^4 d% I# a+ _0 P, \
  18.   }
    6 y5 z* W: n5 f
  19. }
复制代码

9 C) ]/ A9 ]) C& P9 Z这里要修改下Flash算法加载地址,将0x20000004修改为STM32H7的RAM地址,任何RAM块地址均可,只要够存储Flash算法。推荐设置为AXI SRAM地址0x24000004,因为空间够大,有512KB。* y) H8 ?/ t  L- _# A% N( k

( u# x& G, N( X; [4 r--diag_suppress L6305用于屏蔽L6503类型警告信息。
9 V' T# N0 r  a) H% x. o: K
7 [+ N' t4 o7 l: T( W2 C! r特别注意,设置了分散加载后,此处的配置就不再起作用了:
, ^+ |1 P4 z* D+ F! A* f8 f9 T, |( L8 h! _
13b022190bd5115ed249129fc3886a38.png

2 I, V& z/ V0 Q6 u% J% X/ L& U, D; d/ U/ W& z  q
81.5 QSPI Flash的STM32CubeProg下载算法制作* o; x4 |0 Y; `9 E! s$ q/ @; c8 `  q
下面将QSPI Flash算法制作过程中的几个关键点为大家做个说明。
3 a" H% v2 B- @7 `2 R* f8 R
' D& V0 ~0 S* D, ], X3 |) k81.5.1 第1步,制作前重要提示
/ G) h4 C# ?  m1 P4 t这两点非常重要:
3 U5 a) N( E1 `0 w7 H
' V9 b. W& T, V; l+ _- [5 c  P. O  程序里面不要开启任何中断,全部查询方式。. y, e% P% k% ~2 \( s& h8 D1 t8 R
  HAL库里面各种时间基准相关的API全部处理掉。简单省事些,我们这里是直接注释,采用死等即可。无需做超时等待,因为超时后,已经意味着操作失败了,跟死等没有区别。: I* T; W% N! s3 S2 o
81.5.2 第2步,准备一个工程模板6 m1 Z  s1 i, I: p& ]5 Z
推荐大家直接使用我们本章工程准备好的模板即可,如果大家自己制作,注意一点,请使用当前最新的HAL库。
' h. k+ F: u3 D1 d1 Y6 _, c
4 r" V7 |  O; T% x3 E
f46a8d2276d0ffb7beee251cdb0809a4.png

+ z6 O- ?8 O9 ~3 m" T- S* T6 c0 M' P
81.5.3 第3步,修改HAL库3 [  T) A* S+ @5 `- @2 d! X0 \3 s
这一步比较重要,主要修改了以下三个文件:$ W# a& _$ E" Q+ c1 a

) A& r. ^1 p+ j8 ]1 [# t8 Q
1efb78256b9465df406e3e9e95ae30e5.png

: O: r( C7 e" w8 v- L. U1 q! T' N9 e- O. S$ e3 M7 {/ X
主要是修改了HAL库时间基准相关的几个API,并注释掉了一批无关的API。具体修改内容,大家可以找个比较软件,对比修改后的这个文件和CubeH7软件包V1.8.0(软件包里面的HAL库版本是V1.9.0)的差异即可。) o' P0 R( \& K% ]' `& a0 J5 [

5 W; X9 j/ a6 d4 n% d# n  N* m/ x81.5.4 第4步,时钟初始化
$ \: L" ?  R7 {5 M5 x! x/ s我们已经用不到滴答定时器了,直接在bsp.c文件里面对滴答初始化函数做重定向:' g1 |' o/ t7 U8 E: Q/ Y0 p

& G0 u. N8 j( f3 T: F
  1. /*9 ~9 C% H0 R3 ]& Q
  2. *********************************************************************************************************
    - h8 O; C4 J7 r7 @6 h
  3. *    函 数 名: HAL_InitTick- S- c4 s! D/ I; K
  4. *    功能说明: 重定向,不使用
    + a, {4 d* ?* q! I' J
  5. *    形    参: TickPriority
    : ]$ D+ C) N" J( }4 N5 @
  6. *    返 回 值: 无
    - L; P7 A& `8 ?9 ?% c7 j6 E
  7. *********************************************************************************************************
    ' R8 W. `+ W' M: e
  8. */
    ( L5 Y% Q0 q- \
  9. HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
    / [, D6 u0 E  _( p4 h" c
  10. {
    & S0 L0 d, M6 Y) b
  11.     return HAL_OK;
    % D( C& G+ l6 d
  12. }
复制代码

5 S$ ]5 X( ^! Z; J6 u6 g然后就是HSE外置晶振的配置,大家根据自己的板子实际外挂晶振大小,修改stm32h7xx_hal_conf.h文件中HSE_VALUE大小,实际晶振多大,这里就修改为多大:
0 C. x* b) a3 c. X$ i0 H
+ h; o' j: |1 A
  1. #if !defined  (HSE_VALUE)
      p) e- ?/ I+ ~
  2. #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */5 r$ W0 D8 U+ m$ ^/ L4 J  b. a) S
  3. #endif /* HSE_VALUE */
复制代码
7 {4 E+ E% q  y1 l  Q, B; u5 Q
最后修改PLL:
$ T$ q( b  I( x$ {+ E" i! ]; s* L2 z9 t  V/ d% Y/ [! _5 X( d9 W" v
  1. /*
    3 S. t- Y4 i) \( z2 o4 i& A; h
  2. *********************************************************************************************************& k& |0 t) ~4 }+ s6 i: t4 O
  3. *    函 数 名: SystemClock_Config6 R: f9 X( N+ K7 k2 B
  4. *    功能说明: 初始化系统时钟" T. ]$ x  }2 c2 @- Z5 Q7 B
  5. *                System Clock source            = PLL (HSE)
    - g8 O6 v& L& G+ r1 m
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)7 Z  I& Q; s3 x# c6 m4 b
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)& z8 T8 s% ]. w4 u
  8. *                AHB Prescaler                  = 2+ b1 o3 P& b% S: }
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    ( o9 e0 P! |& ?, r1 N
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)! i$ d' V0 T. A. Z% ~  ~  W
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
    0 D2 N8 ?/ F8 ]0 j
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)6 y. m  V1 \: t; d, O5 H$ \
  13. *                HSE Frequency(Hz)              = 25000000. [. _, `2 m, ^; v' ~4 C% x
  14. *               PLL_M                          = 5
    + \& t% h6 w3 n& r
  15. *                PLL_N                          = 160
    ( l6 i  A8 T+ I" {6 L. z
  16. *                PLL_P                          = 2# M& Z2 m9 R" t: Q
  17. *                PLL_Q                          = 4
    ' I. `' \) X: i! `% ^* H
  18. *                PLL_R                          = 2
    ( M' J' n4 \, E. Y! K' C3 O
  19. *                VDD(V)                         = 3.3$ q( k- W# f! `" r" K7 `% v. ?
  20. *                Flash Latency(WS)              = 4
    8 M- k5 O% P* O$ e
  21. *    形    参: 无. G0 V4 N) [0 Z
  22. *    返 回 值: 1 表示失败,0 表示成功! h+ @3 C, m: I$ \2 }: ^; s  g
  23. *********************************************************************************************************; |( \7 W. G) K! n( j% U
  24. */
    ' J" ~% n. i, Q, U6 z2 }
  25. int SystemClock_Config(void)
    / M# Y( N* i0 g, q
  26. {
    " d! x0 ]3 `: v2 f9 e  E8 L* e
  27.     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};; V' g9 B1 b4 s6 }) G5 Y7 ^. r
  28.     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      b" w1 B0 a5 Q( L
  29.     HAL_StatusTypeDef ret = HAL_OK;
    / E5 a/ ]* x0 c& I

  30. 2 Y2 L0 T' p- ^' o, y
  31.     /* 锁住SCU(Supply configuration update) */6 u+ y3 b& J4 m; o$ s0 e9 {/ Q  j
  32.     MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
    . Y7 P2 t* l( S& E

  33. + [5 @  o/ y) J% z* W# o; W  o! B5 ^
  34.     /*
复制代码
, `' L  G3 b2 }
      1、芯片内部的LDO稳压器输出的电压范围,可选VOS1,VOS2和VOS3,不同范围对应不同的Flash读速度,$ `% {5 K3 V" l: ~8 G
         详情看参考手册的Table 12的表格。
1 ~8 x. P/ p% W9 b  j0 ^: x+ D      2、这里选择使用VOS1,电压范围1.15V - 1.26V。
' |2 P: e" y* ^   
  1. */- P9 p/ _. ]3 M3 o0 G% Y
  2.     __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    - O" E" t! ]% W- N% [+ h
  3. 6 Z- ~6 z/ Q5 ?' c
  4.     while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}" J: y$ Q( e4 N; E% \- h  |& k, K3 i

  5. / K, `5 ]9 q- d2 k7 @2 I
  6.     /* 使能HSE,并选择HSE作为PLL时钟源 */
    1 N5 v: e$ t9 ^; ?/ p/ q" u
  7.     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    : _3 w( B! }# y+ j, r9 Q* v* ^
  8.     RCC_OscInitStruct.HSEState = RCC_HSE_ON;" `# g7 T+ g- `
  9.     RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    * B0 k3 S8 I3 ]; Y, M
  10.     RCC_OscInitStruct.CSIState = RCC_CSI_OFF;: N6 T7 g. j- q
  11.     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;. I% j1 m4 b( r
  12.     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    / i6 k5 X4 p6 E/ ]
  13. : b0 x2 X3 s8 v$ ?* }
  14.     RCC_OscInitStruct.PLL.PLLM = 5;/ [5 H2 C) i4 n) m* i0 v
  15.     RCC_OscInitStruct.PLL.PLLN = 160;
    ; e: Y- g' J% }  p: G' e
  16.     RCC_OscInitStruct.PLL.PLLP = 2;: a7 V0 N$ d' Y, C' g
  17.     RCC_OscInitStruct.PLL.PLLR = 2;& t5 m2 k% l/ B8 @; u
  18.     RCC_OscInitStruct.PLL.PLLQ = 4;        - E1 W5 S! `' u9 L6 w  k
  19. ( c: V' L& c8 R' e6 l  m
  20.     RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
    ' R" M. Z$ }) B2 g' Z1 u) n8 \
  21.     RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;   
    : r- d7 j* ^$ E, K
  22.     ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);! [! w7 J9 {/ B9 q
  23.     if(ret != HAL_OK)
      F. y9 k+ T: `2 |+ Y
  24.     {8 m5 X. a0 ]- g3 `4 C/ r7 U
  25.         return 1;        
    % Y( J. p0 S# U
  26.     }' Z4 f5 j' E. N
  27. 3 O/ i4 T0 m+ K' ?9 J& N8 s
  28.     /* ! n; Y' D1 r* W( T. N+ [
  29.        选择PLL的输出作为系统时钟/ v5 c( a# E' e6 K; q/ [: K
  30.        配置RCC_CLOCKTYPE_SYSCLK系统时钟
    . c0 p3 y- U2 i8 N: Q5 I
  31.        配置RCC_CLOCKTYPE_HCLK 时钟,对应AHB1,AHB2,AHB3和AHB4总线
    9 Y6 z/ s, n+ ?* H
  32.        配置RCC_CLOCKTYPE_PCLK1时钟,对应APB1总线
    1 G3 E! l0 ~! k6 R$ c: Q, \
  33.        配置RCC_CLOCKTYPE_PCLK2时钟,对应APB2总线3 i3 |& X, @/ m$ g) w
  34.        配置RCC_CLOCKTYPE_D1PCLK1时钟,对应APB3总线  }. p- P  j! t/ e6 C
  35.        配置RCC_CLOCKTYPE_D3PCLK1时钟,对应APB4总线     
    : t  w! l8 G9 s6 W* c  o& f, g
  36.     */1 ~  \2 [) h( M" U5 `
  37.     RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \
    1 p- [' r6 z/ {. K
  38.                                  RCC_CLOCKTYPE_PCLK2  | RCC_CLOCKTYPE_D3PCLK1);
    & t3 ~& N3 C8 j- [) {3 I( w

  39. + _: H( C. _  {5 I( P' F8 K  \
  40.     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    ) X% M5 E+ W$ J, W0 T
  41.     RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;* @  P- {2 k! G% k0 P, ?
  42.     RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
    * z+ Q( B) e5 |. l
  43.     RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;  
    , Q; J% N* t: a8 l& A/ U0 ]
  44.     RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; + S# X6 C- T7 M9 u
  45.     RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
    ( g( A# G0 m& m' g6 y) `
  46.     RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; ! H9 q( u; l% V
  47. ) @- B- F. ~9 O0 M
  48.     /* 此函数会更新SystemCoreClock,并重新配置HAL_InitTick */+ R2 a4 ~# ~  e- p3 S3 a" X2 e  ^- H
  49.     ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
    * F- l8 D5 t- h: U- w! i
  50.     if(ret != HAL_OK)
    : U& p5 q( X$ O4 G- V+ Z: V
  51.     {5 a% w& a) U3 s4 N9 p
  52.         return 1;0 {% h: [+ d$ V% a0 a- _) C# C
  53.     }
    ' G, |, f- P5 f& O0 v& ?

  54. . }2 E" `+ @' }. n, H2 {4 I
  55.     /*! {; }& b. g" H0 o  Z6 [
  56.       使用IO的高速模式,要使能IO补偿,即调用下面三个函数
    ) U+ @  a+ N8 E) Y3 o8 {
  57.       (1)使能CSI clock
    + J# n0 p! e( O- _, v8 S
  58.       (2)使能SYSCFG clock
    ( ^$ a7 ]9 n  \
  59.       (3)使能I/O补偿单元, 设置SYSCFG_CCCSR寄存器的bit05 }' y0 q' l  E4 U2 U
  60.     */$ u& m3 E$ x/ m6 x' A7 c
  61.     __HAL_RCC_CSI_ENABLE() ;3 _2 W8 M2 }8 J

  62. 1 D  }, A: T0 R4 [0 B
  63.     __HAL_RCC_SYSCFG_CLK_ENABLE() ;
    4 s1 R9 U8 u/ \6 t: m3 d* o

  64. . E( h5 A& B. j; Q- N; \; \
  65.     HAL_EnableCompensationCell();
      F. k' s9 p; N0 E9 Z
  66. + G% ?8 H) L/ d/ |. k
  67.     __HAL_RCC_D2SRAM1_CLK_ENABLE();
    8 ]8 w# n4 Z( [4 W; w3 Y
  68.     __HAL_RCC_D2SRAM2_CLK_ENABLE();* v$ ^5 D# ~8 @1 o3 j, D
  69.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
    + g8 B9 D0 L' X( a- O1 G8 F4 ?
  70. ( L9 Y* z, l4 e2 }( S; F' q
  71.     return 0;+ x- J9 p) E# J
  72. }
复制代码

- z3 Z. S4 N8 B. ]& z81.5.5 第5步,配置文件Dev_Inf.c的实现
' s6 r1 o% ^+ Z配置如下:
- t: D5 t1 |& E! N: u3 u$ P1 a1 n3 B$ I
  1. #if defined (__ICCARM__)
    3 @5 t4 ^$ q3 O& }* T
  2. __root struct StorageInfo const StorageInfo  =  {7 l) `+ Y# u6 G% L- j( L3 a' I
  3. #else
    1 ~5 l' O" z" ]' M( @# Z3 |0 W
  4. struct StorageInfo const StorageInfo =  {
    ) b7 y  O4 [1 _
  5. #endif
    ) R1 X- Z; P, m4 O( ]
  6.     "ARMFLY_STM32H7x_QSPI_W25Q256", /* 算法名,添加算法到STM32CubeProg安装目录会显示此名字 */
    5 K: k% s1 S- c: c2 _6 X
  7.     NOR_FLASH,                      /* 设备类型 */7 h$ \2 P2 C# L3 V* O( w0 Q
  8.     0x90000000,                     /* Flash起始地址 */
    & U/ g6 l9 }: Z3 D4 `3 N2 d) g
  9.     32 * 1024 * 1024,               /* Flash大小,32MB */
    + g9 f$ a5 r! H& A
  10.     4*1024,                         /* 编程页大小 */
    * d. W, e, y* E7 F& Y4 F
  11.     0xFF,                           /* 擦除后的数值 */+ u, g  m3 I7 J# k, P# Z
  12.     512 , 64 * 1024,                /* 块个数和块大小 */
    - J* M6 [7 B$ s: O1 [# _$ ]3 R& v
  13.     0x00000000, 0x00000000,- Z( i$ n- i) D0 D% }; V% G
  14. };
复制代码
" J3 P- {. k- ]9 V) t
注释已经比较详细,大家根据自己的需要做修改即可。注意一点,算法名ARMFLY_STM32H7x_QSPI_W25Q256会反馈到这个地方:0 C5 }0 W0 O( X

  l4 w2 D( P: s" j, H
bc495adf8d970e6e1fb6822b88b94e2f.png

4 @& K0 K) \/ R4 S5 Y! \
1 _0 Q/ I2 p4 f6 M' ?81.5.6 第6步,编程文件Loader_Src.c的实现& R1 K& x3 W: E: R1 C
下面将变成文件中实现的几个函数为大家做个说明:# d: A$ |1 }6 n# q& F1 ?9 k1 d! M

# e1 i; z9 h( v3 e( N5 j  初始化函数Init
5 @0 K/ t% c3 j0 {% g9 ^4 U
  1. /*
    : [$ M! {: e; }
  2. *********************************************************************************************************
    : P% B$ r: W; C2 _; o7 R# w7 @
  3. *    函 数 名: Init
    + L# l; s; M1 J8 V) M
  4. *    功能说明: Flash编程初始化
    ' K! J, t- y$ S" Y0 k
  5. *    形    参: 无$ l  W3 R* Z7 o/ R: ]
  6. *    返 回 值: 0 表示失败, 1表示成功
    1 C5 d. f8 r4 \9 `$ J3 d9 F! t2 A8 L7 I
  7. *********************************************************************************************************
    $ b% I$ q$ d/ t& h1 r
  8. */. o! L% B) \, n4 |& o+ D
  9. int Init(void)5 D) N' J7 c9 c
  10. {   . b7 t/ y6 n  h
  11.     int result = 1;
    3 {: Y" r/ ?  H  F$ c8 z
  12. ' V7 I$ x/ V1 q8 k7 Y' _+ e
  13.     /* 系统初始化 */" Q7 \: H3 k+ G) @9 Q4 p' U& Z
  14.     SystemInit();
    : {- k9 L5 u" z6 _$ n- v3 `6 w

  15. 8 H: R" u& N6 V
  16.     /* 时钟初始化 */9 I# C) }3 G% q5 ]
  17.     result = SystemClock_Config();. {2 N" I. [" Q$ M5 R
  18.     if (result == 1)
    7 t, H/ q& I2 T" Z, D
  19.     {* H3 Y7 E2 W; |! r% A, V3 l
  20.         return 0;        
    * c4 D0 B. M# s( z' f) f
  21.     }
    " M+ \. S9 T# v+ k

  22. 0 ?) H+ I6 o! O# V' r( l  i/ S
  23.     /* W25Q256初始化 */
    % I3 b1 K  ?- q
  24.     result = bsp_InitQSPI_W25Q256();
    $ X, j) \% c% d" g. z: v, [8 J1 r7 O
  25.     if (result == 1)' L7 n4 Z: Q2 o7 {
  26.     {! [. O+ k* y" ^3 C8 K
  27.         return 0;
    : t* V4 e5 x( ~
  28.     }
    7 ~. ^% ?8 d, u) C1 x

  29. - O. x' g+ t0 A, `! y8 W- i. Y
  30.     /* 内存映射 */    2 k$ R# }4 [  S" d; P
  31.     result = QSPI_MemoryMapped();
    - y2 x' g, ~8 t5 n/ g9 c
  32.     if (result == 1)
    4 k9 p: H: d+ y4 m! |8 N9 A
  33.     {( R: S# y1 \1 p$ L/ T* e
  34.         return 0;$ Z$ M- f% n- B6 Q* t7 |
  35.     }1 j% y! t( b* f9 l: u3 d7 @/ z

  36. & M) {- f$ v9 r7 R6 O, k
  37.     return 1;
    : c2 c( R, K2 f( ]
  38. }
复制代码
4 F( k5 L; z5 q3 F" g6 e
初始化完毕后将其设置为内存映射模式。
0 U* f+ |0 L' e0 @2 f. ]8 B) m: `3 e( v7 n! [
  整个芯片擦除函数MassErase* ?1 D" p/ |! q% |! p4 C# A! i* l
整个芯片的擦除实现如下:4 K- C$ W. M4 v
' a6 A6 U7 d+ A
  1. /*! y! E0 P6 l1 R5 u- |
  2. *********************************************************************************************************. g6 i3 l' X  h9 P1 ?: s
  3. *    函 数 名: MassErase; U- B+ n, g. L& h1 d1 f; y
  4. *    功能说明: 整个芯片擦除
    5 `; `6 A/ w  l6 R- X- ~
  5. *    形    参: 无
    3 i8 c! h+ l, [
  6. *    返 回 值: 1 表示成功,0表示失败
    2 t0 g% O5 Y- G( q- b0 ~
  7. *********************************************************************************************************) B' K& D; `: y
  8. */
    8 A. D* l8 Y  f) ~6 M3 {
  9. int MassErase(void)
    8 w( M7 X, t3 S
  10. {6 f) ~6 p4 u& [  j1 M% N9 D
  11.     int result = 1;) M8 k8 t0 y4 F

  12. # Z; ?/ K* v! b  z( [
  13.     /* W25Q256初始化 */
    ( H0 m" @/ K, z9 n; \& \
  14.     result = bsp_InitQSPI_W25Q256();
    1 J# w3 J( u, K, o- J+ Z
  15.     if (result == 1)* v9 a! r- }2 l6 a" q
  16.     {8 r  L, r, ~1 j8 R* e& U
  17.         return 0;
    5 w! o/ S. a7 K9 C; j+ D
  18.     }2 v% [* J+ Q' k1 ?, ^7 f+ T

  19. : l  L' A# p' m: i
  20.     result = QSPI_EraseChip();
    3 S! ~* s. ]2 v4 `! Z% t
  21.     if (result == 1)- H! o7 Y- X7 g  K. @$ W
  22.     {
    $ i% V3 ~4 c5 R1 Y/ @
  23.         return 0;7 A  s2 t( F" i
  24.     }    # H% y3 c" s' b% ]/ r- e6 x% p

  25. 6 J, x9 b: o1 t- b
  26.     /* 内存映射 */   
    ( f5 ^2 j1 d/ r
  27.     result = QSPI_MemoryMapped();
    9 ^+ |" g; O- l, Z. A0 _- B
  28.     if (result == 1)
    - N3 y1 |) u% J6 ], k! l
  29.     {' D- w# a, Z% l" R& _
  30.         return 0;! G% Z, v) X; M5 [6 F* k1 `, ~
  31.     }- ?. z2 d& }9 E4 B) z6 d
  32. 9 a, s9 Y/ d" L) e/ n/ s
  33.     return result;         
    , k( B7 r% [/ s+ L" f; `
  34. }
复制代码

0 Y/ y4 l) K( A; f3 g/ d1 u  扇区擦除函数SectorErase
, w1 q* f5 D+ U8 z3 @扇区擦除实现:) x! _; w- l4 }* F4 W

1 ~# b) ~$ N- t- u0 |' Q# U
  1. /*
    $ g+ k  o0 b7 F0 @9 Q3 S
  2. *********************************************************************************************************
    . }( w* G3 x( s. ^# B4 @# E1 U* {& O
  3. *    函 数 名: SectorErase
    2 R' w! y& A. o+ N
  4. *    功能说明: EraseStartAddress 擦除起始地址7 J$ Y; t: o, J* k) U2 T/ `
  5. *             EraseEndAddress   擦除结束地址
      O; b  }0 u6 @4 P+ o
  6. *    形    参: adr 擦除地址
    5 @8 t" ~& X4 p, H& {4 Z
  7. *    返 回 值: 1 表示成功,0表示失败8 Q3 R8 y4 P( c! g  A4 e
  8. *********************************************************************************************************: }4 P9 n7 n( w* `" z/ H
  9. */
    $ @3 x; V4 T" ~
  10. int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress)8 u" ?( O' {% `" q$ ]( n  q6 C9 t
  11. {
    % b* o1 G" L6 x* i, V. a
  12.     uint32_t BlockAddr, result;
      l5 M5 X) y9 R. H& C
  13. 9 |: m& i' C2 A
  14.     EraseStartAddress -= QSPI_FLASH_MEM_ADDR;
    - r1 Q) z' N( d1 q
  15.     EraseEndAddress -= QSPI_FLASH_MEM_ADDR;# Q" B; M) Y& x7 u
  16.     EraseStartAddress = EraseStartAddress -  EraseStartAddress % 0x10000; /* 64KB首地址 */" c* ^0 ^! l- b) Q0 U% [8 x4 H* _

  17. 9 i% {- w; \4 ^$ f3 b' O; R
  18.     /* W25Q256初始化 */
    & u) g" U1 N3 a9 ~2 M
  19.     result = bsp_InitQSPI_W25Q256();
    ) A  \$ ]7 g& C, C
  20.     if (result == 1); j- M' G( l; x! L! ~( W, c
  21.     {
    : K! b# k! o; ?; z# K0 c/ i8 |
  22.         return 0;        
    5 _6 k* U0 j7 S1 u  P# n* [1 C7 t
  23.     }
    : L2 x% P8 w5 n3 f3 s* g

  24. 4 V2 X7 K3 [7 G7 ?0 f5 Z
  25.     while (EraseEndAddress >= EraseStartAddress), N* U% E3 K: Y/ B" _
  26.     {; S" T* A( f7 Z! {5 B4 \& c2 N
  27.         /* 防止超出256MB空间 */& }" b! R) v+ x* |7 |' O
  28.         BlockAddr = EraseStartAddress & 0x0FFFFFFF;
    9 \, A' h3 X: I+ V
  29. ( q1 _. w# @4 Q: L, I
  30.         result = QSPI_EraseSector(BlockAddr);    $ F6 q" s+ W. q1 e3 z
  31.         if (result == 1)5 U; \. t# `: b' i3 c* B
  32.         {+ D, x* y$ J$ r, M0 ]
  33.             QSPI_MemoryMapped(); / S" x1 t3 A* }! {; ?
  34.             return 0;        ( F# S3 G8 y8 b+ w
  35.         }- |( g" ~$ M% l9 a6 I2 q

  36. 6 I4 i& g4 O5 n/ a8 Y) n  h- b
  37.         EraseStartAddress += 0x10000;
    5 a9 |6 l6 k5 \
  38.     }
    $ G; L. b; e- w7 J

  39. 6 T2 |% a. R' C, I& n
  40.     /* 内存映射 */    . i; ^* e' E; T( z/ M
  41.     result = QSPI_MemoryMapped(); * J& [; ]& a" Q- K3 h' o9 P9 U, Z
  42.     if (result == 1)
    & a0 H$ ^+ x+ w* B
  43.     {
    2 j1 y8 W3 U- N  _- X( z; Q6 d
  44.         return 0;. r8 H6 j  ^7 O
  45.     }# l# F5 |- q; I) S7 |
  46. - ^( A7 Y1 K' l: g# h1 F
  47.     return 1; , C& e9 o; j. n5 D) @/ P0 r/ T
  48. }
复制代码

8 s8 [% S- K) E- |这里要注意两点:; z! p# e3 R4 A$ f+ |
6 l/ [4 W$ {) z
(1)     程序里面的操作EraseStartAddress-= QSPI_FLASH_MEM_ADDR,实际传递进来的地址是带了首地址的,即0x90000000。# n) V  [$ D: d3 R, l
7 I# l4 J9 R8 e: T! E# n$ _% i1 ~/ p$ `
(2)     这里执行的擦除大小要前面Dev_Inf.c文件中配置的扇区大小一致,这里是执行的64KB为扇区进行擦除。: \8 D- {5 B( k1 ]
' U+ C' F# K/ Y0 I+ c
  页编程函数Write
, x. q* r- S0 q: O  E: {  X3 a页编程函数实现如下:5 ~+ d! l% n6 T/ X  y: J

$ ~* P  t* c  z+ Z9 p2 o
  1. int Write(uint32_t Address, uint32_t Size, uint8_t* buffer)
    ; O( _/ j' ]) F+ S8 o) @
  2. { $ K5 A3 Q# [1 p# |
  3.     int result = 0;) _% l" Y+ e) N8 V8 S/ K
  4.     uint32_t end_addr, current_size, current_addr;6 q+ o# a, L# i& M
  5. " \$ S& a0 _% {; u7 k, Z
  6.   O( X# C  s4 O* ]1 x1 @
  7.     if (Address < QSPI_FLASH_MEM_ADDR || Address >= QSPI_FLASH_MEM_ADDR + QSPI_FLASH_SIZES)4 S: ?. e6 q0 W) Q2 a9 k5 ]6 M
  8.     {8 f/ F, ]6 B8 k; S! a1 V" c; s
  9.         return 0;! X2 j' \0 h+ p+ n* ^# q$ K
  10.     }3 M  Y6 O! H8 [
  11. 6 S3 G- \' c5 n2 G1 u+ q* i8 f
  12.     Address -= QSPI_FLASH_MEM_ADDR;; |7 A2 F- d' C9 \; y% \7 W
  13. 5 F! w4 j% @3 v" b1 L
  14.     /* 计算写入地址和页末的字节大小 */" C) t( D7 P0 j# b
  15.     current_size = QSPI_PAGE_SIZE - (Address % QSPI_PAGE_SIZE);+ ^# z) ^" h) }* y# d8 j' ?- ?

  16. 3 _8 y7 L5 `3 U6 _4 S! \
  17.     /* 检测页剩余空间是否够用 */
    $ S+ v, ^2 a7 m6 L
  18.     if (current_size > Size)6 L) ~; @& N. s% x& L
  19.     {
    . ]0 `3 h! |$ ]- A4 I& p( u
  20.         current_size = Size;
    - D( I/ X4 M" i4 W4 K/ |; _6 h
  21.     }8 J( J; s" _, A
  22. + ], [4 y1 F6 o0 u
  23.     /* W25Q256初始化 */" l- i$ M: U+ C% r3 U/ s
  24.     result = bsp_InitQSPI_W25Q256();
    0 C$ T$ s5 ^1 ~* j4 |* r, r! l
  25.     if (result == 1)
    2 o7 A3 D5 {' V- A
  26.     {: r8 b% W* S; y
  27.         return 0;
    $ W. U# t/ }: U/ k+ K
  28.     }, f. b6 T, \1 {& ~9 W: B

  29. & j8 ^5 Z/ E1 t1 o* \% e: Y7 M/ U
  30.     current_addr = Address;
    % z+ }5 E1 N) `
  31.     end_addr = Address + Size;
    0 p% g3 G% E1 _. u
  32. + g; ?- t' w7 }4 |# Q$ x) d
  33.     do{% u. L8 O9 @8 W3 m
  34.         if (QSPI_WriteBuffer(buffer, current_addr, current_size) == 1)
    - J! `* m9 B# J+ I6 H; ]7 H
  35.         {0 V, n. r! Q0 g/ W6 J- {. O3 u' ?
  36.             QSPI_MemoryMapped();  
    - o) E5 d* v6 S4 N; Y+ @7 c- M
  37.             return 0;  5 y) j% N9 }5 r
  38.         }) F/ g) o) a. @. Z& E: d

  39. 8 M. r( V- v7 Z+ _1 y
  40.         /* 更新地址 */0 e* {1 L9 b, j3 A6 a+ b& a
  41.         current_addr += current_size;
    3 i" q' Q$ x, n( X0 H( m
  42.         buffer += current_size;
    / p8 O! z( `. Z) S0 C4 z: O5 y
  43.         current_size = ((current_addr + QSPI_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : QSPI_PAGE_SIZE;7 S% |( o; W% _
  44. - \+ O" Z& a9 m; S- G: P2 r
  45.     }while(current_addr < end_addr);
    ; o9 n* B9 Q4 }

  46. 7 q% h% m8 i- K; @0 e
  47.     /* 内存映射 */   
    , D" _6 \, l* q7 o9 A5 D$ C
  48.     result = QSPI_MemoryMapped();
    4 d7 T6 b5 j+ l
  49.     if (result == 1)
    - ?9 f# q6 K" m9 l( I6 p1 Z
  50.     {! f) v8 s: ]8 ]* x$ `; R
  51.         return 0;. m) y6 F5 A& g- r1 q+ d# f
  52.     }
    7 S# r8 u0 E8 Q3 u  B2 m% X) f# O$ W

  53. 8 a% s2 i& B6 K! ~
  54.     return (1);  
    : ^& w5 q3 a" A8 Z
  55. }
复制代码

5 g* B+ R8 ?/ [& ]1 ?, w2 ^! G这里注意两点:
; f3 _" o- }- Y  Q' B3 D3 G' G" E2 X- c2 o- O
(1)     W25Q256的页大小是256字节,前面FlashDev.c中将页编程大小设置为4096字节,所以此程序要做处理。; C  }; ?# \+ w; C# ]% V

9 h1 j/ v, Q; c) f(2)     程序里面的操作Address-= QSPI_FLASH_MEM_ADDR,实际传递进来的地址是带了首地址的,即0x90000000。
( D+ F5 T. d- I5 H$ I) S! c6 \7 n* _7 q6 F8 M  F
  读取和校验函数
" L; J- g# A4 `4 j) T我们程序中未做读取和校验函数。3 e0 y0 h" z+ q1 d/ n- z9 h$ |( q

1 d5 v# ]1 e4 x(1)     如果程序中未做读取函数,那么STM32CubeProg会以总线方式进行读取,这也是为什么每个函数执行完毕都设置为内存映射模式的原因。6 F2 l4 F* s3 }
: T. D" o" W# Y  b" b" x* O& y! e
(2)     如果程序中未做校验函数,那么STM32CubeProg会读取数据做校验。
0 ~" L1 s7 u# d
2 C' z% ^$ q. ^; K81.5.7 第7步,修改QSPI Flash驱动文件(引脚,命令等)
( ^3 Q8 s7 \- b; ~最后一步就是QSPI Flash(W25Q256)的驱动修改,大家可以根据自己的需求做修改。使用的引脚定义在文件bsp_qspi_w25q256.c(做了条件编译,包含了H7-TOOL和STM32-V7板子):
) k6 u7 j- ^+ b
2 z1 l' S$ `* a9 m# U
  1. /* " `1 {) s0 r9 `
  2.     STM32-V7开发板接线
    9 b: X0 [, t- R- l+ _
  3. 1 v1 B" T! K# b$ T
  4.     PG6/QUADSPI_BK1_NCS     AF10
    7 P2 m8 v7 q9 `6 u. B. \6 t
  5.     PF10/QUADSPI_CLK        AF9
    ( x8 ]& S9 a4 `+ j4 M
  6.     PF8/QUADSPI_BK1_IO0     AF10! w( p" Y% a3 G& y
  7.     PF9/QUADSPI_BK1_IO1     AF10' S& J: p2 b3 U4 M2 z% x
  8.     PF7/QUADSPI_BK1_IO2     AF9" o6 U+ W) l  `9 i9 P. K
  9.     PF6/QUADSPI_BK1_IO3     AF9
    4 Y$ E6 ?+ W2 C% h4 r/ R3 b

  10.   p+ O8 c: A) i% A
  11.     W25Q256JV有512块,每块有16个扇区,每个扇区Sector有16页,每页有256字节,共计32MB% u. r/ C. f3 i1 P- r/ Q7 l/ C) ]
  12. + j9 C; {. N* t% t$ C: M3 z
  13.     H7-TOOL开发板接线
    ' u6 x1 n8 _: }0 X4 }, c

  14. / s1 |" h9 }" u9 G! V
  15.     PG6/QUADSPI_BK1_NCS     AF102 e; U" g0 x& S  j7 k3 X
  16.     PB2/QUADSPI_CLK         AF9+ i2 T* L! x, b+ ^( N6 E
  17.     PD11/QUADSPI_BK1_IO0    AF10
    + m5 Z7 d8 C- B  ~1 m/ a
  18.     PD12/QUADSPI_BK1_IO1    AF10
    : e6 D& Q6 G) A4 @
  19.     PF7/QUADSPI_BK1_IO2     AF9  x1 o( c3 h$ }. y/ M
  20.     PD13/QUADSPI_BK1_IO3    AF9, Z! u1 h) E& K+ u
  21. */
    * m6 W5 t7 C. T; j) k. X

  22. ( h$ D: O. f0 G1 Y4 P
  23. /* QSPI引脚和时钟相关配置宏定义 */1 {# N- W4 Q, K
  24. #if 0
    # o; s# @# o9 w
  25. #define QSPI_CLK_ENABLE()               __HAL_RCC_QSPI_CLK_ENABLE()
    9 c% |3 o: T* s! T  R
  26. #define QSPI_CLK_DISABLE()              __HAL_RCC_QSPI_CLK_DISABLE()
    9 q. F3 f+ l& M% a
  27. #define QSPI_CS_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOG_CLK_ENABLE()$ r' ?. y; C# _8 a9 S5 b+ [1 h
  28. #define QSPI_CLK_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE()' y5 A- I0 A4 S2 X# x# R3 ?
  29. #define QSPI_BK1_D0_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOD_CLK_ENABLE()7 y! \) X  e- Y  n8 e, |% h
  30. #define QSPI_BK1_D1_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOD_CLK_ENABLE()
    1 h2 W7 S- w& @$ y
  31. #define QSPI_BK1_D2_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()
    , x' U$ j1 A8 `
  32. #define QSPI_BK1_D3_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOD_CLK_ENABLE()
    2 {. y& b6 I; b) Z4 s0 L) k& P

  33. ; }* S, ~4 E9 B$ Y# o+ x/ K, D
  34. #define QSPI_MDMA_CLK_ENABLE()          __HAL_RCC_MDMA_CLK_ENABLE()5 e" b8 Y9 D  u2 o7 P
  35. #define QSPI_FORCE_RESET()              __HAL_RCC_QSPI_FORCE_RESET()
    + X1 v: B% H% A3 ]% d
  36. #define QSPI_RELEASE_RESET()            __HAL_RCC_QSPI_RELEASE_RESET()
      G* V; L1 L* {0 D1 P0 i
  37. $ N# q0 V  }: q# h' i/ j: l
  38. #define QSPI_CS_PIN                     GPIO_PIN_61 E3 d& x9 c2 I; n0 a# y
  39. #define QSPI_CS_GPIO_PORT               GPIOG
    " D: ]& ?: f0 @+ B
  40. #define QSPI_CS_GPIO_AF                 GPIO_AF10_QUADSPI6 C) a' F$ a; }) S
  41. 6 k! X8 i& u# w
  42. #define QSPI_CLK_PIN                    GPIO_PIN_2
    9 ^5 A% `# _$ C* t
  43. #define QSPI_CLK_GPIO_PORT              GPIOB4 i: A1 p, j% S; l9 {
  44. #define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI  O8 h9 x% e0 M+ Z8 D1 L; V

  45. 6 m* ^( _2 U0 r5 L  e* I: a7 [
  46. #define QSPI_BK1_D0_PIN                 GPIO_PIN_115 U' V$ T! D) Z! X9 `% j9 g
  47. #define QSPI_BK1_D0_GPIO_PORT           GPIOD- B, Y* o( q9 ^5 c& K
  48. #define QSPI_BK1_D0_GPIO_AF             GPIO_AF9_QUADSPI
    ! Q: e% q, j% o) ^; k& K. y) D

  49. # @: O; b. K+ P& N8 T( b! Z
  50. #define QSPI_BK1_D1_PIN                 GPIO_PIN_12
    ' P$ T! h6 @: H+ E0 j
  51. #define QSPI_BK1_D1_GPIO_PORT           GPIOD
    4 u+ S8 K. N' ~% P( J
  52. #define QSPI_BK1_D1_GPIO_AF             GPIO_AF9_QUADSPI, i- }  n7 k2 V! Z/ M+ W
  53. & Y0 d$ R: r, Z
  54. #define QSPI_BK1_D2_PIN                 GPIO_PIN_7  a1 \4 ]9 a, J' Q
  55. #define QSPI_BK1_D2_GPIO_PORT           GPIOF4 r! C' c' j8 f( X9 ?5 Z
  56. #define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI# v! ^2 i& g$ _6 B. M
  57. ; [0 I+ \+ [- B. n. ~6 {. z) K) n$ z
  58. #define QSPI_BK1_D3_PIN                 GPIO_PIN_13# t# A* F  |6 W: L' {6 e, K$ d
  59. #define QSPI_BK1_D3_GPIO_PORT           GPIOD6 k9 f! w# a# w
  60. #define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI$ x: o# ]+ U, q2 d; M
  61. #else  o, z6 W& b7 T0 t- y, v
  62. #define QSPI_CLK_ENABLE()               __HAL_RCC_QSPI_CLK_ENABLE()
    . Z5 N/ z5 g& P) n
  63. #define QSPI_CLK_DISABLE()              __HAL_RCC_QSPI_CLK_DISABLE()" R; c( E2 E& d, Q
  64. #define QSPI_CS_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOG_CLK_ENABLE()6 s% X# ~- Q1 C3 u9 N  ^! r6 E8 |1 b
  65. #define QSPI_CLK_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOF_CLK_ENABLE(), }/ j) T0 U  L+ o2 Y# U
  66. #define QSPI_BK1_D0_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()
    ! s# y& s3 A( f0 P
  67. #define QSPI_BK1_D1_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()
    ( m1 b5 o( H5 w7 F* _
  68. #define QSPI_BK1_D2_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()
    ! s/ V0 j0 Y# R
  69. #define QSPI_BK1_D3_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()+ ^4 M% }' S) ^/ O! _

  70.   R. W7 I( }5 ]0 k5 f. x+ J; Z: \5 B" t& J
  71. #define QSPI_MDMA_CLK_ENABLE()          __HAL_RCC_MDMA_CLK_ENABLE()
    $ r% j% F3 U; n; g" W3 ~7 J9 u: \
  72. #define QSPI_FORCE_RESET()              __HAL_RCC_QSPI_FORCE_RESET()1 Y, H7 U, Q3 D1 X! |2 F
  73. #define QSPI_RELEASE_RESET()            __HAL_RCC_QSPI_RELEASE_RESET()
    : R7 e+ p2 {( L( G/ G! M7 n' t8 T

  74. ( R7 r/ g# y2 A2 t/ L
  75. #define QSPI_CS_PIN                     GPIO_PIN_6
    # M% s1 A/ _2 ]' X- p$ U1 e+ Z. L
  76. #define QSPI_CS_GPIO_PORT               GPIOG
    . Q3 P; K$ O; s/ a# I" N) U
  77. #define QSPI_CS_GPIO_AF                 GPIO_AF10_QUADSPI& E& A2 c' _6 a& L/ A) I

  78. ( f9 S/ f% g8 M3 s6 V! A1 m
  79. #define QSPI_CLK_PIN                    GPIO_PIN_10
    9 j+ T- X; m, L8 W6 z- e% q6 X
  80. #define QSPI_CLK_GPIO_PORT              GPIOF
    & M, g1 w! M6 e! H% N
  81. #define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI
    + u2 _7 c" \- c
  82. 0 [5 v* C( \: L2 ^
  83. #define QSPI_BK1_D0_PIN                 GPIO_PIN_85 v, {0 z, U5 A( h" R
  84. #define QSPI_BK1_D0_GPIO_PORT           GPIOF
    8 ~: I  q6 d8 @* S+ x9 d4 b
  85. #define QSPI_BK1_D0_GPIO_AF             GPIO_AF10_QUADSPI
    ' K' w) D6 `- J

  86. - v) K6 A3 a; t
  87. #define QSPI_BK1_D1_PIN                 GPIO_PIN_9
    , F: a% a6 ^1 ^4 L2 [
  88. #define QSPI_BK1_D1_GPIO_PORT           GPIOF1 z' V! c2 I& S7 A
  89. #define QSPI_BK1_D1_GPIO_AF             GPIO_AF10_QUADSPI, O! }1 r' S. H- I  Y
  90. ) {, l4 s6 g( k( H0 t
  91. #define QSPI_BK1_D2_PIN                 GPIO_PIN_7
    ! @# p" {8 I2 O6 O9 d3 n% b- P* ?1 M$ B
  92. #define QSPI_BK1_D2_GPIO_PORT           GPIOF
    & B: k" C! n$ O+ N% C" a0 }4 Y- \
  93. #define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI
    . J' o" j6 h/ u+ [( I+ [5 z

  94. ; i9 w/ ^: L2 N- Z! _" H% s
  95. #define QSPI_BK1_D3_PIN                 GPIO_PIN_6
      R$ e' k9 O0 v' Z
  96. #define QSPI_BK1_D3_GPIO_PORT           GPIOF+ y8 h) |( U* |5 ^/ M
  97. #define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI
    " _9 i$ q, A9 U4 ?& S7 f' Y
  98. #endif
复制代码
1 u8 |( v% l( r' d* A7 @
硬件设置了之后,剩下就是QSPI Flash相关的几个配置,在文件bsp_qspi_w25q256.h:
7 Z8 S/ p) U& W! ~, u
# J( w8 D! O$ V. o% d8 b主要是下面这几个:
( S3 |  q' Z: W/ c# S
  O% D. m8 s. y3 M
  1. #define QSPI_FLASH_MEM_ADDR         0x90000000
    ( c! R  _! s; I: j2 B  V' ~

  2. : a. {5 ]$ [$ i2 u3 t# P
  3. /* W25Q256JV基本信息 */, K. x& {, t( R( @0 _
  4. #define QSPI_FLASH_SIZE     25                      /* Flash大小,2^25 = 32MB*/+ u3 u  t0 F- ^6 k3 r$ [
  5. #define QSPI_SECTOR_SIZE    (4 * 1024)              /* 扇区大小,4KB */" X: \9 y1 E( j1 `9 K
  6. #define QSPI_PAGE_SIZE      256                     /* 页大小,256字节 */
    2 U1 E1 P- w; u  j$ [, g
  7. #define QSPI_END_ADDR       (1 << QSPI_FLASH_SIZE)  /* 末尾地址 */" G! b7 [8 n, H$ G/ u8 T2 x9 @
  8. #define QSPI_FLASH_SIZES    32 * 1024 * 1024         /* Flash大小,2^25 = 32MB*/
    ! L2 V/ H6 X4 ~! I

  9. 3 b. \; i2 E: r
  10. /* W25Q256JV相关命令 */" r/ {3 U9 n3 R* N% Y$ W  R& a) W
  11. #define WRITE_ENABLE_CMD                        0x06    /* 写使能指令 */
    ( Z- y3 q; c' c2 p# s
  12. #define READ_ID_CMD2                            0x9F    /* 读取ID命令 *// n. j6 \3 Y% q
  13. #define READ_STATUS_REG_CMD                     0x05    /* 读取状态命令 */6 F6 b- k2 H1 k3 z+ Q' N
  14. #define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD         0x21    /* 32bit地址扇区擦除指令, 4KB */
    1 Y- x( E6 Z7 C! x2 d
  15. #define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD       0x34    /* 32bit地址的4线快速写入命令 */. q, g9 u" J( t, v  n; }
  16. #define QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD    0xEC    /* 32bit地址的4线快速读取命令 */
    2 }% |3 n! }- G' A5 x6 F! [1 K
  17. ' C9 W/ h6 F1 e. |4 P; I
  18. #define BLOCK_ERASE_64K_4_BYTE_ADDR_CMD         0xDC    /* 4字节地址,64K扇区 */+ _5 ?# B+ w6 S! P

  19. , {) a( L/ D/ x/ @' `
  20. #define BULK_ERASE_CMD                          0xC7    /* 整片擦除 */
复制代码

) X' V" M0 e  t9 [! u! M5 e. \. v81.6 QSPI Flash的STM32CubeProg下载算法使用方法
3 n4 J/ {1 ~) C* z1 B+ O3 e编译本章教程配套的例子,生成的算法文件位于此路径下:
- T1 b/ Y  i8 |7 `; ?8 t9 j- m- @  B, E: H- ~1 P) S
d45f9274d8762b095790b3e6778b0a93.png
! X/ L+ L) Q+ F# i0 a
: T  s2 b$ ]. B7 A
81.6.1 下载算法存放位置" {2 P* u9 S# [- k
生成此文件后,需要大家将其存放到STM32CubeProg安装目录路径:
6 I# Q- J5 s. v4 B& W% q
' q: A2 ~, ^$ ?1 ~: e\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader; K' H* U3 H9 `2 ^+ o0 @

* r# ]" X, ]2 ?( C- B" a! M
60cce5a15415e27e9d5b75b05028d1c0.png
* R2 F8 P' K. i+ G+ S* O+ E

% ~' O* Z# _$ h0 Z4 g- g81.6.2 STM32CubeProg下载配置
. u" U, i: F9 b我们这里以STLINK连接开发板为例进行说明(USB DFU或者串口方式不支持下载外部Flash)。$ E6 i+ Y' p8 e; Z  h7 w9 b4 o
; J' \$ [* z& P
9cc179641e765ea43cb38d268bf734df.png
! c+ r1 _+ @4 R6 t, ?! `7 M

' N) j/ m4 g8 i! _9 d& Y' V7 \! c# A点击Connect后效果如下:! u* ]6 b' v; X% R9 J* X0 `

5 m) Y! q$ p" r: T+ B$ F& G  }
b39ce8a738163430db2119bdd87e3fbb.png

7 L" L7 ]% z" H. _1 u1 T( R4 p- ^: M) ~/ C4 n9 U& [% _. X
在这里选择我们制作的下载算法:
0 o4 a& O9 y( c: O# p/ }8 P  W5 V, g3 S" P! i* H, `
17f6e0f50a18ae818faaa1399daef12f.png
; a5 |- B' @8 H. g- \1 A" \) `

% ^4 a6 _& N' J; E- ^1 @7 g7 y- Y% K4 M任意加载个hex或者bin文件,并按照如下配置,然后点击Start Programming
) q7 \6 q( Y. x: d1 e3 r, h# V1 r4 c7 F% O
43a0d90faf1d392f5a74eaa7777e4178.png
9 s6 y0 A! @: E2 X% M2 R9 p

) T) b$ T5 |; ?$ H下载完成后的效果如下:
. l; P3 k6 i9 D+ S$ s" Q9 }; _. `& `: F$ I6 O5 I
a1d6662baa9e7be00f7e67e02b5c9b79.png

3 w/ a; Q4 L2 G- @- {# b+ @6 \$ X
5 c3 O' x# x4 d81.6.3 验证算法文件是否可以正常使用
. \/ O* D+ J5 s" F8 T2 B为了验证算法文件是否可以正常使用,大家可以运行本教程第82章或者83章配套的例子。也可以使用STM32CubeProg直接读取:
4 V5 g7 ^: g8 l( x7 y/ k8 k" D. Z" q6 U' G4 V9 s, u; a# X% G/ U! o
3f2eefeef3db68623cb8969974c40a20.png
( `2 S3 L1 w! ^# O* X
- Y. }# j: a- T8 I& \
81.7 实验例程说明7 ]: \; H" V$ W  ^# \$ C3 H8 a; N
本章配套例子:V7-061_QSPI Flash的STM32CubeProg下载算法制作。
; T/ D* _/ U" {% T2 D4 i: W3 O. u6 i6 ?+ J1 p( ]9 B# L
编译本章教程配套的例子,生成的算法文件位于此路径下:
7 b! [) J# I9 i& o9 j2 |" ~2 }: [! x+ |
b7028271136c8053d7300063ed4aec3a.png

. p; W8 [$ `; W3 w: Y
5 }4 ^" I# L% u& f81.8 总结7 f7 S7 D8 B2 I: M
本章节就为大家讲解这么多,为了熟练掌握,大家可以尝试自己实现一个Flash下载算法。
) H2 z1 b+ q% u7 \
9 R7 E, y1 f1 q: Z6 a. w" j- B5 d; {' Q* k- m( Z: }5 ?7 ^
: |- C& F6 A2 D- ^- j6 l
收藏 评论0 发布时间:2021-11-4 23:27

举报

0个回答

所属标签

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