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

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

[复制链接]
STMCU小助手 发布时间:2024-3-21 17:58
一、引言
8 r, W4 ]$ b' l- S5 }9 |在嵌入式应用系统中,越来越多的应用需要扩展外部 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。% b* A8 [3 H/ H/ ?! m) ]

8 @) z; Q$ |" d: T, |; }8 Y+ i+ SST 的 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 的方法。
! n) P4 }8 d# l/ j9 o' j* s5 ?7 l4 V& D5 a0 u: B" B
二、Flash Loader 的开发过程
. v0 ^4 L& [" Z0 a* j6 J参考 ST 在 X-CUBE-DISPLAY 3.0.0 所提供的 Flash Loader 工程,外部 Flash Loader 的开发过程主要包括以下 3 步。3 v4 P1 S& C- c$ V% [8 I
(1)更新 Dev_Inf.c 中的存储器芯片信息。6 A; M  N  C' m; e# Y  S& j$ i
(2)重写 Loader_Src.c 中的相关接口函数。
6 D  N4 ~: ?6 i& m& U' g6 u+ I' f- W. ?(3)更改输出文件名。, W% i0 o0 ]" G0 B! Q9 A2 D1 o- v
* ]4 R9 a2 a$ M
项目配置好后编译整个 Flash Loader 项目,将生成一个 ELF 文件,文件的扩展名取决于所使用的编译器,Keil 的为.axf,EWARM 的为.out,STM32CubeIDE 的为.elf,通过编译后处理指令更改为 stldr 扩展名的文件,将该 stldr 文件复制到 “bin/ExternalLoader”目录下就可以被 STM32CubeProgrammer 使用了。3 I3 x' h* u" H* Y. u$ P; P; i
2 O2 P+ W2 W$ H& w: ]
2.1. Dev_Inf.c 介绍( \* R. S2 i6 u) J4 ~4 l
此文件中定义的 StorageInfo 结构提供有关外部存储器的信息。用户在制作自己的 Flash Loader 时,需要根据 Flash 的参数来更新相关信息。6 |; m% U9 g. U% g: d
- q# _* X8 n/ _+ X6 }4 [
2.2. Loader_Src.c file+ W& \/ o) F8 Q* E- W
该文件包含了制作外部 Flash Loader 所需的接口函数,主要包含初始化,擦除,写入以及读出等操作。其中 Init,Write, SectorErase 这些函数是必需的,不能被省略。除了这些函数之外,您还可以重写 Read,Verify,MassErase 函数。
, ^& n- w4 ^$ L: m: i
; I* t! c2 M; Q% q/ P7 @  c
2.2.1. Init + J" ~( J1 ~. B+ c" R; `% f) Q- K
Init 初始化连接到外部存储器的 GPIO 引脚以及初始化 IP 所用的时钟。/ M) U' m8 g1 n2 I3 E: l- O2 m
如果成功,则返回 1,如果失败,则返回 0。 8 S& ?* R6 }1 K6 s* K
int Init (void)! n8 o9 ?3 V. n$ k+ r

6 V9 y7 h# [" _& ?2 i
2.2.2. Write ; [/ S4 l$ a/ L, _" P  I
Write 函数将在 RAM 定义的缓冲区写入到外部存储器。2 s% g$ B; _& h* X9 X& ?! z1 n
如果成功,则返回 1,如果失败,则返回 0。 - ^& b+ h7 I# t% {' x( P( |. {: C
int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
" Y3 q+ g: L+ m3 `( c4 o- p6 P- f6 F& ~) v: y* `
2.2.3. SectorErase - D) ^/ z) _' g' J* c/ C! b
擦除内存指定的扇区。其中起始地址等于要擦除的第一个扇区的地址,结束地址等于要擦除的结束扇区的地址。
5 Q2 D0 S1 s6 R! K如果成功,则返回 1,如果失败,则返回 0。
; b, g6 U( p% z, |int SectorErase (uint32_t StartAddress, uint32_t EndAddress)9 ~0 M( U. D% s, t; x' r# \
4 e- X& k* O& d. h
2.2.4. Read 功能
$ F* O( [& U5 IRead 函数将存储器指定地址的数据读取到内存中的缓冲区中。2 y0 K, ~% h* \) N& C& y
如果成功,则返回 1,如果失败,则返回 0
* }8 D, _8 O, Y2 T4 M/ Rint Read (uint32_t Address, uint32_t Size, uint16_t* buffer)& j4 a7 |& [) p* @! g( h4 O

* N2 R* `0 p4 O) C! @) q
2.2.5. Verify ; b3 A; O  k1 v8 _' V
功能当选择“边编程边验证”模式时调用验证函数。此功能检查编程的内存是否与 RAM 中定义的缓冲区相对应。
& O% `) M$ }$ Z3 V/ C4 o( j6 n! u4 i) x% s
2.2.6. MassErase 功能
5 n1 b0 L; X( H  YMassErase 功能会擦除全部内存。5 f6 T( g2 X7 J- g. U
如果成功,则返回 1,如果失败,则返回 0。
" j8 m6 V) O9 c, _4 D! N% Kint MassErase (void)
7 V; q2 ?  h0 j" h- S4 t: y3 q
4 d7 P  w2 w% B
2.2.7. Checksum 功能
' r, ], {6 R! W; t0 I描述的所有函数在操作成功时返回 1,在失败时返回 0。
$ N  t. q  k6 K0 A$ o6 w9 p7 @$ W9 M. p' C$ J" m
三、利用 X-Cube-Display API 生成 Flash Loader 的方法
. j3 J+ T7 D, P; G# ~8 Z3 q5 w
这里参考 X-CUBE-DISPLAY\3.0.0\Projects\NUCLEO-WB55RG\Applications 目录下的 GFX01M2_FlashLoader 工程的方法,来移植一个 NUCLEO-G474+GFX01M2 的 Flash Loader,这是一个 SPI 接口的 NOR FLASH,芯片型号 MX25L6433F。
! [* |8 Y: G4 u2 \, H7 l7 S, `" ]我们打开 STM32CubeMX,MCU 选择 STM32G474RET6,首先配置时钟,其次这里用到外设有 SPI,还需要对 SPI 进行配置,查看 X-NUCLEO-GFX01M2 和 NUCLEOSTM32G474 原理图,外部 Flash 用到了 SPI2,GPIO 引脚用到了 PB13, PB14, PB15, PA8。SPI2 相关配置参数如下图所示。4 _9 J, U0 c5 t  C+ {1 a5 u4 Y

