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

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

[复制链接]
STMCU小助手 发布时间:2024-3-21 17:58
一、引言. `! W( R6 @, Y* L$ @
在嵌入式应用系统中,越来越多的应用需要扩展外部 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。
: q6 j+ h& O9 V3 H# s- b5 v# z
1 y" f- H2 R% ]$ x  N- ]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 的方法。
, Z# `0 m, I& o9 g% z
2 @# v+ k9 N2 o; W0 j. O
二、Flash Loader 的开发过程
/ C6 a5 H5 b* W7 x2 N8 f/ N& o- M参考 ST 在 X-CUBE-DISPLAY 3.0.0 所提供的 Flash Loader 工程,外部 Flash Loader 的开发过程主要包括以下 3 步。. `5 H- [3 @% ^, v% O* a" b
(1)更新 Dev_Inf.c 中的存储器芯片信息。$ D, u' ~9 v' L; @+ D  _! R: Q, B
(2)重写 Loader_Src.c 中的相关接口函数。
+ `# w- _! s( I(3)更改输出文件名。7 w  Z, i. c3 I) F# E
6 u( R) }- H- Z# @4 J% Y) ]
项目配置好后编译整个 Flash Loader 项目,将生成一个 ELF 文件,文件的扩展名取决于所使用的编译器,Keil 的为.axf,EWARM 的为.out,STM32CubeIDE 的为.elf,通过编译后处理指令更改为 stldr 扩展名的文件,将该 stldr 文件复制到 “bin/ExternalLoader”目录下就可以被 STM32CubeProgrammer 使用了。
1 {. @+ I. ~; f) P3 z; i! t6 S
( z" b" D( Q: F* D
2.1. Dev_Inf.c 介绍) D9 p3 w" S$ j
此文件中定义的 StorageInfo 结构提供有关外部存储器的信息。用户在制作自己的 Flash Loader 时,需要根据 Flash 的参数来更新相关信息。
& b$ l2 Y6 i( K! a+ r6 ]( W5 N
1 [9 l1 E  C& [8 w
2.2. Loader_Src.c file/ s9 I: p' @/ O$ y. `. |
该文件包含了制作外部 Flash Loader 所需的接口函数,主要包含初始化,擦除,写入以及读出等操作。其中 Init,Write, SectorErase 这些函数是必需的,不能被省略。除了这些函数之外,您还可以重写 Read,Verify,MassErase 函数。5 q6 N" A$ N& ?( M! _# v  G+ E
: ^+ a5 \) x" F2 l8 t) w' V
2.2.1. Init   H& }0 G" M, J4 E% s' D% c
Init 初始化连接到外部存储器的 GPIO 引脚以及初始化 IP 所用的时钟。
4 S+ ^5 \' `( `- }7 B- k# B如果成功,则返回 1,如果失败,则返回 0。 , k; b. W1 d9 q: q0 v0 D, z
int Init (void)5 Y1 l/ G, w9 l2 N: F/ Z1 @; c
" Y( Q; n9 _& j. a4 t5 T; \
2.2.2. Write ' z' n0 d+ f- B" m& k9 y. n) z
Write 函数将在 RAM 定义的缓冲区写入到外部存储器。7 n/ V. D/ [, `7 E, d, h
如果成功,则返回 1,如果失败,则返回 0。 / P3 C, I8 k7 A  v3 }
int Write (uint32_t Address, uint32_t Size, uint8_t* buffer). I0 a/ I" b+ Y0 \) H( p* ^

( f: p* P3 Y/ h
2.2.3. SectorErase 9 C7 K+ m+ Y! K1 x' F
擦除内存指定的扇区。其中起始地址等于要擦除的第一个扇区的地址,结束地址等于要擦除的结束扇区的地址。9 [: n4 @0 W' J. T
如果成功,则返回 1,如果失败,则返回 0。
1 P) u$ N3 Z: Z5 kint SectorErase (uint32_t StartAddress, uint32_t EndAddress)
# i* [( H0 P1 `7 e! `+ o0 r* J0 y7 E3 x: p; E  ]# G# H
2.2.4. Read 功能
+ |% [. y; Z. V/ l/ _9 A5 A* rRead 函数将存储器指定地址的数据读取到内存中的缓冲区中。
* \5 S1 F/ n3 h' {2 f. [! D如果成功,则返回 1,如果失败,则返回 0
+ u1 `1 E0 d8 T" ]) \int Read (uint32_t Address, uint32_t Size, uint16_t* buffer), R: d0 M( g+ ]

7 ]/ [7 o: O  I/ ?9 I
2.2.5. Verify
8 y' `9 d% n! c3 R! a" b功能当选择“边编程边验证”模式时调用验证函数。此功能检查编程的内存是否与 RAM 中定义的缓冲区相对应。
! \  Y. S" z9 C/ R/ c
6 e3 j. O1 C$ @  a+ S% e! \
2.2.6. MassErase 功能 ; Q# Z3 K+ |- j% G+ W& v8 I8 H: L
MassErase 功能会擦除全部内存。
$ V8 ^2 F, h3 T( b如果成功,则返回 1,如果失败,则返回 0。
2 n8 W7 @6 j8 X4 w1 c2 Dint MassErase (void)
1 W' R. C& `1 K. }- P& A' }3 I/ n+ B- i& h* n4 }
2.2.7. Checksum 功能
! }5 `" s. N6 y描述的所有函数在操作成功时返回 1,在失败时返回 0。
7 n! j5 A: y3 Y! R: {+ W: k% o. `* U8 b5 j/ ~& j+ `# S2 b5 A
三、利用 X-Cube-Display API 生成 Flash Loader 的方法
& W4 _) V( p1 u, }' c& J5 ~% Z
这里参考 X-CUBE-DISPLAY\3.0.0\Projects\NUCLEO-WB55RG\Applications 目录下的 GFX01M2_FlashLoader 工程的方法,来移植一个 NUCLEO-G474+GFX01M2 的 Flash Loader,这是一个 SPI 接口的 NOR FLASH,芯片型号 MX25L6433F。
% j7 u8 W6 V0 R7 S  w我们打开 STM32CubeMX,MCU 选择 STM32G474RET6,首先配置时钟,其次这里用到外设有 SPI,还需要对 SPI 进行配置,查看 X-NUCLEO-GFX01M2 和 NUCLEOSTM32G474 原理图,外部 Flash 用到了 SPI2,GPIO 引脚用到了 PB13, PB14, PB15, PA8。SPI2 相关配置参数如下图所示。
0 V7 z3 S4 C' R2 P; K
4 B& b. D  Q6 j; ?5 V) M$ k
1.png

1 G: q  y6 ~$ L$ Q+ V; g: w! w
) n* v& u7 F0 x0 n
4 `. ]7 A/ ~$ ]! ^4 i2 u
, P9 O% O" C- I) T( J5 a
▲ 图1. SPI 参数配置

