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

【经验分享】STM32 IAP固件升级(一)

[复制链接]
STMCU小助手 发布时间:2022-1-15 22:19
章节说明
STM32 IAP固件升级实验分为一下的章节(加粗的字体是本章节的内容):
一、Flash和RAM的区域划分、工程建立、程序分散加载、程序烧写
二、Stm32 bootloader、application、firmware 程序的分析和编写
三、使用DMA收发串口的不定长数据
四、通信协议的设计
五、STM32 IAP程序的设计, B+ M! |& l9 O8 f0 C
六、上位机的程序的编写
* a7 F6 w' Q8 i* ?
/ s$ q0 B: @: t- A
一、Flash区域的划分1.区域划分
  • 实验使用的是 STM32F103VET6型号的MCU。这个单片机的型号的内部flash的大小是512Kb, RAM的大小是64Kb。
  • 因为一般使用的都是flash的启动方式(即flash 的起始地址0x0800 0000被映射到 0x0000 0000。STM32的启动方式可以查看《STM32中文参考手册》) 所以flash的区域划分如下:
    7 e, Y" L# }1 B) \
1627979-20200118160928915-2018591605.jpg
+ M9 }  x3 k9 N2. flash 分区说明
  • 0x0800 0000 到 0x0800 b7FF 地址的flash块划分给bootloader,大小是46kb
  • 0x0800 B800 到 0x0800 BFFF 的flash块划分为参数表(parameters),大小是2Kb
  • 0x0800 C000 到 0x0804 3FFF 的flash块划分为应用程序区 (application),大小是224Kb
  • 0x0804 4000 到 0x0807 BFFF 的flash块划分为程序升级区 (update region),大小跟应用程序区一样 224kb
  • 0x0807 C000 到 0x0807 FFFF 的flash块划分为固件区(firmware),大小是16Kb/ |! P; ]6 d+ R6 P! n0 X+ E
