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

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

[复制链接]
STMCU小助手 发布时间:2021-11-4 23:27
81.1 初学者重要提示4 x/ G4 _. y5 J- @8 g+ M, ?: _
  QSPI Flash的相关知识点可以看第78章和79章。# z: C2 x$ w+ D. c# I# e
  QSPI Flash下载算法文件直接采用HAL库制作,方便大家自己修改。
( x' _+ j  H" X. f; G  STM32CubeProg下载算法制作和MDK下载算法制作基本是一样
8 j6 Q! j- z8 l) R9 p" P) l- R' B  本教程的第68章USB DFU和第69章串口IAP章节为大家介绍过STM32CubeProg的用法。
- E; W+ O) E& q. O81.2 STM32CubeProg简介
& P0 g9 O( s' X# F) T7 _% B6 sSTM32CubeProg,此软件实现了之前的 DfuSe,STLINK 小软件和 Flashloader 三合一,并且支持外部 EEPROM,NOR Flash,SPI Flash,NAND Flash 等烧写,也支持 OTA 编程。
) e0 v' u/ E7 g6 u; ^3 ?
' n5 G0 Y/ s! i8 H
1bbabf500126f58ff1439b6bc36014be.png

% ^4 ^! l$ S  W+ R$ _7 P6 H4 e% N% c2 N( @6 U1 N( Q
81.3 STM32CubeProg下载算法基础知识, H, l, i! @) k2 e
STM32CubeProg下载算法是一种用于擦除应用程序或将应用程序下载到Flash的程序代码。ST自家的芯片都自带下载算法,存放在STM32CubeProg安装目录里面,但不支持的需要我们自己制作,本章教程为此而生。
! b  q6 ]* w* s; a0 X3 s" g7 {" p+ D
, g. m' f4 t5 X& R* C9 \81.3.1 程序能够通过下载算法下载到芯片的核心思想
& a% s- W8 R6 f  ~% B认识到这点很重要:通过IDE开发环境创建一批与地址信息无关的算法文件,实现的功能主要有初始化,擦除,编程,读取,校验等,然后STM32CubeProg下载阶段,会将算法文件加载到芯片的内部RAM里面,然后STM32CubeProg通过与这个算法文件的交互,实现程序下载,数据读取等操作。' ]( Y+ W. T, e+ H* e, b

2 r# N/ @9 A7 Q9 r( c) z* Z81.3.2 算法程序中擦除操作执行流程7 H2 J2 t# {; q* s/ U
注:下面是MDK的算法执行流程,STM32CubeProg是类似的。' X) q6 `0 `" Y! |' {0 L& G* Y! ?
0 A5 h( T. T! ^& i5 e+ L4 W/ S) h
擦除操作大致流程:
, T$ J# c  x1 U+ S5 E. I
0 D& s& M: b) X3 a2 {' t) E
161f92ebd9b1dbf9febba815fa091b8b.png
0 [' M( z+ r. o  \/ Y
+ }' k7 J! m5 B- Y
  加载算法到芯片RAM。
) H! V: ~, m5 b, J  执行初始化函数Init。& h7 l( S) W( _
  执行擦除操作,根据用户配置,这里可以选择整个芯片擦除或者扇区擦除。
' ~8 C) c3 n3 L# k# W# C8 Q% J  执行Uinit函数。
+ h0 z2 [+ `8 @) W: f- J  操作完毕。
' I3 r- m3 @- \. U! r- D* u81.3.3 算法程序中编程操作执行流程
. k9 U. s, h$ T  {, K, X注:下面是MDK的算法执行流程,STM32CubeProg是类似的(没有Unint函数)。
/ U  _& C7 Z5 P5 F7 T) _' ~/ c0 }$ N9 v- n" n
编程操作大致流程:
1 [' P( G' L* L3 X/ x; y2 ]& E+ s7 f- G
d80dfd755411aa0d0565f1c56f10e66a.png

, D( f) A+ _9 g8 m6 D* p) }) g% q+ o) f- X5 |+ s
  针对IDE生成的axf(elf)可执行文件做Init初始化,这个axf(elf)文件是指的大家自己创建应用程序生成的。" l2 D! V. O4 B6 \/ v% ?
  查看Flash算法是否在FLM文件。如果没有在,操作失败。如果在:
" O, X$ ]* [, H4 |  加载算法到RAM。' i$ N& }" ]0 Q4 C
  执行Init函数。
  P; Z7 f  ]$ w& p  加载用户到RAM缓冲。
' B2 D; b( `8 Z! B! z7 d0 D  o/ p  执行Program Page页编程函数。4 Q6 ]+ D: k6 {" g- Y# e
  执行Uninit函数。0 g( D$ Q2 u2 B, R3 t  p
  操作完毕。7 F/ i# }  C0 r3 D* ~# X
81.3.4 算法程序中校验操作执行流程, j$ T9 ~) F" `( }$ O2 L
注:下面是MDK的算法执行流程,STM32CubeProg是类似的(没有Unint函数)。4 \: b; h8 k/ y0 o8 ~& W

1 C4 e# u. n3 T; y" m6 P  a3 a. O校验操作大致流程:0 q; B% @6 e$ A& `  ^3 A
" e2 B4 ~! `$ g
f15191090ab169d48a203ea3617af9b4.png
; M- p( D4 V  M" f
$ X( Y6 d% H) ~7 o
  校验要用到IDE生成的axf(elf)可执行文件。校验就是axf(elf)文件中下载到芯片的程序和实际下载的程序读出来做比较。: Y1 l1 v+ ^: ~% p7 H. p
  查看Flash算法是否在FLM文件。如果没有在,操作失败。如果在:
+ U3 r# r2 C8 h  加载算法到RAM。
1 e" E* L( b/ y5 Z, Y5 ]  执行Init函数。; G; b4 f/ w# `3 `4 z6 }: G! U. x
  查看校验算法是否存在9 ^2 c) @0 _: p
  如果有,加载应用程序到RAM并执行校验。5 M" ]% z) p$ Z# M& h7 u' h1 `/ _6 r) h
  如果没有,执行计算CRC,将芯片中读取数据出来和RAM中加载应用计算输出的CRC值做比较。0 q% T. x) A2 w
  执行Uninit函数。
% F; B4 Z( ~# s. }  替换BKPT(BreakPoint断点指令)为 B. 死循环指令。
" N0 p) l3 j0 l' R8 H( F  执行RecoverySupportStop,回复支持停止。
% o8 O. z  ~7 O) c+ V( N  \+ G  执行DebugCoreStop,调试内核停止。
1 f0 `0 P2 a  |0 x  }  X/ Q2 z+ p- i  运行应用:
- i1 y7 h9 h+ }# n  执行失败
; H$ u0 H! ~* z) Y, z" E1 D  执行成功,再执行硬件复位。" Q( ]* j! `1 W) ^" e/ C
  操作完毕,停止调试端口。
' K6 \# A5 ^4 l+ i) Q- \% d: Y! y81.4 创建STM32CubeProg下载算法通用流程
7 n" o+ s) l; p: Z2 ?! C! @下面是STM32CubeProg给的一种大致操作流程,不限制必须采用这种方法,自己创建也可以的。
7 ]9 ]; e' r5 i! H, Q  G: X
" V6 G4 A$ B& {  \1 G- y0 C* J81.4.1 第1步,使用STM32CubeProg提供好的程序模板
1 S5 ^2 l# j6 t位于路径:STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader
# F' ~& U+ Q1 R- y1 M/ ^  q
' F! s9 J  i8 O3 O9 v
4fbfb0047e29fe23083224607059d97f.png
, j2 h# m4 {5 O

  P% f7 B0 J% W( u/ Y8 s以M25P64为例(注,其余步骤就以这个为例子进行说明):7 z- x/ R5 M, u# |
% @0 l' Z7 F; P  I9 d
d1b1a340fdc655c1030330a7dad2abba.png

/ ]! i# s/ ~' G9 g+ X4 ]  k
4 h& k/ g+ d2 N8 L& c# I! m4 ^81.4.2 第2步,修改工程名
! S6 \- B" J6 D! ?9 f+ M) E2 _STM32CubeProg提供的工程模板原始名字是M25P64_STM3210E-EVAL.uvproj,大家可以根据自己的需要做修改。比如修改为MyDevice.uvproj(MDK4的后缀)或者MyDevice.uvprojx(MDK5的后缀)。
& b  y/ {* f5 w6 f) x! E. j: t5 ?1 g$ f
81.4.3 第3步,修改使用的器件5 t5 v7 T7 I$ ]( v9 g( }" }/ V
在MDK的Option选项里面设置使用的器件。
/ x! I  c' x( }  a8 `
" Z+ J0 [- o  F# V8 {7 ?
092174ad976a8ce9c7fca533049e2dd0.png

) c( y/ k0 r% u! O, t# K$ Q! h0 `+ \( F* _& d& i
81.4.4 第4步,修改输出算法文件的名字
  Z% _" E( h* {这个名字是方便用户查看的,比如设置为stm32h7,那么输出的算法文件就是stm32h7.stldr。# ?7 x3 w) d: v. Q+ o+ c

; z6 x/ `# W2 ^
79c42251311dd3892fc7d6b8ddde68b8.png
$ \. W1 n( `8 \8 h

& T) w& ^2 W" {# [5 [6 W4 |; S注:STM32CubeProg软件里面别的文件名并不采用这个,而是由用户在文件Dev_Inf.c里面定义的:
/ W9 U2 ~  I! B- T; H4 y
e2fe61fa7ea99b25b178341b7350558f.png