/ b" c* s7 B; c) K% ^6 D+ _' e: _" o" ^  J/ _3 I4 O  b8 F

: d( R) q- y  p! f: ?7 c$ ?SPI2 外设相关参数配置结束后,点击 X-CUBE-DISPLAY 标签,为相关的 IO 接口配置对应的引脚和外设。
4 ^) c: Q" w# _! W5 y3 ^图片5 M+ I: h- \6 y1 e, z5 `8 w
$ d9 V' s% s: {' y
7 t6 g+ Q, S/ Q) f) u4 l! z; y) j
2.png

  `( T3 X) m/ V+ P5 X$ j8 X
! e: h( @# \4 c7 }0 }
9 Z% `: T3 @6 W) K; C
▲ 图2. X-CUBE-DISPLAY IO 接口配置

7 a4 A% W& X1 v0 h. e& y- e
% m& j; F# s+ R1 m( \! V4 F8 K& D$ h

1 P! H4 h5 `! F# g5 ~5 R) x; ]相关参数配置好后,点击 Project Manager,给工程重新命名,由于 Flash Loader 不需要 main 函数,选中配置的 “Do not generate main()”,这样生成的代码就不会有 main 函数。然后点击生成代码按钮生成代码。5 D' F6 j9 K( B+ C
/ u& `. W2 X3 s; A
) c/ s5 O  p; k& }, P% F
3.png
0 P& p  [  G7 G3 s5 A0 k0 n) l1 y, D5 N

, [# r( \& V+ }8 O: X  u

  J2 h, }" V" ~6 w
▲ 图3. Project Manager 修改
# S+ A: ~4 E* V- @

/ t' n; o; `7 _6 A9 a( R0 W

+ M  |, w" k% B2 x( o1 j, Q- _% C生成的代码还需要添加 Dev_Inf.c、Loader_Src.c、Dev_Inf.h、Loader_Src.h,将这个代码添加到 Core 文件夹下的 Inc 和 Src 文件夹,为了方便不同编译器生成的代码能够自动加载这几个文件,复制.extSettings 文件到该工程文件夹,该文件会为工程新建一个 Loader 文件组,然后再重新生成代码。生成的代码用 VSCode 打开,在 main.c 函数中新增 MX_Init()函数,函数主要的功能是复位外设和初始化 GPIO。1 ?  a; h1 k' E! g( ^
$ D; p! R" l$ Y, N

