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

基于STM32生成外部Flash Loader的方法经验分享

[复制链接]
STMCU小助手 发布时间:2024-3-21 17:58
一、引言
( P; n; B, W0 q& D! x3 R在嵌入式应用系统中,越来越多的应用需要扩展外部 Flash 来满足存储需求,例如 GUI 的应用,需要将视频、图片、字体等素材存储在外部 Flash。对于 SPI、FMC、 FSMC、QSPI、OCTOSPI、SDMMC 等接口存储器,需要一个 Flash Loader,把资源下载到外部 Flash。在 STM32CubeProgrammer 安装目录的“bin/ExternalLoader”目录下,ST 提供了官方开发板对应的 Flash Loader,也就是 stldr 文件。但官方提供的 Flash Loader 数量有限,不能完全满足用户需求,需要用户根据自己的 MCU 型号、Flash 类型,开发自己的 Flash Loader。
# P: @3 s- |7 g' L+ Q1 |- B$ Z; r7 a' z+ N" X: ~7 {0 f9 \5 m( E
ST 的 X-Cube-DISPLAY 是 STM32Cube 扩展包,3.0 版本提供了 SPI/QSPI 接口的 MX25L6433F 的 Flash Loader 的源码工程,用户可以基于此进行自己 Flash Loader 的开发。本文档就是根据 X-CUBE-DISPLAY 3.0 所提供的 Flash Loader 工程,以 NUCLEO-STM32G474+GFX01M2 开发板为例,介绍了 STM32CubeIDE、KEIL、IAR 等不同编译器利用 X-CUBE-DISPLAY 所提供的 API 来生成外部 Flash Loader 的方法。
- v3 Y( B" V& m( X2 K
! c8 Z* l- c% g
二、Flash Loader 的开发过程
6 N8 Y, d6 n9 r) ]: b: }参考 ST 在 X-CUBE-DISPLAY 3.0.0 所提供的 Flash Loader 工程,外部 Flash Loader 的开发过程主要包括以下 3 步。
6 _, |) B$ y# J6 w# d(1)更新 Dev_Inf.c 中的存储器芯片信息。0 R. _0 L. P2 }6 h/ W* N. _
(2)重写 Loader_Src.c 中的相关接口函数。  k9 \* {! g) I0 ?8 S* h: m
(3)更改输出文件名。
2 `( m  e9 Z* [9 }/ @! v! `. n! g& g3 Q. I- l3 e. }& v" |
项目配置好后编译整个 Flash Loader 项目,将生成一个 ELF 文件,文件的扩展名取决于所使用的编译器,Keil 的为.axf,EWARM 的为.out,STM32CubeIDE 的为.elf,通过编译后处理指令更改为 stldr 扩展名的文件,将该 stldr 文件复制到 “bin/ExternalLoader”目录下就可以被 STM32CubeProgrammer 使用了。
! F  }8 T' V# w  {8 L" a9 M1 T) Y% T+ z! Z( L: i) z) \, V
2.1. Dev_Inf.c 介绍) \& L( j0 T5 [' C8 i/ v
此文件中定义的 StorageInfo 结构提供有关外部存储器的信息。用户在制作自己的 Flash Loader 时,需要根据 Flash 的参数来更新相关信息。
4 q( S' E2 Z0 i; A5 ^% v
! S6 C9 }1 c2 n- m) w; ^
2.2. Loader_Src.c file- J" i2 B6 v7 P, p3 U, ?
该文件包含了制作外部 Flash Loader 所需的接口函数,主要包含初始化,擦除,写入以及读出等操作。其中 Init,Write, SectorErase 这些函数是必需的,不能被省略。除了这些函数之外,您还可以重写 Read,Verify,MassErase 函数。+ Q. w+ }2 C0 ?# S
( x. ], ~$ a/ X% H4 k! a
2.2.1. Init
" g! `% R  e( c, p0 E0 l5 Q: y& {% r* GInit 初始化连接到外部存储器的 GPIO 引脚以及初始化 IP 所用的时钟。6 h+ C: J( n" w  Q2 w
如果成功,则返回 1,如果失败,则返回 0。 % J+ S( u1 H- E, @6 w! U/ S  A
int Init (void)% i6 l: Y! ?0 n( a% v3 ?% w
4 d2 p& m+ a0 _, P" |
2.2.2. Write
4 n. W: s$ E( a4 Z5 S. P$ gWrite 函数将在 RAM 定义的缓冲区写入到外部存储器。
& P: C; z( l7 p如果成功,则返回 1,如果失败,则返回 0。
! f2 Z1 ?3 n1 ^3 `, c! yint Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
- r; N5 P2 \  l$ Z0 O+ l: k
1 P) v$ A" X9 g: M$ h& c
2.2.3. SectorErase
3 Z8 A3 J' a4 V6 j) b擦除内存指定的扇区。其中起始地址等于要擦除的第一个扇区的地址,结束地址等于要擦除的结束扇区的地址。2 y/ O1 G- F) T& R- M
如果成功,则返回 1,如果失败,则返回 0。
5 G- g; Y0 c8 p0 cint SectorErase (uint32_t StartAddress, uint32_t EndAddress)
1 O5 r! {" V  n6 n7 G+ `
; Y) H2 m3 E  t: o! ]
2.2.4. Read 功能 , c3 p- O2 Q4 d$ i* h6 D5 @( I
Read 函数将存储器指定地址的数据读取到内存中的缓冲区中。
: Q( t- Y7 j/ ?. h! d* f如果成功,则返回 1,如果失败,则返回 0 ! i5 g% b0 s5 M* }" J; A
int Read (uint32_t Address, uint32_t Size, uint16_t* buffer)
: I/ x# W% P2 V) c2 n: l3 P4 N% L3 c- q
2.2.5. Verify
0 N0 E' B  p5 @. ~8 O7 Y1 K功能当选择“边编程边验证”模式时调用验证函数。此功能检查编程的内存是否与 RAM 中定义的缓冲区相对应。- O( Y$ w8 \4 A% b( E

; b, H1 o* x6 h  a3 F. C8 W
2.2.6. MassErase 功能 2 u3 x4 ]; U, }* p3 A& m% Z
MassErase 功能会擦除全部内存。
1 |% ]# P; O; C! y2 S- {: d5 \/ G如果成功,则返回 1,如果失败,则返回 0。
+ b! C' I) J! s) `" o4 s; X" E& D  K3 Wint MassErase (void)
# D) E1 ]) [: i) [7 f  A
/ P4 v4 c% U7 o' I# l8 l
2.2.7. Checksum 功能
- F; f: Z/ @+ P+ D, ~, C0 G描述的所有函数在操作成功时返回 1,在失败时返回 0。
, x$ x/ p- [% [; D' z0 S/ c; p" p  z& E; G( E; E" F  ~
三、利用 X-Cube-Display API 生成 Flash Loader 的方法
# f: Y6 ^* U4 l. |. z
这里参考 X-CUBE-DISPLAY\3.0.0\Projects\NUCLEO-WB55RG\Applications 目录下的 GFX01M2_FlashLoader 工程的方法,来移植一个 NUCLEO-G474+GFX01M2 的 Flash Loader,这是一个 SPI 接口的 NOR FLASH,芯片型号 MX25L6433F。0 f$ h& x' K. q( r' f0 `
我们打开 STM32CubeMX,MCU 选择 STM32G474RET6,首先配置时钟,其次这里用到外设有 SPI,还需要对 SPI 进行配置,查看 X-NUCLEO-GFX01M2 和 NUCLEOSTM32G474 原理图,外部 Flash 用到了 SPI2,GPIO 引脚用到了 PB13, PB14, PB15, PA8。SPI2 相关配置参数如下图所示。
6 m7 c, U9 @3 A3 P9 y, X( v" M$ P$ B+ |/ ^! n
1.png
7 g$ [3 F, m3 P6 ^  H# Q# O1 ~
5 V& I. a) g0 _: b' d

" U% a8 p3 d5 M. N
) q$ n" K6 n2 f
▲ 图1. SPI 参数配置

8 b( m" g$ Z) N. O/ u: N" K  j7 V, |$ U" X0 L5 ^1 j

& C& U. E6 n, a7 x1 x4 gSPI2 外设相关参数配置结束后,点击 X-CUBE-DISPLAY 标签,为相关的 IO 接口配置对应的引脚和外设。
& q+ I& e( C3 ~. M! u图片5 `' E% s( m, V+ K

) q1 w! ~5 v7 }
) Z- _$ }4 {0 B1 H* c
2.png
5 _4 Q. c/ f, b1 N% K
8 \1 ^+ O% U6 E5 s$ Z0 C

5 P# Y0 ~7 K4 a: Y5 {- F( q; g
▲ 图2. X-CUBE-DISPLAY IO 接口配置

5 _8 z! N0 c& o- z
7 {3 x: W1 p) ]/ {7 A( \
. s7 S5 o) N, o; m  d% k
相关参数配置好后,点击 Project Manager,给工程重新命名,由于 Flash Loader 不需要 main 函数,选中配置的 “Do not generate main()”,这样生成的代码就不会有 main 函数。然后点击生成代码按钮生成代码。3 Z5 ?# {# A" b" j5 w
2 X7 D- i1 i4 i- d' v  ^0 K: u
4 x! F: G% s, j+ i4 S$ R
3.png
/ a/ N+ B/ F9 ]1 Q. i7 P