2 E- E! }3 v1 Q/ f/ a* k
+ r* e6 C, |# s) }$ D: [81.4.5 第5步,修改使用的库文件和头文件路径
  j% \0 A# m3 f+ |: @9 h0 o; }" U根据大家使用的主控芯片,添加相应的库文件和头文件路径。
* Z2 Q$ C+ w$ p( p8 ]
' E1 P# G8 J6 r: \0 e81.4.6 第5步,修改编程算法文件Loader_Src.c$ R5 s: ]1 X! e6 m5 q6 X" {
模板工程里面提供的是M25P64,部分代码如下:' l+ {) A1 i* i6 |8 I- e6 [

  P# X9 s! r! B, L% S9 o' P$ V4 {
  1. /**
    5 y) z7 R, k2 L9 N
  2.   * Description :( B7 L3 G' P3 j
  3.   * Initilize the MCU Clock, the GPIO Pins corresponding to the& C( `: s. U  a+ x
  4.   * device and initilize the FSMC with the chosen configuration * p7 v0 ^( u- I2 V& A
  5.   * Inputs    :
    2 p! ^# k* A6 a- f, I5 ]
  6.   *      None
    . O6 Q9 C( J/ g: |5 g/ }  a
  7.   * outputs   :% K/ n" w6 n  H" h' c, q" @# l
  8.   *      R0             : "1"             : Operation succeeded0 T7 K% M' m& o
  9.   *               "0"             : Operation failure3 K& a% w( h' c, q( B: j6 i
  10.   * Note: Mandatory for all types of device 2 d$ O6 M7 r" F
  11.   */
    ; d( x% D& k$ F8 {1 }5 u' V& V
  12. int Init (void)
    . {' S7 C' L; F4 r; G' r/ k6 K' r# [
  13. {  
    % j: r1 s" Q/ t, ]! f
  14.   SystemInit();
    : {8 P- L! Q# h* l# r
  15.   sFLASH_Init();
    % L! M$ m# \0 g. p9 M( k
  16.   return 1;. K9 z9 K  W7 z( [2 y8 [- C
  17. }. X3 ?! A+ [2 }
  18. 8 N. D6 N# D2 Y/ h/ Q7 G

  19. * i+ s# l' g. |# C% y: u. G
  20. /**
    , V7 I0 O3 d; Q& C! L; l( Z( j/ m7 ]- V
  21.   * Description :  b0 G" N3 D! j1 R8 d5 ^5 E, \
  22.   * Read data from the device
    ! q8 E9 R4 R/ N& ]2 m. `9 B+ ]
  23.   * Inputs    :
    4 d. z9 c/ \. C8 }$ p
  24.   *      Address       : Write location
    3 M% O# C# }# N0 t  {6 z
  25.   *      Size          : Length in bytes  
    9 V* N& {; p  u7 Y- O" ~- \
  26.   *      buffer        : Address where to get the data to write0 r, s) a* {; Y7 l3 K
  27.   * outputs   :
    ; S3 M# l* e( O
  28.   *      R0             : "1"             : Operation succeeded
      |1 k) ?$ h4 d6 N' N
  29.   *               "0"             : Operation failure
    / v- Q$ o! R% e7 l* P3 g5 m
  30.   * Note: Mandatory for all types except SRAM and PSRAM   
    4 \8 T. Y7 ]: c9 o
  31.   */
    & T4 h7 Q; Z2 w& E2 f
  32. int Read (uint32_t Address, uint32_t Size, uint8_t* buffer)
    " V, O7 M) o  g) ^
  33. { 3 N# Y4 w& A1 h
  34.   sFLASH_ReadBuffer(buffer, Address, Size);* r5 k- _1 |9 J0 L
  35.   return 1;
    " B# s! M: Z9 P
  36. } ) d( Y: M  D' m8 q: J$ ^

  37. 3 y, X' @+ E* Z5 c
  38. - E+ C/ z" N4 `# p7 U) @
  39. /**
    0 q3 V7 I, h' T1 T8 q! C( }
  40.   * Description :. a+ A  X% c/ T2 @
  41.   * Write data from the device # N, P& O1 r( \7 I. C, O
  42.   * Inputs    :
    & X3 ?3 @5 V- {7 u. I+ T
  43.   *      Address       : Write location
    ! w, \2 @1 X  Z$ t# C
  44.   *      Size          : Length in bytes  
    ' C/ ]% [; _' F+ {2 Y
  45.   *      buffer        : Address where to get the data to write) C. q. j* k3 @. F
  46.   * outputs   :! F% t# G" _6 g9 Y* Q6 g. R& J
  47.   *      R0           : "1"             : Operation succeeded
    - S* M# o9 y' Y* T/ z& g
  48.   *                     "0"             : Operation failure, c4 c0 [% `2 y8 X
  49.   * Note: Mandatory for all types except SRAM and PSRAM   
    / J/ n% T# n" V2 k& w, a
  50.   */
    $ `5 p' }6 {( ]7 R8 h
  51. int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)  D$ d, e( |1 M8 @
  52. {3 F8 x7 D6 |+ v
  53.   sFLASH_WriteBuffer(buffer, Address, Size);
      V5 O& v! t# W, N$ N3 V# J4 ^: D
  54.   return 1;
    * i' I* s8 `. B4 l
  55. } * w6 @7 E2 W& Y+ I
  56. 1 t: c5 a& C# S7 }3 U1 y& s

  57. 2 i' r! E3 P! u) H# F9 t5 k6 M
  58. /**1 S/ y8 H6 x, [
  59.   * Description :& j( l; r' Y: }; l
  60.   * Erase a full sector in the device# w2 i& I0 p# s9 ^8 g0 h" Q
  61.   * Inputs    :4 j$ g* ]( u' W9 N' R0 ?
  62.   *     None/ J3 r+ }) L8 P; ]
  63.   * outputs   :
    9 w8 E+ }/ w# @/ s
  64.   *     R0             : "1" : Operation succeeded
    , B) F+ b! ^5 C4 S- q2 e
  65.   *              "0" : Operation failure& l8 |: `) f, S0 T5 ]  c5 H( g
  66.   * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH
    ) Q7 J6 p: w* p0 g- r6 e3 _
  67.   */
    : l0 h- p! r) v% J2 G/ Z
  68. int MassErase (void), v! U. g' H0 K4 X+ P
  69. {  
    / `5 Y- N5 r4 G7 ~
  70.   sFLASH_EraseBulk();
    : B1 f/ V2 K% e; `1 \
  71.   return 1;    - t% m, d: R$ N' W7 H. [; m% o
  72. }
复制代码

! [, y% y# g- R7 H0 ^81.4.7 第6步,修改配置文件Dev_Inf.c
+ t. _0 b6 {2 ]6 S模板工程里面提供简单的配置说明:- }9 S6 g' z1 M& L! T1 V, c0 T
; e5 \6 u+ k7 Z* g  k& N
  1. #if defined (__ICCARM__)
    . R0 B( }# U( H2 M$ A
  2. __root struct StorageInfo const StorageInfo  =  {
    # L7 P% g$ r* _) Y; s( m
  3. #else
    " |/ i1 ?. |, l, j8 f
  4. struct StorageInfo const StorageInfo  =  {
    7 z1 _, p$ D. z
  5. #endif# P6 l( L. l; Q( N. L" k
  6.    "M25P64_STM3210E-EVAL",           // Device Name + version number
    3 x: H7 O3 @3 Q! N3 `
  7.    SPI_FLASH,                       // Device Type
    , Q$ d  |3 e( F/ Q1 X
  8.    0x00000000,                     // Device Start Address7 ]' Z; v  \3 \: u- y
  9.    0x00800000,                      // Device Size in Bytes (8MBytes/64Mbits)
    $ U% h" f& A1 w: N0 I+ m' T
  10.    0x00000100,                      // Programming Page Size 16Bytes! v0 z; K; Z# \4 b% U$ A
  11.    0xFF,                            // Initial Content of Erased Memory
    & m/ i! ]3 l1 L* X) m% {
  12. // Specify Size and Address of Sectors (view example below)8 `% y' F9 B( Q# Z0 g
  13.    0x00000080, 0x00010000,          // Sector Num : 128 ,Sector Size: 64KBytes 4 |" k! x, ^- ^/ z6 \  x, D
  14.    0x00000000, 0x00000000,. H8 Q; A" [5 J% o
  15. };
复制代码
6 c/ c# \& \  A/ T0 K  Q7 G0 M
注:名字M25P64_STM3210E-EVAL就是我们第4步所说的。STM32CubeProg会识别出这个名字。
7 X* m# U/ k' t8 h/ ?! m: \) ~) {, n
7 m- y) ^4 z$ K1 V5 S4 d# h$ E  r# w: n! I% C/ m

! V# y9 V; M# @: ?5 Z81.4.8 第7步,保证生成的算法文件中RO和RW段的独立性,即与地址无关。
: ^/ R9 H+ X$ h4 zC和汇编的配置都勾选上:% m; p. c: ]* m. U/ D
& I& V- _* Q# x7 K% T% e
8f2ba38db4c1f685f131e7f1f4e98551.png
8 a. g' [( ?; s6 j- ^: p

. Y+ z7 q- g8 i! `& f6 A/ J0 d汇编:; @# M/ e# P  v* U' f0 z

2 `4 r- c/ H! c: X- Q
0d264153b167afa2303144bdd378d501.png
3 `/ T+ G3 L5 c7 j5 A

4 i0 L) |/ U! Q6 m如果程序的所有只读段都与位置无关,则该程序为只读位置无关(ROPI, Read-only position independence)。ROPI段通常是位置无关代码(PIC,position-independent code),但可以是只读数据,也可以是PIC和只读数据的组合。选择“ ROPI”选项,可以避免不得不将代码加载到内存中的特定位置。这对于以下例程特别有用:
9 p2 @; X3 g+ @; r. r  S; f( G  j0 ]8 u( o$ j) O
(1)加载以响应运行事件。
% y! `& e* |0 r- O7 Z, F3 s) ^8 k1 V. ?, S
(2)在不同情况下使用其他例程的不同组合加载到内存中。
5 E( F% b0 D; N4 S) @% V9 Z5 W
0 s/ R; o4 N  k1 Z! T- @(3)在执行期间映射到不同的地址。
8 A+ E0 ^' D5 X& k
7 N8 X0 s9 Q/ Y" N/ K) l! }7 f使用Read-Write position independence同理,表示的可读可写数据段。
/ q; A: Z" f& k, }
( A+ B, @3 P' X0 q1 m2 w" P81.4.9 第8步,将程序可执行文件axf修改为stldr格式# ^4 v! X( Z/ v4 \' n  Z
通过下面的命令就可以将生成的axf可执行文件修改为stldr。
  ?- S9 b( _$ H. L9 a
' R2 ?, \+ N! G% [: t
f50b1594f3741e77b4fbd5523564d3af.png

- U$ t) y' K  g% a! b4 G- X4 n) A. i0 C* i+ \3 Q. ]
81.4.10   第9步,分散加载设置
) p6 Z7 P1 T- K5 Z( g: ~9 U! i- w我们这里的分散加载文件直接使用MDK模板工程里提供好的即可。% N, h/ Q: W3 g* [" D- X
$ g/ M6 b% `/ H) X. n5 t; `
8a01cb7c9be38519d4d0510a218447e2.png
+ e7 [' M' P/ g5 z7 r8 k1 C. ^6 _
+ u. _- u( T4 h+ }' R) A4 ~
分散加载文件中的内容如下:
" K% n' a- h* {7 ]! W" Z+ B( E; E  V
  1. FLASH_LOADER 0x20000004 PI   ; FlashLoader Functions  W- W! C$ L8 n. ?9 Q8 W7 S
  2. {
    0 _0 X) Y& j* G
  3.   PrgCode +0           ; Code1 e, V0 B9 k  {4 `9 a. C3 u' p
  4.   {% `1 J3 e+ s( H( `7 x) H3 `0 x3 J9 `
  5.     * (+RO)
    $ l4 G2 ~7 g$ C+ n. A+ m" v. V
  6.   }! U7 e! W, y; X
  7.   PrgData +0           ; Data
    ! B9 ~( D: V4 \+ y; w* E
  8.   {
    # E$ y2 F  |6 F! u
  9.     * (+RW,+ZI)
    6 F4 K7 ?6 s5 U% z3 u
  10.   }
    . p5 ]9 z+ V( v, f& d8 i2 M
  11. }
    & n( V& V6 D  N. ^( h

  12. ( c" X# `  e6 T
  13. DEVICE_INFO +0               ; Device Info
    , L" ^% D8 e  B2 o: R
  14. {
    0 |6 N  M) I( `8 C; `! j
  15.   DevInfo +0           ; Info structure8 {/ k# a7 g5 x/ t) {9 {
  16.   {
    8 N8 M  y: X  f! X) a0 e1 `& w' A
  17.     dev_inf.o4 D- p6 I# G. R: c
  18.   }# j$ D& h8 \: P
  19. }
复制代码

" T3 p& H6 q% l& q0 ~) a这里要修改下Flash算法加载地址,将0x20000004修改为STM32H7的RAM地址,任何RAM块地址均可,只要够存储Flash算法。推荐设置为AXI SRAM地址0x24000004,因为空间够大,有512KB。, Q5 V4 t7 ~- H
* t2 U& _& z- I6 }1 f
--diag_suppress L6305用于屏蔽L6503类型警告信息。
; u4 L3 o0 o- p  }" G" A( b  @( ?( B* {" }, z  h0 z9 u
特别注意,设置了分散加载后,此处的配置就不再起作用了:
% ], p8 U# h! M' Y2 _( N1 V  g% }7 p  r
13b022190bd5115ed249129fc3886a38.png

6 \, ~, ]! e7 a7 h0 O+ [( U4 }! s
5 U2 N4 ]' h' b2 f: U7 L81.5 QSPI Flash的STM32CubeProg下载算法制作
+ U: C$ W6 A0 ]4 W& Y& R! f8 k下面将QSPI Flash算法制作过程中的几个关键点为大家做个说明。
# v5 r% Z9 i# h5 ^# P2 f/ G4 Y9 M. H9 T; K
81.5.1 第1步,制作前重要提示2 u6 \0 e- p" H& C
这两点非常重要:
" C, g% \. j8 Z1 P4 V. P
+ F9 o9 e- ^0 Q: N4 Z3 d' Q  程序里面不要开启任何中断,全部查询方式。0 P; A* ]- ?) A- R7 t9 W9 e" d4 Q# ^
  HAL库里面各种时间基准相关的API全部处理掉。简单省事些,我们这里是直接注释,采用死等即可。无需做超时等待,因为超时后,已经意味着操作失败了,跟死等没有区别。
4 n, E8 r5 T0 ~5 |2 |! W81.5.2 第2步,准备一个工程模板$ K9 f- ^2 }+ r9 ~9 z; a( `9 z$ U
推荐大家直接使用我们本章工程准备好的模板即可,如果大家自己制作,注意一点,请使用当前最新的HAL库。0 X9 F; ]) m' ~

5 w: M* s$ Z0 h5 o( w7 _# \* E
f46a8d2276d0ffb7beee251cdb0809a4.png
. z& J5 Q9 `  F& E: U

. z7 S# N- g- R! F3 Q81.5.3 第3步,修改HAL库* l' K3 K7 P. ^( y
这一步比较重要,主要修改了以下三个文件:. x; M& C: W, t4 ?
# {5 d2 F/ ?9 O# e/ d" {$ I' p
1efb78256b9465df406e3e9e95ae30e5.png

- p. K% N4 f: b2 a6 U
& u( N- J9 [, c+ j* h  e主要是修改了HAL库时间基准相关的几个API,并注释掉了一批无关的API。具体修改内容,大家可以找个比较软件,对比修改后的这个文件和CubeH7软件包V1.8.0(软件包里面的HAL库版本是V1.9.0)的差异即可。
3 e1 b( e. U# y. }8 |- c; `$ \" [( Z. z& A* T  I+ S
81.5.4 第4步,时钟初始化
7 U/ t; V) `  g  P我们已经用不到滴答定时器了,直接在bsp.c文件里面对滴答初始化函数做重定向:
: P+ {1 a/ L& L2 O+ c  x7 |3 W
  1. /*, ]+ D, _$ F* c/ V0 f$ I
  2. *********************************************************************************************************/ K- `+ i2 W( w% ~$ B8 f/ A. K
  3. *    函 数 名: HAL_InitTick1 r! L7 E3 Q! m. |+ r& p
  4. *    功能说明: 重定向,不使用
    # m: N, ?- _) s+ D: Y
  5. *    形    参: TickPriority/ S7 S. q8 w3 v! L" T
  6. *    返 回 值: 无- V% v' E( C( h% z
  7. *********************************************************************************************************
    ; N; k- ?, @( v* h( k
  8. */
    9 {  A' b2 f  ]9 J+ i$ i
  9. HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
    1 j5 e( ]6 k* R7 [
  10. {
    0 @2 ^2 N" f4 u* }0 K4 a7 P
  11.     return HAL_OK;
    7 F0 L/ H, H) o. ^! R9 V
  12. }
复制代码
7 q; m# t0 ]9 K$ P+ L7 _
然后就是HSE外置晶振的配置,大家根据自己的板子实际外挂晶振大小,修改stm32h7xx_hal_conf.h文件中HSE_VALUE大小,实际晶振多大,这里就修改为多大:
! @3 T2 m9 O  z8 z
; i' m, d5 e: p. z) b  c% Q) ?* I
  1. #if !defined  (HSE_VALUE) # |, x+ i0 C+ g: r" O
  2. #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */: N1 X  Z% K6 i1 h
  3. #endif /* HSE_VALUE */
复制代码

8 |+ `: V4 L0 J最后修改PLL:6 s9 D& e, U. B" r" I4 m: _3 t
8 v4 R8 U- S7 Z
  1. /*9 t" O* `5 m, n
  2. *********************************************************************************************************# O5 I" T4 X+ b- ~; z; m
  3. *    函 数 名: SystemClock_Config; u( ^$ M5 A# I( d3 \$ |
  4. *    功能说明: 初始化系统时钟
    / P7 q7 i- g8 o( `+ G
  5. *                System Clock source            = PLL (HSE)
    " @+ q4 q0 J4 F, m9 O; T% C
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock): L& P7 B2 d3 x  v
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
    " ~( _1 d2 R5 H; O, X
  8. *                AHB Prescaler                  = 2
    ' l* \1 s+ E* I8 Z
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    ( V0 y+ y8 H" ]& \9 y( h
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)
    + y3 O' F+ @9 |
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz), l+ l7 U( v# v+ i  r
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)$ L9 `* X& m) Q. `  F( E
  13. *                HSE Frequency(Hz)              = 25000000
      X( v% s5 O9 ]- b/ A9 X. Q4 T
  14. *               PLL_M                          = 5
    & v& z8 a+ O  C5 |6 b# a9 J2 F. V% V: a
  15. *                PLL_N                          = 160
    : j0 ?8 c7 }+ U, R% v
  16. *                PLL_P                          = 2
    & m4 z* T" ^  n/ q) E
  17. *                PLL_Q                          = 4( [3 ^; K6 ^" k+ f
  18. *                PLL_R                          = 2
    ; Z& d1 x/ j4 i  i
  19. *                VDD(V)                         = 3.34 @2 m7 G7 M2 l, K0 P8 d# y
  20. *                Flash Latency(WS)              = 4% B3 G& J6 J# V  A# m0 p
  21. *    形    参: 无/ K5 d7 N9 W7 n" l: S1 Q
  22. *    返 回 值: 1 表示失败,0 表示成功
    / Y# N( f/ v) x
  23. *********************************************************************************************************! u3 W% H4 S9 {6 S1 D3 u. d0 d
  24. */+ `+ j7 S) S. O2 l/ _/ a6 D& L2 ^& w
  25. int SystemClock_Config(void)! r0 I) F" H* u7 N/ X- b& Y
  26. {
    , X# n# F) L5 ]
  27.     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    ( @" K' ]8 s5 s/ E6 _) |/ \
  28.     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    0 L& E" q% h0 s/ N) p: r
  29.     HAL_StatusTypeDef ret = HAL_OK;
    5 x7 j: F: Z0 S0 u; _5 G
  30. ; G7 u+ P: r1 e
  31.     /* 锁住SCU(Supply configuration update) */, r/ `9 j3 s2 \) L$ M' x( \
  32.     MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);* E5 e3 t8 G1 ?# o7 l5 F
  33. ( ^& q* k; u; x9 L" A5 w1 w. u
  34.     /*
复制代码

" c) _, g! k1 U' i, u7 T      1、芯片内部的LDO稳压器输出的电压范围,可选VOS1,VOS2和VOS3,不同范围对应不同的Flash读速度,9 `# a0 C6 k: K" B% W
         详情看参考手册的Table 12的表格。
2 Q- ~* I5 H4 e" Z7 t      2、这里选择使用VOS1,电压范围1.15V - 1.26V。
4 X" X8 C: l8 M) Z  d   
  1. */
    2 k8 p4 z4 [) X' [
  2.     __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    ) _' H7 o# n% d! U0 m/ z

  3.   ~) R8 u6 p! @+ d/ P! d0 ~
  4.     while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}0 q; e* g0 ~8 j6 M( F
  5. 2 b9 h& i! _( P& ?2 {/ X3 o
  6.     /* 使能HSE,并选择HSE作为PLL时钟源 */
    / T' x8 o% ~; u7 x
  7.     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;! {5 l- ?5 X& L7 a- f! K, c- P
  8.     RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      ]& J( m+ K5 [9 m6 U
  9.     RCC_OscInitStruct.HSIState = RCC_HSI_OFF;& P* I. L' u. }; v
  10.     RCC_OscInitStruct.CSIState = RCC_CSI_OFF;" v. y$ d* v7 J# y8 j- d
  11.     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;/ B, e3 F  u- Q8 b+ \5 V' ^
  12.     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    3 `4 |3 U& [6 C* E8 e

  13. + r( f* o1 ^8 }: t2 F8 ^
  14.     RCC_OscInitStruct.PLL.PLLM = 5;
    6 s( _; k# ~" X$ e1 u
  15.     RCC_OscInitStruct.PLL.PLLN = 160;0 j6 m+ g" c& P( C1 {9 e2 H" d
  16.     RCC_OscInitStruct.PLL.PLLP = 2;1 F/ i# S% V7 w+ ^: {5 _
  17.     RCC_OscInitStruct.PLL.PLLR = 2;
    / I2 K, M% M8 D' T' W
  18.     RCC_OscInitStruct.PLL.PLLQ = 4;        
    6 `' a1 ~  P0 w* E( ]. U

  19.   K4 J& n, `9 L6 Z
  20.     RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
    $ F, |( `, ]! u5 k, P
  21.     RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;    4 ?( `* o# [3 d% _7 v$ I: d7 y6 B$ d
  22.     ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);, N3 U$ ?# z" R1 w* C  ?
  23.     if(ret != HAL_OK)4 g" b. {% ?- K" r( }. [
  24.     {
    & m+ A- v" b  H% r
  25.         return 1;        1 J9 \! C$ U" ]5 D. H. U9 S# N2 K
  26.     }
    4 ]) Z2 r7 x+ r: t2 {& c
  27. ) ~3 l- F. p- ]( Q& [4 w
  28.     /*
    ' z7 L2 O, O2 g/ P/ f
  29.        选择PLL的输出作为系统时钟) ]# e% e  ?( k# V" P8 W5 U
  30.        配置RCC_CLOCKTYPE_SYSCLK系统时钟
    ' C2 e2 s1 N: |: }& H
  31.        配置RCC_CLOCKTYPE_HCLK 时钟,对应AHB1,AHB2,AHB3和AHB4总线1 M* x' R, u5 }4 N4 Z; Z
  32.        配置RCC_CLOCKTYPE_PCLK1时钟,对应APB1总线
    / ?" u4 }: J) B% _& I
  33.        配置RCC_CLOCKTYPE_PCLK2时钟,对应APB2总线
    + l1 g! N6 b3 {, O) r0 ~
  34.        配置RCC_CLOCKTYPE_D1PCLK1时钟,对应APB3总线
    * i7 S, j; f6 o  s; l" B  ^
  35.        配置RCC_CLOCKTYPE_D3PCLK1时钟,对应APB4总线     
    ! F6 |: G& S* }& _; b: p$ U
  36.     */5 S: d& y+ @: u9 D. N
  37.     RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \( y/ W3 T2 _" B  f3 F6 y
  38.                                  RCC_CLOCKTYPE_PCLK2  | RCC_CLOCKTYPE_D3PCLK1);" T, K% X) L& \# {1 |

  39. 7 ]& H  Z" i' @0 B+ k2 v
  40.     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    + X5 ^/ w3 R: r3 ]1 w
  41.     RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
    ) }4 z1 c& F+ {" \: s1 J" F
  42.     RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
    ' g! y* o, P% O6 u% |( i6 I& K
  43.     RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;  , n4 k! T- |- j% `
  44.     RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
    5 V) m6 U5 e0 L% l4 i
  45.     RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
      k0 X8 n, C$ {& g3 i9 Q; r* n
  46.     RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
    & C; @5 Z  X4 `% B/ a: F
  47. - v! G% K/ C" G' }
  48.     /* 此函数会更新SystemCoreClock,并重新配置HAL_InitTick */
    ' r5 f  @# \/ {: V( V
  49.     ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);4 p; C/ P7 W& N# l
  50.     if(ret != HAL_OK)8 h( ^7 M7 B) \" m
  51.     {
      B/ A' {+ K3 d, M( }
  52.         return 1;& [  k' ^% {( o, |2 x# n
  53.     }
    % S1 n1 k$ q+ ]" `& m# n

  54. ( l! S& m# ^# _% [
  55.     /*. y5 A- t- W9 N/ N7 o
  56.       使用IO的高速模式,要使能IO补偿,即调用下面三个函数
    5 \- S9 D0 ^( z( X/ H
  57.       (1)使能CSI clock
    ' t9 C% S* a% G1 _2 k% M. r9 _
  58.       (2)使能SYSCFG clock: P: w! z- D3 B- A; R. A
  59.       (3)使能I/O补偿单元, 设置SYSCFG_CCCSR寄存器的bit0- {+ m7 L$ ]2 r: @  ?
  60.     */" M( K' W5 {7 t
  61.     __HAL_RCC_CSI_ENABLE() ;
    1 t, m* w) h0 r2 G, g$ L
  62. . A& o8 g" X. U7 d6 p
  63.     __HAL_RCC_SYSCFG_CLK_ENABLE() ;) [2 ^& f& s  l- d) Z

  64. 9 f+ M9 }, I  m3 R5 {
  65.     HAL_EnableCompensationCell();- C+ E0 P3 E$ `, _" a! I/ W2 w9 r

  66. 7 t$ w6 G5 i1 c% C0 _
  67.     __HAL_RCC_D2SRAM1_CLK_ENABLE();2 C4 W- l* B# _
  68.     __HAL_RCC_D2SRAM2_CLK_ENABLE();1 A$ s- y2 s6 W% A! ]
  69.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
      q# M6 t; p' n  i5 L

  70. ! p3 b1 n  i  x/ {) U! g3 r
  71.     return 0;* s; v1 j0 k# H
  72. }
复制代码

) H" H3 H' H3 J. x) F0 H6 O2 e81.5.5 第5步,配置文件Dev_Inf.c的实现
2 P3 _, S2 N( H: F3 ~$ ^  i5 ]配置如下:# o, j% R; t3 l. ?' O
) F5 I6 p/ k! `$ K
  1. #if defined (__ICCARM__)
    ; m6 U- a# N! J* S3 G& O
  2. __root struct StorageInfo const StorageInfo  =  {, ^# [9 F2 {# p8 O- G
  3. #else
    1 [0 P9 t6 E# y) S+ Y# ~
  4. struct StorageInfo const StorageInfo =  {
    * ^: O6 W5 w2 E. j" |6 Y5 z- E: \
  5. #endif
    8 q4 O9 k- L, X7 c, K
  6.     "ARMFLY_STM32H7x_QSPI_W25Q256", /* 算法名,添加算法到STM32CubeProg安装目录会显示此名字 */
    % Q7 a1 o. U6 G
  7.     NOR_FLASH,                      /* 设备类型 */
    + Q1 x. c. j2 O4 J- T; @
  8.     0x90000000,                     /* Flash起始地址 */) G9 a# E8 U" W3 o* s$ M
  9.     32 * 1024 * 1024,               /* Flash大小,32MB */% S# J, C/ }$ W# f7 |0 A+ p
  10.     4*1024,                         /* 编程页大小 */
    # v; |$ e. M6 F" k  M7 f
  11.     0xFF,                           /* 擦除后的数值 */2 e8 y3 G. B+ i5 w: g; F7 I
  12.     512 , 64 * 1024,                /* 块个数和块大小 */
    9 z; C2 H9 [/ F/ o  C
  13.     0x00000000, 0x00000000,0 y! f/ e5 h) a, X
  14. };
复制代码

" m: C4 l) V5 Z8 M注释已经比较详细,大家根据自己的需要做修改即可。注意一点,算法名ARMFLY_STM32H7x_QSPI_W25Q256会反馈到这个地方:
$ w# ]- T9 ]! g; K# A
* `% r% Y0 v9 @1 I- m
bc495adf8d970e6e1fb6822b88b94e2f.png
0 X, q+ M; P; I# Y% \  e: N
5 u" U: L/ R2 ?% Q7 d. A& E
81.5.6 第6步,编程文件Loader_Src.c的实现
4 F8 @" t! z$ x1 X下面将变成文件中实现的几个函数为大家做个说明:
- h% M0 k- P2 m2 P2 G$ o. S3 x4 O! X
1 l4 O1 Q5 X& m; Z% Z' y5 z/ j  初始化函数Init
6 s% ]. C% v0 @8 c
  1. /*
    1 F6 }8 c) M7 I' v% |
  2. ********************************************************************************************************** h% `& i  R: O2 x! U0 z
  3. *    函 数 名: Init7 T+ E% Y1 T4 F! R1 ~' O5 H
  4. *    功能说明: Flash编程初始化
    8 w9 \3 ~7 c0 A" v  g
  5. *    形    参: 无
    . H2 |4 ^( m" a, _- m
  6. *    返 回 值: 0 表示失败, 1表示成功* I3 b: J" e8 z( h9 [; C
  7. *********************************************************************************************************
    7 J- g( `- s( b5 j) c5 y
  8. */
    + o5 I4 i* W( S( ^' _0 b7 g2 u
  9. int Init(void)
    5 K, T  V1 u; U4 v
  10. {   3 Y1 f% C) a  n4 u
  11.     int result = 1;5 n. z! @2 U5 X; R$ q
  12. : q' ~  k+ S9 ~) z! Q+ L9 d
  13.     /* 系统初始化 */
    " Q6 r: F7 [+ A) d
  14.     SystemInit(); & y, c5 o  x0 F; \4 C% M2 I

  15. 2 r+ {6 u- E2 U3 I
  16.     /* 时钟初始化 */
    3 ~: G, ~" o/ g
  17.     result = SystemClock_Config();2 _* w& U8 z7 z- g$ Q
  18.     if (result == 1); t8 C6 I. \* j0 g" T
  19.     {& d. C# X+ R8 H$ ^# S% q
  20.         return 0;        
    ) ]/ x  C; d6 G! V+ I! w
  21.     }. d) a3 |  s+ `) |9 d
  22. " y# z, X" @0 F! r; K
  23.     /* W25Q256初始化 */# z. r( R/ |: f/ u" X3 _
  24.     result = bsp_InitQSPI_W25Q256();) _% M5 K' b- E) a/ W- |
  25.     if (result == 1)
    - b, `% H$ t9 Z$ L0 t8 Z+ H  G
  26.     {9 n) U0 q9 ~! ^8 z) U$ P
  27.         return 0;' l+ z: P9 Q- C9 I
  28.     }
    ) v' j; ^4 [3 [

  29. : [6 ]1 L% T! d& L. m$ U
  30.     /* 内存映射 */    & g& X6 x% @, ^4 ^
  31.     result = QSPI_MemoryMapped();
    + G0 o, S: a8 {1 t
  32.     if (result == 1)
    5 S  X; d. N) X( d
  33.     {) J& R- e( f* ^
  34.         return 0;
    0 {/ W( }" t# A* |4 B3 L. j
  35.     }
    ; ~. {( _, I9 p# R

  36. : L. j$ [; y, ]/ p. A; ~( j/ b
  37.     return 1;
      O; O7 H0 @6 B( e  A
  38. }
复制代码

8 T' Z8 e5 }# Z+ v初始化完毕后将其设置为内存映射模式。
- W2 A: }9 x$ i4 m0 P$ l( k6 p" n: j& W+ {% F$ V9 Z
  整个芯片擦除函数MassErase) K# i. A1 P5 O  V* S) N
整个芯片的擦除实现如下:2 R2 R7 U8 s0 o
" U# ^6 W& b+ x) l. \- ?
  1. /*
    : w; O3 r7 ~5 C- S; Q
  2. *********************************************************************************************************1 s, Z5 ^' @% S( C
  3. *    函 数 名: MassErase" L; y% p% N" j+ i% K
  4. *    功能说明: 整个芯片擦除+ D& u7 h: W8 i! O: h
  5. *    形    参: 无$ \4 ~  e( {5 o, j2 C6 }- x
  6. *    返 回 值: 1 表示成功,0表示失败
    ! y; m& e. ^- C" d( j
  7. *********************************************************************************************************
    $ S# H4 P( P8 X  \8 C+ U
  8. */) k! _) v- R' [$ I- w0 j3 |" {- x; A
  9. int MassErase(void): O2 m- e9 r' X5 D; a, h
  10. {( D  D: z. m0 U/ n& x; x
  11.     int result = 1;7 ~( r  V1 v3 W6 k1 b

  12. . X' H% c8 E# p: G( U
  13.     /* W25Q256初始化 */
    6 B# A2 m2 [7 L; S5 N
  14.     result = bsp_InitQSPI_W25Q256();0 ~8 t5 p: v: J( o! @6 t% f- ~2 `; h
  15.     if (result == 1)  Z+ Q8 C+ f& ~
  16.     {1 l8 Z% j5 K, a) O% S
  17.         return 0;
    ; j5 e7 O" m: Y2 Y" y% C6 h( V! b
  18.     }& ]- f9 \' ?, i
  19. 6 {4 n8 I$ y; F1 w0 g3 \# `
  20.     result = QSPI_EraseChip(); " _+ v7 E( {4 t9 ~
  21.     if (result == 1)0 u  B8 i& `5 b4 f, W
  22.     {
    / }  D1 E1 w- R" }5 H
  23.         return 0;
    5 {2 s7 e3 K1 X9 K) X. l( q% U
  24.     }    ; k# l0 L4 ]3 i
  25. 8 ?; W2 {/ o% w: o' T; q: v5 T
  26.     /* 内存映射 */    + e; x1 T3 h0 X" `/ C" R$ `
  27.     result = QSPI_MemoryMapped(); ; e" e% B6 F% R8 Q
  28.     if (result == 1)
    ' P! u; s/ G, k  j( c0 y6 q
  29.     {( h5 q# Y, y) B" w
  30.         return 0;
    % ~1 o# u# c; j# Z  }+ [: i3 m
  31.     }/ T+ E. {3 G" w0 k) m3 Z2 x: a1 ?7 a/ o
  32. ) ^0 ^3 w  X* }: l+ P
  33.     return result;          9 V* _# l8 w8 u$ u
  34. }
复制代码
& |3 u$ j0 D, D4 ~( M) R! f
  扇区擦除函数SectorErase  Z5 ?6 D1 [# l1 W, l+ L
扇区擦除实现:: q; Z* a( W" t" _  V
6 H/ I3 @& a7 ?# l2 v
  1. /*4 K" _* U9 H; v5 H
  2. *********************************************************************************************************
    ( M, B" s; m7 l
  3. *    函 数 名: SectorErase( q& @5 X: y2 o
  4. *    功能说明: EraseStartAddress 擦除起始地址* K) E1 ]: n8 \. F
  5. *             EraseEndAddress   擦除结束地址% t. H# R( N/ |2 K- T/ j
  6. *    形    参: adr 擦除地址
    + X  O3 F: I, q( K
  7. *    返 回 值: 1 表示成功,0表示失败
    1 b* [) G8 Z7 J8 ]3 A
  8. *********************************************************************************************************
    8 U, F/ W0 D( e3 G
  9. */
    , j1 b% s+ J. s7 a: a+ m9 m
  10. int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress)( a3 f8 {: U  [; a1 J; o
  11. {/ R0 L& b# @/ [, W! Z! G
  12.     uint32_t BlockAddr, result;
    $ o! w# P2 }' O6 J6 B) w0 E+ O- k
  13. 6 ]' x" W& i! s: D
  14.     EraseStartAddress -= QSPI_FLASH_MEM_ADDR;* @) ^$ c5 C1 U- h2 _6 y/ g
  15.     EraseEndAddress -= QSPI_FLASH_MEM_ADDR;/ b( a! h; l2 f* o# ^9 ]# @
  16.     EraseStartAddress = EraseStartAddress -  EraseStartAddress % 0x10000; /* 64KB首地址 */) A% c2 T# u7 e# W

  17. - u- f, q5 K3 L# |5 ?0 p
  18.     /* W25Q256初始化 */; G+ s  P" ^9 x6 ]" [
  19.     result = bsp_InitQSPI_W25Q256();! W4 ~$ K6 O1 r$ I; q4 p% F8 M* m: X# C
  20.     if (result == 1)
    6 B/ q- s  {, h3 E3 A/ @
  21.     {. @9 u; ~  T) d/ W
  22.         return 0;        , E0 ]1 ^$ d* s7 j9 _
  23.     }
    1 M5 [. f, l. a# x) E' p

  24. 8 c0 U5 W; h9 M; i, X$ m0 G
  25.     while (EraseEndAddress >= EraseStartAddress)
    % ~( _5 C8 z; C; {' b
  26.     {
    / L  [( |, u3 H
  27.         /* 防止超出256MB空间 */& K6 A  j3 i) C' D- x
  28.         BlockAddr = EraseStartAddress & 0x0FFFFFFF;! R. n& x( B$ x. N3 w, K; o
  29. 0 U+ [% @9 p3 v- D' R1 |% a& j
  30.         result = QSPI_EraseSector(BlockAddr);    # \  S, @8 \/ D$ I! g0 ]
  31.         if (result == 1)
    1 V) |8 X4 D5 X, Y+ T- J9 Z
  32.         {
    3 `& n! }' H3 E  ]3 `8 o
  33.             QSPI_MemoryMapped();
    * F# X9 l8 o6 _- P7 X
  34.             return 0;        5 T  \4 Q. t: A- F  H; T
  35.         }
    9 G8 D1 j3 z  F9 f. l* c

  36. 9 I4 }4 J4 P. t, ~& {3 {# D4 F' `
  37.         EraseStartAddress += 0x10000;2 _  K4 w, d* f5 \: e, y/ y
  38.     }
    & D8 X  x  Y1 z" F7 [; W
  39. - T" c# b3 R/ H# y" F! O. e
  40.     /* 内存映射 */   
    , [( D0 C( H3 @: w
  41.     result = QSPI_MemoryMapped();
    : @( Z4 u' d* h4 R
  42.     if (result == 1): R2 _5 u$ G, V+ i+ Q( |6 e
  43.     {
    " _: a5 L/ O1 J" F+ ?$ d& \
  44.         return 0;
    8 V1 \8 V( E) ^& ?2 {) [5 f
  45.     }8 T. c! r0 G1 R* T
  46. . {- W$ T* F3 w# F. Q* Q5 n& V8 n5 f
  47.     return 1; 4 n1 \) v& r/ m% T5 G
  48. }
复制代码

6 X$ d8 [# C" x& {这里要注意两点:/ a3 F2 Z  ~" [/ E- ~( n

/ ]+ [8 I: t; C9 q(1)     程序里面的操作EraseStartAddress-= QSPI_FLASH_MEM_ADDR,实际传递进来的地址是带了首地址的,即0x90000000。
9 Q1 Y8 U- g% M  I9 H7 [; l0 q+ r2 d2 F+ x6 r6 v8 W
(2)     这里执行的擦除大小要前面Dev_Inf.c文件中配置的扇区大小一致,这里是执行的64KB为扇区进行擦除。
# n; @: h, V! [! Y& D' ?7 [, S: }- M0 _
  页编程函数Write
4 R+ P: g7 A2 A0 t6 |- f! v2 e3 z页编程函数实现如下:
1 m3 p" X+ l3 q8 m6 y
* Z, O2 R6 s& A: r4 l
  1. int Write(uint32_t Address, uint32_t Size, uint8_t* buffer)
    : V, s# S) D, [9 z6 ?
  2. {
    8 C2 X- \5 T2 K6 R0 g5 ]* {7 O
  3.     int result = 0;& C, f- P. q( K! x# W4 [
  4.     uint32_t end_addr, current_size, current_addr;
    # ^3 w8 J/ _3 ?& H, I6 O# f

  5. ! m3 f# r4 m8 Q- F6 m: R
  6. % H. T( K# a) F3 \! _% k/ g
  7.     if (Address < QSPI_FLASH_MEM_ADDR || Address >= QSPI_FLASH_MEM_ADDR + QSPI_FLASH_SIZES)
    # J8 r/ q: D" F7 E& K$ J
  8.     {( v# s; Q+ S: u8 d9 C
  9.         return 0;
      a" |  v* X. T& B
  10.     }; k8 N* N% g  r) _3 j

  11. : w, ]& S  F, Z8 H
  12.     Address -= QSPI_FLASH_MEM_ADDR;) R' [; G2 [3 k3 R# J/ t( V1 b8 d

  13. & Y, ?0 \% D! x$ u0 K$ c
  14.     /* 计算写入地址和页末的字节大小 */4 ?+ j6 w* Z8 E2 P, h
  15.     current_size = QSPI_PAGE_SIZE - (Address % QSPI_PAGE_SIZE);
    # j9 f% [8 b0 v9 a  O" z7 p; D
  16. , c- H- s/ z* [" T" |
  17.     /* 检测页剩余空间是否够用 */
    / I/ c9 D& }) P% }  }
  18.     if (current_size > Size)
    0 k6 v$ \4 b9 A* y
  19.     {% f% j" T' w4 B, m* @& i! @+ H( N
  20.         current_size = Size;! U7 y5 w  \) `4 X2 q
  21.     }- x/ B( c) i! t; |% N4 B
  22. ( P# `. E" r! F1 ~& B( M
  23.     /* W25Q256初始化 */
    % s$ z2 x4 ^/ w# W+ b0 d4 J" O- }4 L4 W
  24.     result = bsp_InitQSPI_W25Q256();
    & m$ T  c# ^1 }2 M, I
  25.     if (result == 1)* Y) O8 P5 V( `  X. |
  26.     {% o3 e* G) X- q: S4 _- n
  27.         return 0;: i- A+ j, L5 d& v; m; s
  28.     }: b1 n* m4 W# ~# B1 o1 \$ [% o2 M

  29. 3 x0 S5 T. \2 R
  30.     current_addr = Address;7 u4 G4 {  k1 |( o% i0 f# v% L  v
  31.     end_addr = Address + Size;( S: L, X$ i+ Y( v+ _! J% }
  32. + S* w. Y5 Z) a
  33.     do{5 ?% Z/ E  x7 t/ b3 A: f
  34.         if (QSPI_WriteBuffer(buffer, current_addr, current_size) == 1)3 Y) u) w/ A' e' ]/ A6 ?4 V2 ~: M* X
  35.         {
    7 P2 S! k/ ]0 ~8 j
  36.             QSPI_MemoryMapped();  5 e4 i5 L' `/ S+ g) ]% N
  37.             return 0;  
    - h6 S' I" }9 J8 T
  38.         }
    1 W- C' t, s% U# t8 t, \/ r

  39. & K7 o9 V& Y. c' Q
  40.         /* 更新地址 */
    " P" T6 p5 @! E. t- y9 @" g
  41.         current_addr += current_size;: r5 H( v; x6 q2 P0 H
  42.         buffer += current_size;. p. C' v0 H: \( c# E
  43.         current_size = ((current_addr + QSPI_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : QSPI_PAGE_SIZE;& Y/ t  e& b0 f' O  A5 C! F  o, s
  44. % m8 ^5 j. A% z) b5 b. k6 z
  45.     }while(current_addr < end_addr);) M% f9 l' h- x! b& F  Z" B

  46. % S' |  R+ F3 a+ m
  47.     /* 内存映射 */    / [/ ]5 Q4 {; y7 T4 C$ I- M$ q
  48.     result = QSPI_MemoryMapped(); $ e+ R$ E" ^/ L$ l1 l3 Q
  49.     if (result == 1)% {( g/ A5 I! J7 C
  50.     {5 h6 ~- B) t6 c: m2 Z3 q; B
  51.         return 0;* `& @  i! y. K! N8 I
  52.     }
    6 @% H+ X8 o0 ]: x/ W

  53. 4 ^+ A) O& C8 z: T
  54.     return (1);  2 c( X0 b4 K0 R. X1 @
  55. }
复制代码

4 V3 d) T/ ]4 F3 o  \1 G这里注意两点:
) E" ~$ _. a0 Y( g7 L
  C0 I) @' _" I9 w% X% Z% D(1)     W25Q256的页大小是256字节,前面FlashDev.c中将页编程大小设置为4096字节,所以此程序要做处理。
3 N) A) ]9 U; d; i! u) j
  V- \; p' [2 S8 Q(2)     程序里面的操作Address-= QSPI_FLASH_MEM_ADDR,实际传递进来的地址是带了首地址的,即0x90000000。
# m% Z8 b3 }, Y
* T3 z( {- i& g0 {: h5 o  读取和校验函数& Y2 i* z+ \! ?, V6 [% y& s! a* n+ U
我们程序中未做读取和校验函数。$ x7 R! D8 ?% }3 F$ U6 L$ p
9 J% l% t) L4 Z7 G0 H) |$ \
(1)     如果程序中未做读取函数,那么STM32CubeProg会以总线方式进行读取,这也是为什么每个函数执行完毕都设置为内存映射模式的原因。" @5 ]1 z% [( \

& T( s9 }2 N! Y+ u/ y% J! x8 Y: I1 ^(2)     如果程序中未做校验函数,那么STM32CubeProg会读取数据做校验。
6 d( n% t, x4 ]( I" v  z* k$ [/ l: F9 a# R- g
81.5.7 第7步,修改QSPI Flash驱动文件(引脚,命令等)
* y) L) i5 a0 G- l- J最后一步就是QSPI Flash(W25Q256)的驱动修改,大家可以根据自己的需求做修改。使用的引脚定义在文件bsp_qspi_w25q256.c(做了条件编译,包含了H7-TOOL和STM32-V7板子):8 X, C6 _* I$ Y; |) ]
9 R9 h! g( x; g6 J) k
  1. /*
    " N" s( [" b6 a, A4 ^
  2.     STM32-V7开发板接线) H: R( `3 G" o

  3. 8 q2 E- W- \/ S& i- V
  4.     PG6/QUADSPI_BK1_NCS     AF10
    : v( X/ r: S5 j, P/ J
  5.     PF10/QUADSPI_CLK        AF9
    ) M7 D) t" w, ?) o) q
  6.     PF8/QUADSPI_BK1_IO0     AF101 M: r" z+ k# H% q6 P% h2 G! s
  7.     PF9/QUADSPI_BK1_IO1     AF10
    - L; [" b3 N- n9 ~; x8 T
  8.     PF7/QUADSPI_BK1_IO2     AF9
    : ]! Q1 _  V9 R& t
  9.     PF6/QUADSPI_BK1_IO3     AF9! K* z1 w5 |& U8 H0 o4 l

  10. , Y! m* ?+ ^) Z2 l; x/ e1 [
  11.     W25Q256JV有512块,每块有16个扇区,每个扇区Sector有16页,每页有256字节,共计32MB; q. e* X+ X" q' n4 _  r/ ?
  12. ' e9 A9 a+ k+ ~# F
  13.     H7-TOOL开发板接线
    - V" h7 Y. x& [

  14. 7 u) ?) S; }$ {6 m6 z
  15.     PG6/QUADSPI_BK1_NCS     AF10
      m7 p6 G7 k+ `" F& {  n
  16.     PB2/QUADSPI_CLK         AF9
    3 e- A' ~# {' }" b2 t4 E2 K
  17.     PD11/QUADSPI_BK1_IO0    AF102 C; Z4 G. W+ q1 i, p! N* t1 |
  18.     PD12/QUADSPI_BK1_IO1    AF100 F4 J/ h) D9 C. y! |) R
  19.     PF7/QUADSPI_BK1_IO2     AF9% ~& \4 c' P9 |
  20.     PD13/QUADSPI_BK1_IO3    AF9
    8 V1 h6 z- }, @* }. H# [
  21. */
    . H) b2 c) x8 ^3 t" i1 D
  22. 1 P6 B% V1 q/ D3 G1 N
  23. /* QSPI引脚和时钟相关配置宏定义 */
    0 ]" f' m: J' I, P2 s
  24. #if 0. ?6 {% H! A% L/ H. r& I# I9 E# x# P
  25. #define QSPI_CLK_ENABLE()               __HAL_RCC_QSPI_CLK_ENABLE()/ ~" w3 P4 x. l
  26. #define QSPI_CLK_DISABLE()              __HAL_RCC_QSPI_CLK_DISABLE()/ _( y& S6 k6 {3 o, c2 H; J) V
  27. #define QSPI_CS_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOG_CLK_ENABLE()
    + h; z6 [6 d! P: P6 T
  28. #define QSPI_CLK_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE()6 f+ z; P; T' q. O3 k3 |# S$ W
  29. #define QSPI_BK1_D0_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOD_CLK_ENABLE()) K) {, k# y1 ?5 y1 w
  30. #define QSPI_BK1_D1_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOD_CLK_ENABLE(): P- U+ ^0 ^& O& A
  31. #define QSPI_BK1_D2_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()
    " I2 q; [8 w. r; w" K- b7 g' L# P& ^
  32. #define QSPI_BK1_D3_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOD_CLK_ENABLE()
    * M, E; H" N- Z9 f8 e. |6 _6 W

  33. 0 ?) |+ |& ]4 o+ @2 [4 ^
  34. #define QSPI_MDMA_CLK_ENABLE()          __HAL_RCC_MDMA_CLK_ENABLE()
    2 d5 C- N5 R4 @9 @, R2 |. p
  35. #define QSPI_FORCE_RESET()              __HAL_RCC_QSPI_FORCE_RESET()( F) s; W0 F) G/ k, `# X. X
  36. #define QSPI_RELEASE_RESET()            __HAL_RCC_QSPI_RELEASE_RESET()
    + u/ b5 H' y/ y. i

  37. + W% G7 h9 b" s- Y3 L
  38. #define QSPI_CS_PIN                     GPIO_PIN_6) x6 N1 U- U: {6 O8 s5 Q: p
  39. #define QSPI_CS_GPIO_PORT               GPIOG% V) d- K& G- U! ?2 y/ v; }
  40. #define QSPI_CS_GPIO_AF                 GPIO_AF10_QUADSPI# V/ R/ Z7 @  X. H$ Q7 O
  41. : Z* n* l! u! f: R3 M9 s
  42. #define QSPI_CLK_PIN                    GPIO_PIN_2
    0 H5 E" v& z& M' J' q8 ?: v
  43. #define QSPI_CLK_GPIO_PORT              GPIOB( Z# {5 y& @. C% a8 n
  44. #define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI0 F) p: G0 U7 q/ ~4 \7 ~% C! P! R
  45. " C0 p0 g" M  P* ]& x& H* G
  46. #define QSPI_BK1_D0_PIN                 GPIO_PIN_11/ o: N5 X; G. b* P, A
  47. #define QSPI_BK1_D0_GPIO_PORT           GPIOD
    1 e1 u; R: M$ B& z( h
  48. #define QSPI_BK1_D0_GPIO_AF             GPIO_AF9_QUADSPI
    / d  T9 g# h3 _! [; ^' I$ K

  49. & J5 \. Y, @: ~; L0 g) K8 u
  50. #define QSPI_BK1_D1_PIN                 GPIO_PIN_12( \: d+ t) F4 o1 a
  51. #define QSPI_BK1_D1_GPIO_PORT           GPIOD
    4 Q$ }  ^& V; f* o9 \) Q7 g
  52. #define QSPI_BK1_D1_GPIO_AF             GPIO_AF9_QUADSPI
    $ `$ }1 R  C! Z' `" t
  53. ) U/ h- j$ ~  ?* p% x# a
  54. #define QSPI_BK1_D2_PIN                 GPIO_PIN_7
    " `& K/ s1 a1 H8 v' [; o7 t
  55. #define QSPI_BK1_D2_GPIO_PORT           GPIOF
    6 N8 T. |/ |4 I- X6 `" V
  56. #define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI6 i  u+ H  Y8 O8 |/ p
  57. % m6 v/ H0 L8 T5 T7 A6 t- P
  58. #define QSPI_BK1_D3_PIN                 GPIO_PIN_13# H$ n' c( ~+ \  ^  R7 D3 E
  59. #define QSPI_BK1_D3_GPIO_PORT           GPIOD
    8 o* v* d' A. T2 N; s
  60. #define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI
    : ?9 I; H, I- t
  61. #else/ O+ `% y5 A- p8 w
  62. #define QSPI_CLK_ENABLE()               __HAL_RCC_QSPI_CLK_ENABLE()! {6 q+ O% @6 f/ k5 r  e
  63. #define QSPI_CLK_DISABLE()              __HAL_RCC_QSPI_CLK_DISABLE()
    " r5 q# o: y5 L4 w7 ~+ F
  64. #define QSPI_CS_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOG_CLK_ENABLE()
    ! h! X* E+ y( D! Z2 c: i
  65. #define QSPI_CLK_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOF_CLK_ENABLE()
    0 @+ I/ R, {' `
  66. #define QSPI_BK1_D0_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()1 B) \% J. Z% I) E2 B
  67. #define QSPI_BK1_D1_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()  \& v) |0 k. Q, R5 g1 B
  68. #define QSPI_BK1_D2_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()% V' U: Z# t  q+ D- |; p; [
  69. #define QSPI_BK1_D3_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOF_CLK_ENABLE()$ ]6 r% u: C7 M' a, I; l+ w! p
  70. 4 s; m' g; D9 O
  71. #define QSPI_MDMA_CLK_ENABLE()          __HAL_RCC_MDMA_CLK_ENABLE()& G+ Z3 U# a  |8 Y  C, i
  72. #define QSPI_FORCE_RESET()              __HAL_RCC_QSPI_FORCE_RESET(). k% J& O9 [% U4 U+ O0 p
  73. #define QSPI_RELEASE_RESET()            __HAL_RCC_QSPI_RELEASE_RESET()3 x& K8 N5 s* \; U  d8 }- P# f
  74. ! X7 |; ]. W0 S( X3 G. J
  75. #define QSPI_CS_PIN                     GPIO_PIN_6
    $ d# P  x( l, v& P* X2 \4 R* j
  76. #define QSPI_CS_GPIO_PORT               GPIOG
    2 T! B' k$ d2 O  f5 w) L8 H
  77. #define QSPI_CS_GPIO_AF                 GPIO_AF10_QUADSPI
    ( l4 u4 y  |! z) s! e

  78. 2 E4 w: j1 |% `: v; F
  79. #define QSPI_CLK_PIN                    GPIO_PIN_10% I0 F$ l, R; T$ D6 G0 e
  80. #define QSPI_CLK_GPIO_PORT              GPIOF
    / t6 P1 {7 g% _2 [" A# X# I' v
  81. #define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI6 e" f) Q' B- }4 T. {' l7 N

  82. 7 A+ j/ G1 L: d% b
  83. #define QSPI_BK1_D0_PIN                 GPIO_PIN_8) |" K/ O( O+ d1 O  U
  84. #define QSPI_BK1_D0_GPIO_PORT           GPIOF
    / C( z. [+ K% `7 _6 }1 c" V5 O
  85. #define QSPI_BK1_D0_GPIO_AF             GPIO_AF10_QUADSPI
    9 v) [/ d6 ^6 P% u0 [( _

  86. " [" R. W  U* c3 v1 ~9 u) s$ R5 p
  87. #define QSPI_BK1_D1_PIN                 GPIO_PIN_9( i" l! T! l( g5 P' V3 ]
  88. #define QSPI_BK1_D1_GPIO_PORT           GPIOF
    + n1 G/ p" P( O( t
  89. #define QSPI_BK1_D1_GPIO_AF             GPIO_AF10_QUADSPI* j9 \" X4 J+ o3 X, h

  90. : @- _. c; D% X% [8 _
  91. #define QSPI_BK1_D2_PIN                 GPIO_PIN_7
    / w: t  E( G4 u4 }# D
  92. #define QSPI_BK1_D2_GPIO_PORT           GPIOF
    7 R6 {. k5 p# a+ x+ P3 ]; `7 Y2 {8 A
  93. #define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI  M0 M. g  \+ }$ @! T1 e

  94. 0 s: S7 f, [- m9 m# A2 L9 t
  95. #define QSPI_BK1_D3_PIN                 GPIO_PIN_64 }+ Z# q: ^' K/ h/ H
  96. #define QSPI_BK1_D3_GPIO_PORT           GPIOF7 `3 H9 x& G1 P: o1 }
  97. #define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI
    ) h) V  E! z# \8 ~0 ]: Y
  98. #endif
复制代码
4 Z: p6 Q6 f" D; E2 w9 T
硬件设置了之后,剩下就是QSPI Flash相关的几个配置,在文件bsp_qspi_w25q256.h:- [% M' P9 E; i- c4 Y3 {
% u& Y% V7 `/ ?! z9 e4 P- F
主要是下面这几个:
4 Q. Q( s3 i$ S$ P, J  |
- y/ D+ E! F) N. t" ]6 x- i
  1. #define QSPI_FLASH_MEM_ADDR         0x90000000  ?* W- D- e$ d: W" t# _

  2. 7 |4 D5 A* u3 V/ ~# l( m7 r! Q
  3. /* W25Q256JV基本信息 */. C3 S7 M% O6 i& l: D" p& P" U
  4. #define QSPI_FLASH_SIZE     25                      /* Flash大小,2^25 = 32MB*/1 l" n# s1 _  _
  5. #define QSPI_SECTOR_SIZE    (4 * 1024)              /* 扇区大小,4KB */8 O1 k7 G. j2 T# |$ H0 c
  6. #define QSPI_PAGE_SIZE      256                     /* 页大小,256字节 */
    ) D: w: i' o# Y$ A
  7. #define QSPI_END_ADDR       (1 << QSPI_FLASH_SIZE)  /* 末尾地址 */" h: m: i9 y( s/ d
  8. #define QSPI_FLASH_SIZES    32 * 1024 * 1024         /* Flash大小,2^25 = 32MB*/# B' G& y& F3 }0 Z5 `' w

  9. : }. K, V2 \* [! n' @
  10. /* W25Q256JV相关命令 */
    6 U1 y$ N" ^, k: H
  11. #define WRITE_ENABLE_CMD                        0x06    /* 写使能指令 */$ D2 G1 q) D: P, @5 E5 ~9 ^+ Y
  12. #define READ_ID_CMD2                            0x9F    /* 读取ID命令 */' O! g& M. G6 E6 F
  13. #define READ_STATUS_REG_CMD                     0x05    /* 读取状态命令 */* g  G3 L# x9 R  u
  14. #define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD         0x21    /* 32bit地址扇区擦除指令, 4KB */. J, V  ?" p5 r) z
  15. #define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD       0x34    /* 32bit地址的4线快速写入命令 */3 v! r. D, T# W
  16. #define QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD    0xEC    /* 32bit地址的4线快速读取命令 */* E1 [  ]' p/ P- a

  17. ; T4 U& F5 g- p) V; {
  18. #define BLOCK_ERASE_64K_4_BYTE_ADDR_CMD         0xDC    /* 4字节地址,64K扇区 */
    5 L$ ?2 K: g5 j* [

  19. 3 Q8 s* M! W) E# V( \
  20. #define BULK_ERASE_CMD                          0xC7    /* 整片擦除 */
复制代码

% c$ L' c- Q% C/ E  a81.6 QSPI Flash的STM32CubeProg下载算法使用方法/ I. m9 K- E$ z2 N' x" |
编译本章教程配套的例子,生成的算法文件位于此路径下:# O" N2 [. Z# @8 Z! {# P

: i- l) @6 L. {1 x
d45f9274d8762b095790b3e6778b0a93.png

; {" {1 f4 F( h5 S5 R
( i( ^2 W. H4 U* \. ~81.6.1 下载算法存放位置
! v+ C+ G& b5 e3 K; F- u2 \: A生成此文件后,需要大家将其存放到STM32CubeProg安装目录路径:
2 G. r5 M  E! N) Z$ \, E1 P( p  k* p$ `; y5 Z! C
\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader3 C$ H2 L8 S7 U- U- X

" x7 b$ E* {0 k4 ]6 f
60cce5a15415e27e9d5b75b05028d1c0.png

7 d& ?* f& [, O! y
/ Q& H9 R5 q/ z; F4 i* j- |7 F81.6.2 STM32CubeProg下载配置
+ S4 M: L  y/ F  k' B8 @9 ?我们这里以STLINK连接开发板为例进行说明(USB DFU或者串口方式不支持下载外部Flash)。
' _/ k7 y5 G2 h" \7 F5 Q9 P/ c- G2 \: L( ?6 E
9cc179641e765ea43cb38d268bf734df.png

( L4 u0 @6 c% V2 Q4 e5 F" }3 C2 C3 H7 u% F/ s) |6 L  |2 O
点击Connect后效果如下:% M' l( E" b6 Q) x; o0 }

8 P9 B8 }! L* i' F
b39ce8a738163430db2119bdd87e3fbb.png
0 \- `8 ?, J- Z5 }8 p# i
1 c& {+ o- S* `0 Z
在这里选择我们制作的下载算法:
& g- m0 o& M. h  m' m7 R3 J* C" \
17f6e0f50a18ae818faaa1399daef12f.png

5 i5 s# r& v  A( j$ B, B1 P1 @+ t6 {2 p' d4 t5 i/ E
任意加载个hex或者bin文件,并按照如下配置,然后点击Start Programming2 a9 v( j- x- z5 Y
; d7 F0 _* `, Y4 X) F
43a0d90faf1d392f5a74eaa7777e4178.png

4 |) g, t( e- J" S
5 |* ]7 ^) t$ X4 O6 z- Y下载完成后的效果如下:
: \/ T7 m9 K  G" b3 G; o
: X* A# Z7 m5 H
a1d6662baa9e7be00f7e67e02b5c9b79.png

. z0 A8 j" I) w$ B
8 A7 c! C6 h# i$ `1 k" R8 R81.6.3 验证算法文件是否可以正常使用
8 }7 G( Q1 H: n+ {为了验证算法文件是否可以正常使用,大家可以运行本教程第82章或者83章配套的例子。也可以使用STM32CubeProg直接读取:
! j" s1 K! p" ~) z6 z/ B; O  ^+ w
3f2eefeef3db68623cb8969974c40a20.png
. [& V% f: N& W* I0 Z" R0 {) M
: W* W7 k* e+ C) F& k% A
81.7 实验例程说明2 P: L* _2 m/ [3 J/ R  Z
本章配套例子:V7-061_QSPI Flash的STM32CubeProg下载算法制作。" \  g* k5 _. [, |3 ^) G
8 z  K5 D. U1 m; M. F; C9 u
编译本章教程配套的例子,生成的算法文件位于此路径下:
" i! S  q. \; q6 B, T% r9 `
0 q! i, m$ `2 k9 X
b7028271136c8053d7300063ed4aec3a.png
. I& ^1 q- W1 y0 q
# M  j/ j+ j+ v4 l- U& x6 c7 q
81.8 总结9 G! [9 B. p" C: G1 i# X
本章节就为大家讲解这么多,为了熟练掌握,大家可以尝试自己实现一个Flash下载算法。
+ d* N" t1 L  }2 T& {/ H* Y# S
5 ~3 s6 g1 y5 b1 t9 ~, j  x$ `' y! P, |( v

, f2 P8 t( }6 B; C1 h: w
收藏 评论0 发布时间:2021-11-4 23:27

举报

0个回答

所属标签

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