2 z& [1 A5 O4 n: I
4.png
, X: D" B! P9 W- _" B: m
▲ 图4. 添加 MX_Init()函数
6 I: Y& v" c# x. H) ]" n% N: n! v$ I$ o
关于 Dev_Inc.c 和 Loader_Src.c 文件中的函数,这里就不再做一一说明,大家可以对照附件查看,下面主要介绍下不同编译器的工程属性配置。
' `0 E% M) z/ @7 S/ w' E& @, K) l& G* ^" S
3.1. STM32CubeIDE 工程配置
# {/ g) a) i9 O; C4 V4 V1 n/ f3 eSTM32CubeIDE 的配置修改包括从工程中去除 startup_stm32g474retx.s,修改 Linker 文件,修改启动函数入口,添加后处理生成 stldr 文件。 + A- t% b* J2 M1 T& l( q; ~! E
7 ]: i- s! ~: f3 D2 W3 W

  S0 n1 j3 S: e: G' n
5.png
2 `+ `  S( @6 d$ r0 x
0 u# H4 R% p5 {* h, {- \

" T- I, ]* E# \1 x8 \
▲ 图5. STM32CubeIDE 中将 startup_stm32g474retx.s 从工程中去除

! {" G2 q* e" E- W8 q& n) J" l# H
! g# }- T: h! G( J

1 s9 \5 u" a- [- H' C3 C2 R修改 Linker 的配置,通过“Properties”打开设置页,将 Linker 文件修改为 STM32_FLASH.ld。
" E# O/ w3 N$ d* h8 c
0 o; ]9 V. D5 c

* \$ s$ r6 z& v
6.png

& ~) k3 a7 r2 H8 k# z
; T. |4 O4 c2 F3 Y% N
% a. ~6 n' v6 }5 D6 B* [1 ]
▲ 图6. STM32CubeIDE 修改 Linker 文件
' n( N5 }. c$ ^$ [' ^* m  f" z) c