( S* ^: P# b' r' K

6 j9 C( `. _$ W3 g' h! s0 M5 i
▲ 图3. Project Manager 修改
6 g+ _5 I8 x4 R+ H

" @* c  w7 P& w( z* W/ x
" G' W7 N, T* i
生成的代码还需要添加 Dev_Inf.c、Loader_Src.c、Dev_Inf.h、Loader_Src.h,将这个代码添加到 Core 文件夹下的 Inc 和 Src 文件夹,为了方便不同编译器生成的代码能够自动加载这几个文件,复制.extSettings 文件到该工程文件夹,该文件会为工程新建一个 Loader 文件组,然后再重新生成代码。生成的代码用 VSCode 打开,在 main.c 函数中新增 MX_Init()函数,函数主要的功能是复位外设和初始化 GPIO。
5 Q4 \9 P3 ?/ l* ~$ Z+ @
! o% {% c5 Z. s4 f% z( t( a  y3 U; _6 W; ?) m
4.png

+ N* U! ^! [7 p3 @4 h
▲ 图4. 添加 MX_Init()函数

1 j: X; }# y& `
关于 Dev_Inc.c 和 Loader_Src.c 文件中的函数,这里就不再做一一说明,大家可以对照附件查看,下面主要介绍下不同编译器的工程属性配置。2 f# K- ?& Q. N( u

- j! A. g# Q( J; d  H5 s& K" L
3.1. STM32CubeIDE 工程配置 1 K# Z% K* n0 K
STM32CubeIDE 的配置修改包括从工程中去除 startup_stm32g474retx.s,修改 Linker 文件,修改启动函数入口,添加后处理生成 stldr 文件。 ; W0 G0 Z, \( `+ F. t3 D

. n  g, n2 |$ i" i
; M, X1 d+ {$ y+ k  j9 Y  W
5.png
6 m0 B- v' A9 p5 p+ x- N6 k
$ }: J+ k% ?8 j# ~7 e) R* }3 Z
6 o8 y( x, J3 ^) C  D7 D
▲ 图5. STM32CubeIDE 中将 startup_stm32g474retx.s 从工程中去除

( V( o9 F# M3 Y7 d$ N2 u7 Z  K
, N) _3 I# g7 B) Z2 \" s. F5 L

2 o3 Y7 @/ M  ~9 `& z2 @* N修改 Linker 的配置,通过“Properties”打开设置页,将 Linker 文件修改为 STM32_FLASH.ld。
: ^5 I- R8 E/ F6 }" Z
6 q( d0 U* Y4 f8 `
, K& `  j: e+ \0 y' F1 z
6.png

3 @3 d2 `- P: a/ Q4 x

: q$ F. Q( O0 J1 }3 H2 _) F! Y  |

8 K& U" U% B" y6 ]* N! Y* e
▲ 图6. STM32CubeIDE 修改 Linker 文件
# R* |) d4 C. ?1 {+ i3 P) M
8 I% l, g: M, x" C3 k
通过 “Settings” -> “Build Steps” 配置页中,在 “Post-build steps” 处添加指令 :cmd.exe /c copy /Y "$(BUILD_ARTIFACT)" "..\MX25L6433F_GFX01M2_STM32G4.stldr",编译后生成 stldr 文件。
, h5 H. H9 B/ t( A' `- @) l
7 [& m: c7 P6 c7 @% J
9 t/ m) @5 r6 Z# L7 o9 M
7.png
1 O- z( i8 Y9 m8 I
▲ 图7. 在 STM32CubeIDE 中添加后处理语句
7 n1 B. p! q. g7 f

: B! b: b1 F2 W+ o* G" ]当这些配置好后,重新 Build 工程,这样就会产生所需要的 Flash Loader。$ L5 U, p2 {! }3 n; _$ w' L

4 Y* e: d" t1 R. c& F7 w
3.2. KEIL 工程配置
1 G" ]3 B* u. W$ f与 STM32CubeIDE 配置过程类似,KEIL 的配置过程主要包括以下操作。在 Target 标签页,Arm Compiler 选择“Use default compiler version 6”,如下图所示。
6 `0 w% ?" v* T- I9 ^8 c0 ?7 K! f( [6 o
; @( p0 c4 a" @' }: V5 O
8.png

; [8 X* S2 X: S) N! V

+ T9 I$ @& a. |0 ]

% U+ M; B5 Y! H) x  G* m8 ?7 G
▲ 图8. 更改 Arm Complier

+ m  k& \' c7 c" k0 X5 F; e在 startup_stm32g474xx.s 的文件属性中,去除勾选“Include in Target Build”和 “Always Build”,这样这个文件就不会被编译和包含在这个工程中。
( F( }+ u8 n; q) T! T7 Z4 G' {+ n$ F: W  f

4 B- \( Z0 w" B! c
9.png
: a5 D$ A" }! C9 E
8 V) ?( p! \* U& m) ^
+ k, T8 ~% r, l/ i& [( B: E
▲ 图9. 在 KEIL 中将 startup_stm32g474retx.s 从工程中去除

* D9 L- ^. f5 h& t4 e( r- R! \6 G2 Y1 F9 }# A' p
$ Y7 j% z# ?5 K) G5 p
在属性界面,切换到 Linker 界面,去掉“Use Memory Layout from Target Dialog”勾选,修改链接文件,将链接文件更换为 stm32_loader.sct,同时注意在 Misccontrols 添加“--paged --pagesize 0x10--diag_suppress L6305” 。
4 Z  d, G/ I/ p7 I; x  A6 P. S% w" i. o/ S/ Z
; ]! L5 Y$ r/ k0 q* q/ b
10.png
- q% n2 W; Z" R4 u4 ?
▲ 图10. KEIL 中修改链接文件
' z% i  h; e" y& ~6 Z

' B, b3 w1 v' p4 v7 P与 STM32CubeIDE 配置类似,添加后处理语句“cmd.exe /C copy /Y "!L" "..\MDK-ARM\MX25L6433F_GFX01M2_STM32G4.stldr"”。
; g2 M* _- e) u7 i9 E3 h6 O# k" n1 v. U7 X
; A# i+ |3 V8 \% `' f; [# U; j
11.png

8 T7 w3 {0 W" V+ a& s. W& I* f
▲ 图11. KEIL 中添加后处理语句

, u: R: t" G3 N4 e3 B
0 X% W1 `5 `& N6 ^

- W  S" s0 |; |5 _; ^9 W# `这些配置好后,重新编译代码,会在 MDK-ARM 文件夹下生成 stldr 文件。
+ F2 t# R4 x: ^$ L' l& J0 s5 ^; a& P: Y, ]
7 Q+ `! _* }. t  }4 [! [0 r, L5 d
3.3. IAR 工程配置
% [% d  Q0 [$ V, K& nIAR 工程配置与 STM32CubeIDE 和 KEIL 的过程类似。 3 A/ X1 X" V3 @0 o/ X- A. F
4 V; x& U# w! m/ }( J
7 E7 @) ^, q  N4 o5 n9 m% |0 r
12.png
2 ~* o) @  _9 E0 q2 y4 G

+ V2 E6 A4 D; _0 j4 L
2 [  I! Q" \! k3 _& H/ v5 ^
▲ 图12. IAR 中将 startup_stm32g474xx.s 从工程中去除
6 ~3 g% E- @7 Y# w2 a( Q7 A0 `, p

) G" L  ?$ c& u% O
1 @; b" V* X+ o8 v
13.png

4 }) f1 @6 ~- ?. l( p" f1 e. W0 F- |
3 x9 N/ ~% I' B1 k1 S
▲ 图13. IAR 中修改链接文件

) w) E! ~9 V! w. Y: D! u/ p' L- ]