$ P- P5 S3 S& s& B
1.png
3 ]$ {6 H$ s! E6 S8 Z$ v& R

5 u; F& S/ Q! \+ x$ t

1 y9 `# E5 D3 u. [) d6 p  B0 t  d4 }0 E
* ^9 J1 ]9 v2 E! P3 a
▲ 图1. SPI 参数配置

5 j% C( t& E/ h, ^& F1 i5 [; }7 s  Y& U# ]0 f

; ?: F# t5 w! D2 }4 j- pSPI2 外设相关参数配置结束后,点击 X-CUBE-DISPLAY 标签,为相关的 IO 接口配置对应的引脚和外设。
% Z/ `+ p' [! W: D图片
4 z% G2 i% C5 I+ Y3 |1 T
  K: C+ k( t3 A! f& V5 x

9 q* ?# p; R% }
2.png

9 ?6 n& |9 S; @. D) L& h' ~

6 t* K! G6 ^( Z; N5 H2 v& f
7 s* A6 P; f) L1 {
▲ 图2. X-CUBE-DISPLAY IO 接口配置
7 p* H! a# L9 Q$ m& y

& G; o7 u" h; `
) f7 Z/ d. [8 x$ E
相关参数配置好后,点击 Project Manager,给工程重新命名,由于 Flash Loader 不需要 main 函数,选中配置的 “Do not generate main()”,这样生成的代码就不会有 main 函数。然后点击生成代码按钮生成代码。
& e0 U, Q3 b3 R) s
) x1 S' z3 }) R4 X  y
- u; x/ i+ [' ?( K& {/ Y
3.png

% m, P9 E  c3 v2 Y% T; q  }) k+ d

, U9 p1 h6 i9 ^2 @

$ x5 E/ X9 v! [- J, p
▲ 图3. Project Manager 修改
+ e, p7 V2 k; W8 h1 w. ?) H

2 p8 I7 T/ x" Y! Y

7 D( c9 G. A) b4 H; H8 I+ O+ O生成的代码还需要添加 Dev_Inf.c、Loader_Src.c、Dev_Inf.h、Loader_Src.h,将这个代码添加到 Core 文件夹下的 Inc 和 Src 文件夹,为了方便不同编译器生成的代码能够自动加载这几个文件,复制.extSettings 文件到该工程文件夹,该文件会为工程新建一个 Loader 文件组,然后再重新生成代码。生成的代码用 VSCode 打开,在 main.c 函数中新增 MX_Init()函数,函数主要的功能是复位外设和初始化 GPIO。
$ ]! G! v) w3 P+ J; a# u
& ~% ]% s" |* T  O7 @8 l1 v3 |# h. R# h. e4 |9 {$ l8 J6 s0 a
4.png
3 i" h. p3 s. [
▲ 图4. 添加 MX_Init()函数