7 X/ J( P: e: v% |& b3 o
通过 “Settings” -> “Build Steps” 配置页中,在 “Post-build steps” 处添加指令 :cmd.exe /c copy /Y "$(BUILD_ARTIFACT)" "..\MX25L6433F_GFX01M2_STM32G4.stldr",编译后生成 stldr 文件。
( d7 O+ o6 w$ u, R
! a+ `9 o) \4 E  `6 P; [
  X: W- o8 Q2 d1 G7 G0 c
7.png

- f  t* A6 t9 U  G! R0 V7 E4 `  O
▲ 图7. 在 STM32CubeIDE 中添加后处理语句
5 K! ^1 Y0 D* [! B4 [) g

$ b# l9 K3 x/ ^0 O! M当这些配置好后,重新 Build 工程,这样就会产生所需要的 Flash Loader。
: y2 G7 ]: Y/ ^4 m* Z$ W* Z! A
. C* Z5 d  L# D7 o
3.2. KEIL 工程配置
+ i; U  a9 A6 J$ d与 STM32CubeIDE 配置过程类似,KEIL 的配置过程主要包括以下操作。在 Target 标签页,Arm Compiler 选择“Use default compiler version 6”,如下图所示。) L. y; |9 e9 ?& G  q$ d

# Y& u3 ^" P# d

. O7 [  @6 o$ K* A& ]
8.png

! }! K0 c% [) y2 v% a/ R1 a
+ f; u. ]: t' {0 k* h
1 X5 z) w+ M0 ]; H+ c
▲ 图8. 更改 Arm Complier
$ Q0 F0 l; D$ k
在 startup_stm32g474xx.s 的文件属性中,去除勾选“Include in Target Build”和 “Always Build”,这样这个文件就不会被编译和包含在这个工程中。1 P7 Z% B0 }- m; W6 z
, b- Y: `$ X! l  e6 z4 s$ D' A

9 G; d2 D  E( W; X, l, y3 O0 Z/ o7 u
9.png

& I! k4 I# C" [& J4 x1 d
5 g0 e- H7 d: [" [3 v

+ L$ `7 X) M0 h% G8 Y
▲ 图9. 在 KEIL 中将 startup_stm32g474retx.s 从工程中去除
' v0 d! p3 y6 u% r3 h
7 m2 v, _6 y& i9 V& c4 Z" h9 g
* G  G3 r) N! |' E' d
在属性界面,切换到 Linker 界面,去掉“Use Memory Layout from Target Dialog”勾选,修改链接文件,将链接文件更换为 stm32_loader.sct,同时注意在 Misccontrols 添加“--paged --pagesize 0x10--diag_suppress L6305” 。* O! o1 [3 z. c( i

2 Y5 ]2 w6 r; C: X/ p

, P; Y2 q) B0 [2 w" h% Y, x7 i
10.png

6 W8 n; p2 ~  n: o2 s8 t+ r. W7 \
▲ 图10. KEIL 中修改链接文件
# Y1 m+ r9 x3 ]5 z, C

; L3 t4 _) h+ @( }  P& b! K与 STM32CubeIDE 配置类似,添加后处理语句“cmd.exe /C copy /Y "!L" "..\MDK-ARM\MX25L6433F_GFX01M2_STM32G4.stldr"”。
+ F1 Z; f( a5 a. _5 P3 M" m: K  z/ ^1 C

9 F; N; N+ e8 |% |
11.png

9 w5 A/ Y% \' t  W
▲ 图11. KEIL 中添加后处理语句
  y5 D. h+ N, o  P5 c& u4 c
! w0 [. i- v1 h2 t8 }
6 W. w* _. A$ p( l$ p9 c0 q
这些配置好后,重新编译代码,会在 MDK-ARM 文件夹下生成 stldr 文件。
" ~2 K. x: \8 z  z( n6 h; }3 a& ?& A: O# {0 h- L; u. U
+ r9 P, G% E# |) N
3.3. IAR 工程配置' x! x  r! E  X' H( V# J
IAR 工程配置与 STM32CubeIDE 和 KEIL 的过程类似。
0 A+ P6 E9 b- v9 H8 a* l- w2 f2 F# P5 I" b$ j6 x7 L
$ U+ n" a  I$ J
12.png
3 j/ s9 G& I) a- h% i
& C3 l: [- \5 Y% l* L

4 x* f" G; [! o! S  ?7 @2 V
▲ 图12. IAR 中将 startup_stm32g474xx.s 从工程中去除

. U, Q7 h# P$ `" P5 \% A1 |" f) b  O/ g% B
6 J9 y0 r' K8 u) |$ B; f
13.png

/ b; `7 t3 Q* A7 b( ~' Z+ U- F* ]* w7 i  Q* ?
▲ 图13. IAR 中修改链接文件
& [) D- {0 b) q, Y6 P# T
3 f) m! M% [4 J. u9 J! y* z6 X5 }. P- z

4 P( G9 q; F/ G0 L0 g
9 U0 I( E$ G, S
14.png
4 i% _/ w$ w0 n0 H# y
! R' H7 r; y, v
▲ 图14. IAR 中更改入口函数
9 a0 ]$ ~2 l9 P1 R4 o8 F% J/ `

( z( S2 y$ I. d8 o; Q# U; w5 d
& t/ D6 g5 Q7 r
+ v8 k5 n7 j1 j6 }4 c  ^( s
15.png

: m% @( c' U4 n: S2 ]; ?6 _$ R1 u. S
5 M; O8 [5 Y9 @: ]9 |4 r
▲ 图15. IAR 中添加后处理函数

, [! ?' v8 O! N! [) Z
" g3 Q# E- A& m8 e' V

1 P" [( l0 v3 F  o* U
这些配置好后,重新编译代码,会生成 stldr 文件。! P5 }0 D% C5 _4 A
' I) @) m. e3 ~9 u& W- F
四、小结# F$ z" }! o" d- ?( B
本文结合 X-Cube-DISPLAY 3.0 软件包中的示例,介绍了利用 X-CUBE-DISPLAY API 进行 Flash Loader 的方法,如果用户选择的 Flash 是 MX25L6433F 这款 Flash,那么可 以参照此方法,来快速开发自己的 Flash Loader,如果所选的 Flash 不是 MX25L6433F,也可以参照此方法,重新编写对应存储器的驱动来开发对应的 Flash Loader。
5 p2 d. \& r2 S, C
8 V3 n' B: u3 a) B. v5 y

9 `, X) e+ z& N; A6 J# R! }转载自: STM32
/ L6 u) S9 b5 o* X8 Z如有侵权请联系删除6 c& d) I8 q! P6 p8 E+ Z

0 {2 t$ x2 l( W9 B- N5 [6 C

% y1 j+ S" o! b% K0 J+ @  Y% p1 J" x7 i/ G4 J5 o9 ]! D; f/ ^
赞 收藏 评论1 发布时间:2024-3-21 17:58

举报

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

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

所属标签

相似技术帖

官网相关资源

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