3. 每个分区作用
  • bootloader 启动加载程序,主要用来加载和启动应用程序,还有更新应用程序
  • parameters 主要用来记录信息,bootloader 和 application 的信息交互
  • application 应用程序区,主要用来实现所需要的业务的程序
  • update region 程序更新区,主要存放更新下载的程序,当然也可以直接下载到 application 区,但是如果更新失败了,应用程序就不能执行了。所以单独划分一块区域,存放更新下载的序,更新完后再覆盖到application然后复位运行
  • firmware 固件区,主要存放一些函数接口,用户可以通过函数指针直接调用。像tiny-4412、smart210、esp32等这些板子的芯片在irom里面都提供了一些函数接口,通过地址可以直接调用这些函数。/ P3 E1 f( v- U& E  I1 W
二、RAM内存的划分
, X. a1 h+ e# m7 h0 J2 p1、区域划分
RAM(内存)的起始地址是 0x2000 0000,大小是64Kb。在实验主要将它划分为两块。一块是从 0x2000 0000 到 0x2000 FBFF 大小是63Kb。另一块是从 0x2000 FC00 到 0x2001 0000 大小是 1Kb,划分如下图
1627979-20200118161003642-847963352.jpg
2、区域的作用
  • 63Kb这块内存区域主要是用于 bootloader 和 application 应用程序的可读可写段(RW),未初始化或者初始化为0的数据段(ZI)、堆空间、栈空间
  • 1kb这块内存区域主要是用于 firmware 区域的可读可写段(RW),未初始化或者初始化为0的数据段(ZI)
  • 注意:firmware因为没有初始化堆,所以不能使用malloc这类堆内存管理函数。
    $ O& M% J4 B$ H9 r1 K7 H
3、简单说明
  • 因为STM32的flash 是norflash 读的时候可以像内存一样读,但是写的时候不能像内存那样子写,所以这些 RW 段 ZI 段都是加载到内存里。加载到哪里,这是由分散加载文件.sct文件(和链接脚本一个意思)里面说明。至于怎么加载 ,stm32 函数库的start_up.s文件的__main 到 main函数的过程就是加载数据到RAM空间。后面再介绍.sct文件
    4 Q" w5 I7 P; _! h; p" l; M
三、工程建立
工程中需要三个project,分别是 bootloader application firmware 如下图:
1627979-20200118161053289-1264155561.jpg
0 c, E8 R  G0 h2 F# s
四、分散加载
因为程序存放在不同的区域了,并且每段区域的程序是独立的,所以在链接每个程序的时候需要告诉连接器,程序怎么放,程序加载启动的时候又应该怎么加载,堆区和栈区的位置这些都要告诉链接器。我们可以通过分散加载文件.sct 文件来告诉链接器。下面来看一下这个文件
1.原来的分散加载文件6 q& M$ A! W! E2 q  ~1 N
  1. ; *************************************************************9 X4 j" }4 U6 X+ @) r9 X
  2. ; *** Scatter-Loading Description File generated by uVision ***  R- s+ G. C. m, v4 a
  3. ; *************************************************************3 T, W* G0 j) k7 _" u$ |  P4 d
  4. ;LR_IROM1 段名/域名4 d/ ?% w1 o/ i4 I% ?8 |: r2 ?
  5. ;0x08000000 程序加载的起始地址
    7 n9 @9 V+ M3 y% F
  6. ;0x00080000 加载域的大小$ Q3 }* {. P  w  X" S2 f
  7. LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
    & O2 ^- u$ E; ^" w% C
  8.   ;ER_IROM1 执行域的名称  * ?/ X" m+ @1 u6 e3 j* W
  9.   ;0x08000000 程序的执行起始地址7 B) w" ]; h2 x3 r
  10.   ;0x00080000 执行域的大小. O/ ]" V5 ^+ ^; `
  11.   ;一般程序是在 flash 里面运行的所以 程序的执行地址等于加载地址,如果想要让程序运行在RAM中,执行地址修改为RAM的地址
    # _, b; X8 l5 ?' s2 `( U0 Y
  12.   ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
    * A4 z7 J5 v, j2 m0 f
  13.    ;下面就是指定某些段怎么链接了
    ' x/ q' k- v, Z* `6 e6 P4 X
  14.    *.o (RESET, +First)   ;链接的时候最先存放的是 所有.o文件的RESET段,紧跟的是First段(RESET段在start_up.s文件中有定义). ?" ~7 N* A: C! @: i9 m& q- T
  15.    *(InRoot$Sections)   ;然后存放 __main 到 main的这段代码,这段代码主要是将flash的RW和ZI段加载到RAM中) q- z7 t' V- Q- A* O1 ]/ E
  16.    .ANY (+RO)            ;紧跟着的是所有文件的只读数据(RO段),一般是向量表、代码段和常量(字符串常量,和const修饰的数据)9 i; h  k. d. D0 T! o6 j
  17.   }
    ) _# U  z* i& c. C# i- E/ v
  18. ;RW_IRAM1 可读可写数据的段名! u" l/ o3 P% ^  S
  19. ;0x20000000起始地址  9 @$ z( c8 J* ?% W. g, L, u
  20. ;0x00010000大小
    6 t+ a; l& n9 _, o" X
  21.   RW_IRAM1 0x20000000 0x00010000  {  ; RW data
    ( b" `3 H& x" S& S
  22.    .ANY (+RW +ZI);紧接着的是(RW段),(ZI)段! V+ X, b3 G& j
  23.   }4 U6 o8 y8 o! i
  24. }
    ( |0 _1 M4 P% K8 N
  25. 3 G; f- A2 z( Z8 c' {
复制代码
3 c! A( y$ b; i) w' i, Q" @
Region的名称可以自己定义或者修改,重要的是地址要分配对就可以了。
2 o5 Z; m5 H% ]5 A. j; B/ c2 PHeart_of_Eagle这位博主有一篇比较详细的博文值得参考,不过不是MDK的sct文件的,原理都是大同小异' P! o2 |3 ]* q; W- w
MDK也是有详细的帮助文档,不过是纯英文的,想用好sct可以阅读里面的内容! j7 \( c$ o6 V  b! X* o
1.
1627979-20200118161128852-617757783.png - b+ x# @+ [% R! f9 m9 @% l0 r

: J6 ?4 l" m  |# y* N2 @7 Z
2.
1627979-20200118161146238-1228850186.png
6 Z/ Y/ \+ ]0 D& S9 X8 X
2.修改bootloader的分散加载文件
根据上面的flash和RAM的划分修改sct加载文件,如下代码块:
  1. ; *************************************************************) }: |: H- E$ O: d& r
  2. ; *** Scatter-Loading Description File generated by uVision ***& ^  y; Q( Q. y$ w8 h" S  E8 ^
  3. ; *************************************************************4 D# Y/ {+ {/ Q: t3 n
  4. ;因为bootloader是第一个启动的程序,而且机器上电复位的时候是从0x0800 0000开始执行(因为被映射到了0x0000 0000)地址
    5 V0 K7 Y/ }- [( a
  5. ;所以bootloader加载域的起始地址和执行地址都是0x0800 0000; W* r, K& @4 B  o
  6. ; 0x0000B800域的大小(46kb)也是通过上面的设计的分区来填写
    ) y2 `% h% j! j* m( ^5 z
  7. LR_IROM1 0x08000000 0x0000B800  {    ; load region size_region
    ; G) L) l- B0 g9 Q0 V
  8.   ER_IROM1 0x08000000 0x0000B800  {  ; load address = execution address
    ! s; X9 u1 Q1 E+ a, f+ A, E
  9.    ;里面段的存放位置使用默认的就可以8 o$ l/ U) c6 J9 V. |3 y
  10.    *.o (RESET, +First)9 X6 ?1 l& ^1 F
  11.    *(InRoot$Sections)
    $ z0 E- Y* Y1 Z1 _8 [6 c7 |7 U
  12.    .ANY (+RO)
    / B# k7 G* T6 d' _- C
  13.   }3 Z9 W% l/ \1 n) z
  14. ; 0x20000000 这个也是根据上面的RAW的分区填写,
    : [4 K: B6 p, d0 e* [; E9 e
  15. ;0x0000FC00 大小是 63Kb' {9 x) _5 l( c2 w" h
  16.   RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data7 O9 A: {5 P- Q
  17.    ;段的存放位置使用默认的就可以了
    7 Y5 E6 E& }  R" V; p  n% b5 N
  18.    .ANY (+RW +ZI)
    7 Z: A! X$ ~9 q' M( V: P9 ~0 p
  19.   }0 i, {. Q/ U; V9 x# ]' W: w8 ?) @
  20. }7 b: U9 @% z& m) ?
复制代码

  d- C5 c8 a# L( J1 o% E6 T
  h* t# s) j: v) ^8 X8 K3.修改application的分散加载文件
修改如下,跟bootloader一样,就不啰嗦了
  1. ; *************************************************************
    & c0 p5 g9 c! l0 [3 ^
  2. ; *** Scatter-Loading Description File generated by uVision ***& u9 r4 }$ ~- Z
  3. ; *************************************************************/ t0 R5 A* Y/ O) M. I+ B
  4. LR_IROM1 0x0800C000 0x00038000  {    ; load region size_region7 W8 m: H9 D7 h) A. X- N
  5.   ER_IROM1 0x0800C000 0x00038000  {  ; load address = execution address
    2 F2 p7 q) B  ^
  6.    *.o (RESET, +First)
    9 ~0 X# B4 Q, P- I, c
  7.    *(InRoot$Sections)
    1 \9 x0 ~: i. n6 d$ y! j
  8.    .ANY (+RO)
    1 g! J! i+ z- I+ o# s9 q( S
  9.   }  ?: @. a3 ~* ?" W. x2 ^
  10.   RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data    0x0000FC00
    3 a8 Y6 _7 u: }; p  N6 D, M5 c
  11.    .ANY (+RW +ZI)
    $ K% s) e9 X3 e! I
  12.   }
    ! e6 d: y( N% X& Y0 Z$ \$ }
  13. }, _. G4 ^! g6 W) |4 f4 }
复制代码

: |0 G9 P6 c; G9 Z+ _, o5 S
, S9 ^' b; G+ n0 `. R( m4.修改firmware的分散加载文件
*(InRoot$$Sections) 被注释掉了,因为 firmware 的程序是没有 __main 到 main 函数部分的代码的。下一章节写程序的时候会有讲解。其他的内容也跟bootloader文件差不多,上面的分区来写就可以了
  1. ; *************************************************************9 s5 ?+ Y& B: |5 u
  2. ; *** Scatter-Loading Description File generated by uVision ***
    # v& k6 K  W9 C: \! m) W/ n
  3. ; *************************************************************, }4 ?9 `- B7 F1 w

  4. ; c* a' R2 d& z  i( o
  5. LR_IROM1 0x0807C000 0x00004000  {    ; load region size_region
    ; q/ K" `1 I! i: F5 s% L
  6.   ER_IROM1 0x0807C000 0x00004000  {  ; load address = execution address
    1 U- t+ Y. W' D# C$ M
  7.    *.o (RESET, +First)
      Y, {& A8 x* M) e
  8.    ;*(InRoot$Sections) ; M/ m* {8 T/ z* y7 V
  9.    .ANY (+RO)  o9 f0 K  @0 f2 a; @
  10.   }! a- m' O9 x) x" X4 H
  11.   RW_IRAM1 0x2000FC00 0x00000400  {  ; RW data  
    $ W. B" l4 B7 d- n; _
  12.    .ANY (+RW +ZI)
    ; W, `' _/ w: e1 p( i, g
  13.   }9 e9 T) C) v8 B. K9 y; K
  14. }
    6 E# ~9 O0 x2 c' c) c
复制代码

! z- ?; m* c6 ]6 q# I+ `
. G& `# q% Q7 Y( V3 c7 w* s5. 注意事项
在MDK的默认设置里,链接的时候是不使用分散加载文件的 xxx.sct 文件。要使用 xxx.sct 文件需要将下面的设置去掉
LLK)B5}W)WA(Z28_DYZVX0H.png
6 V/ _0 D0 I  R1 H3 a/ M- S9 R
五、程序的下载设置
  • 由于本章还没实现IAP这部分的程序,所以 bootloader、application 和 firmware的程序都是使用烧写器来烧写到falsh的不同区域。所以需要设置一下。
  • 设置的地址跟大小也是根据上面的flash分区来设置的。
  • 主要设置MDK里面的 Debug -> Flash Download 的这两个地方,设置完这里就可以用Jlink将不同的程序烧写到不同的区域了。
  • 下图是 bootloader 的设置,其他两个也是根据实际来设置6 p, }' ~4 G) o8 y/ I- b$ A! F0 V
    %IM8%5@HK}METIUD`XBCXXG.png
    0 \7 Q$ C* [! o$ w! E. s% B
六、实验现象
说了这么多先来个实验现象吧, 对于下面的程序分析和编写就下一章再写了。% a; f% o( M' q3 u2 j9 p
工程文件已经上传到码云---->
4 a4 H+ J) |/ ~) C9 [' i8 p; q代码可能存在问题,有问题可以留言讨论。
  • hello bootloader 是在bootloader运行的时候打印出来的,打印完后就跳到应用程序执行了
  • num = 10和 num1 = 0 这两个值是通过函数指针调用firmware固件区的函数接口来获取的
  • 打印完上面的两个值之后循环打印hello app
    " g* E+ }6 M4 B& b. I现象如下图:5 d0 C2 m! a8 @- A/ X" L( M
    T6PYBAQPXKFJ3H`NS)G6C2H.png $ }. ^2 }3 B' h, `& n
; }% f% }" I6 s( k

4 m1 r4 b. I) _# q7 {6 x
赞 收藏 1 评论0 发布时间:2022-1-15 22:19

举报

0个回答

所属标签

相似技术帖

官网相关资源

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