5 o( B4 B5 Z4 Y' f2 Y! X* F5 ?  s
关于 Dev_Inc.c 和 Loader_Src.c 文件中的函数,这里就不再做一一说明,大家可以对照附件查看,下面主要介绍下不同编译器的工程属性配置。' P+ _1 j: b6 a* i4 U4 b
7 k  i$ E* d0 Y4 q2 l( o
3.1. STM32CubeIDE 工程配置
' Z+ _) [0 o7 f4 j2 D  J: cSTM32CubeIDE 的配置修改包括从工程中去除 startup_stm32g474retx.s,修改 Linker 文件,修改启动函数入口,添加后处理生成 stldr 文件。
8 Z1 Z2 [, N4 Q
, x! F! U0 c3 A6 x( `

! Z# c# N, B& F
5.png
7 U* e' I# i1 D  d
% v$ r& ]6 l5 {! J$ m4 o' H1 E& [
% s' |1 L5 }- W+ \% `8 ?
▲ 图5. STM32CubeIDE 中将 startup_stm32g474retx.s 从工程中去除
) y( @0 @" O7 l, h  h' S5 H* d

' x8 Y' Z5 V4 [0 a5 m: y7 ^# E( g

% O1 p# |3 ^8 V: w  [: [2 j6 j) X% A修改 Linker 的配置,通过“Properties”打开设置页,将 Linker 文件修改为 STM32_FLASH.ld。  r, O; A' `/ P5 D0 E: x$ g
) `7 g/ g9 {* a
; e. h$ _" s/ K) B/ j
6.png
; ~+ u$ f! o" q' i7 b
' Q1 C$ o2 h7 Y& l
5 T1 t! S* H; ~
▲ 图6. STM32CubeIDE 修改 Linker 文件

. Y! I' k3 I; t! \9 }9 ~
* [4 k0 y( U0 q  ]
通过 “Settings” -> “Build Steps” 配置页中,在 “Post-build steps” 处添加指令 :cmd.exe /c copy /Y "$(BUILD_ARTIFACT)" "..\MX25L6433F_GFX01M2_STM32G4.stldr",编译后生成 stldr 文件。! j1 P* g/ E$ r) m8 z6 V9 l* {* s

* k8 X( `3 D7 K0 h
  `" w) q$ T: i  H+ p
7.png

* Z" o- Z6 s" g* g3 Y
▲ 图7. 在 STM32CubeIDE 中添加后处理语句
8 t4 `1 ]/ v# c" d
  }& j( ~5 Y/ D# s( A8 b0 D
当这些配置好后,重新 Build 工程,这样就会产生所需要的 Flash Loader。
; J8 f0 _/ v( s# @9 y" K( b( z$ R. W, K9 P" a
3.2. KEIL 工程配置
2 l! F/ x& z- U' Y6 X6 \2 a, R与 STM32CubeIDE 配置过程类似,KEIL 的配置过程主要包括以下操作。在 Target 标签页,Arm Compiler 选择“Use default compiler version 6”,如下图所示。2 u1 d0 J) E- J" Q# ~* l

) _8 x2 \  @: b. z7 ?1 u0 q$ A+ u  V
1 V7 @& r8 k* [$ x
8.png
/ V  Q# V4 A: v

3 q' a) I0 c0 u9 x
! J$ ?0 j$ Z6 E4 r" b7 ]8 S
▲ 图8. 更改 Arm Complier

' K% g) g- k+ l: e' ?在 startup_stm32g474xx.s 的文件属性中,去除勾选“Include in Target Build”和 “Always Build”,这样这个文件就不会被编译和包含在这个工程中。& z+ X. g4 q/ l( _7 r, D

8 y9 a) y7 C3 H1 w( K
6 ~$ d+ D  ]5 H
9.png

1 f/ @- }) n/ J. X% q. H' w( A

& Q% D6 o% t! a- n/ ]2 ~

$ v' L  g; B. G
▲ 图9. 在 KEIL 中将 startup_stm32g474retx.s 从工程中去除

: y+ A* e0 ]% P* A8 ~% F* O' ~6 j) n8 |% O( `6 c; ?7 I% Q% O' \. v
* y' P; h1 @! E, \: _0 T0 A1 p, s
在属性界面,切换到 Linker 界面,去掉“Use Memory Layout from Target Dialog”勾选,修改链接文件,将链接文件更换为 stm32_loader.sct,同时注意在 Misccontrols 添加“--paged --pagesize 0x10--diag_suppress L6305” 。6 @# w& g8 V( \
8 s& _* ?1 c% |" q, s* ~- f) J
: M/ l: `# O( a) Z
10.png

+ S8 T; P7 D6 a1 L" D
▲ 图10. KEIL 中修改链接文件

( W0 _$ p* f  y( d7 b
+ @  F2 s8 W, d2 C
与 STM32CubeIDE 配置类似,添加后处理语句“cmd.exe /C copy /Y "!L" "..\MDK-ARM\MX25L6433F_GFX01M2_STM32G4.stldr"”。
' I! W' }$ ?0 c% f! r  R4 ^/ i9 i
/ C* P; s, m/ P# e: F+ _0 _
11.png
, l( h) O4 W) V/ k! L2 I3 i4 V" L
▲ 图11. KEIL 中添加后处理语句
: e+ m6 M" z- Q9 h$ b0 j1 w

2 v) h. |# H4 Y# a) n2 C' `
6 `: x7 [( _* b# H+ {" Z2 k, o8 G
这些配置好后,重新编译代码,会在 MDK-ARM 文件夹下生成 stldr 文件。
6 E! G$ h$ x8 U4 i
& ]7 d5 ~' Z, H$ m9 E

& X) n- V, A! u# [3 e1 l) I3.3. IAR 工程配置" e" E7 `  u# b% w" T0 H) f
IAR 工程配置与 STM32CubeIDE 和 KEIL 的过程类似。
( W  f1 V$ {- A, m. w1 X- E$ m) b
) ?7 @  ?6 V" G
# h' R% r7 E: N7 Y3 k0 K- ?" E
12.png