( x; J( a, b7 a4 |# x  e
& M9 L, K7 C/ G7 r& l! W. p

3 T0 s2 Z. x8 p; |$ S5 R
14.png

4 U4 T5 y* \$ r# R# u( m: J0 t5 y
▲ 图14. IAR 中更改入口函数

3 s4 h' K- P0 s
. J0 m2 k0 W/ _! q/ x
% E/ e" U- N# ~" o/ [1 m+ J8 `

$ I  Y0 {, [! X) d( d
15.png

3 u: I! U2 K* D2 s& f
. g; M, D( h4 d4 t" U6 g3 E
▲ 图15. IAR 中添加后处理函数
2 S8 e/ G! U' F

7 t8 u3 Z9 f1 H1 d1 p" \
/ @2 M4 N  m8 c
这些配置好后,重新编译代码,会生成 stldr 文件。( _+ S# P: d9 u0 G. a1 n

* h- a7 d9 p& x: `/ Y! P7 K5 l2 e
四、小结. h3 N3 u, @8 k2 ?/ z% B
本文结合 X-Cube-DISPLAY 3.0 软件包中的示例,介绍了利用 X-CUBE-DISPLAY API 进行 Flash Loader 的方法,如果用户选择的 Flash 是 MX25L6433F 这款 Flash,那么可 以参照此方法,来快速开发自己的 Flash Loader,如果所选的 Flash 不是 MX25L6433F,也可以参照此方法,重新编写对应存储器的驱动来开发对应的 Flash Loader。; n% P" [% A) J

! J5 k% P1 Z$ d& y4 ?) W/ C
* |) }% G2 C& E' b! }1 @
转载自: STM329 A& d% }( U! j5 Z8 i
如有侵权请联系删除
6 m: T  H( \: T+ b
/ \4 k$ C: p% m% h

2 Z4 C4 s0 i+ }* q, K. A' @& ~/ z" h4 X& X
收藏 评论1 发布时间:2024-3-21 17:58

举报

1个回答
Cheng、 回答时间:2024-4-12 15:13:08

你好,关于IAR制作stldr文件有详细的教程吗?比如最后用的是什么指令?

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版