! A5 g2 X) c( u1 q+ I' h2 e& h) r; K4 p

% c; C9 X/ \7 p8 `
% \' U* s9 B# {: r
▲ 图12. IAR 中将 startup_stm32g474xx.s 从工程中去除
$ ^" ~6 P4 q# _( `3 T5 m  v4 ~! n
/ D, m7 U- |- k
; X5 J" t+ T  y# ~
13.png

0 M' a& H! y) C: n- z+ S' E" K. M. I; H( F1 i* h
▲ 图13. IAR 中修改链接文件

3 j/ x& ]  n/ M) }

8 \) P" X9 @3 C" @2 k" i7 s

3 _$ _& R- s, G4 r7 w% g4 n

- t; a: G: p0 s, \* Y' L
14.png

8 T( v$ y8 v0 v
( j# B3 @! h  x5 E. G9 L" H
▲ 图14. IAR 中更改入口函数

7 `1 P) X% }% t. W, M1 ?! o
9 H, u5 I/ h; y1 s

; t; [5 m% N8 _

6 N& _7 }5 |; q- p
15.png
$ S( K+ P7 _  I
+ A# d) C7 n8 t  m* V$ n: ]. z
▲ 图15. IAR 中添加后处理函数
* I$ C4 ^9 i0 {/ S- x+ W  ~7 P

2 w* _! x9 R- x5 w# u% t: r  ^
7 {: H% X( b/ {! U+ h
这些配置好后,重新编译代码,会生成 stldr 文件。
% i9 N( b4 N, X2 Z( L
+ R2 B$ Y. P/ p" S
四、小结
( f& [& m9 L2 R" i# c本文结合 X-Cube-DISPLAY 3.0 软件包中的示例,介绍了利用 X-CUBE-DISPLAY API 进行 Flash Loader 的方法,如果用户选择的 Flash 是 MX25L6433F 这款 Flash,那么可 以参照此方法,来快速开发自己的 Flash Loader,如果所选的 Flash 不是 MX25L6433F,也可以参照此方法,重新编写对应存储器的驱动来开发对应的 Flash Loader。+ x, J8 U) e' v( ^/ ^* O0 @: J4 R

  L8 e0 e: v. }9 H% ]+ T; D
! W# b# C8 ?  E) S- Q( _
转载自: STM32
7 L6 K* d2 {( ]1 P  \" F如有侵权请联系删除) [3 i$ s5 |' Y+ G0 ]
: I8 H0 @/ l* h6 S
: N) T1 g8 S% R$ J. W5 A
' C, j+ @: [7 z% l
赞 收藏 评论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 手机版