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

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

[复制链接]
STMCU小助手 发布时间:2022-1-15 22:19
章节说明
STM32 IAP固件升级实验分为一下的章节(加粗的字体是本章节的内容):
一、Flash和RAM的区域划分、工程建立、程序分散加载、程序烧写
二、Stm32 bootloader、application、firmware 程序的分析和编写
三、使用DMA收发串口的不定长数据
四、通信协议的设计
五、STM32 IAP程序的设计: y% D( L' W8 b  ^# [1 ~
六、上位机的程序的编写
/ n& y5 P& |& `5 \9 R
' b# B* s. K( C% k: r) M2 D
一、Flash区域的划分1.区域划分
  • 实验使用的是 STM32F103VET6型号的MCU。这个单片机的型号的内部flash的大小是512Kb, RAM的大小是64Kb。
  • 因为一般使用的都是flash的启动方式(即flash 的起始地址0x0800 0000被映射到 0x0000 0000。STM32的启动方式可以查看《STM32中文参考手册》) 所以flash的区域划分如下:9 U0 f$ `4 D8 _! m! a5 w* F
1627979-20200118160928915-2018591605.jpg
* b* P7 C0 O; s% H& @( h2. 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
    & \8 k! O3 v. i! F
3. 每个分区作用
  • bootloader 启动加载程序,主要用来加载和启动应用程序,还有更新应用程序
  • parameters 主要用来记录信息,bootloader 和 application 的信息交互
  • application 应用程序区,主要用来实现所需要的业务的程序
  • update region 程序更新区,主要存放更新下载的程序,当然也可以直接下载到 application 区,但是如果更新失败了,应用程序就不能执行了。所以单独划分一块区域,存放更新下载的序,更新完后再覆盖到application然后复位运行
  • firmware 固件区,主要存放一些函数接口,用户可以通过函数指针直接调用。像tiny-4412、smart210、esp32等这些板子的芯片在irom里面都提供了一些函数接口,通过地址可以直接调用这些函数。" k) ]. D* `* y, q4 x; F% |
二、RAM内存的划分  k; P- L+ |3 l3 C% T: h$ @; E! g& z
1、区域划分
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这类堆内存管理函数。  `3 ]- b# o* U3 z1 z: f
3、简单说明
  • 因为STM32的flash 是norflash 读的时候可以像内存一样读,但是写的时候不能像内存那样子写,所以这些 RW 段 ZI 段都是加载到内存里。加载到哪里,这是由分散加载文件.sct文件(和链接脚本一个意思)里面说明。至于怎么加载 ,stm32 函数库的start_up.s文件的__main 到 main函数的过程就是加载数据到RAM空间。后面再介绍.sct文件
    * r5 n. G( T; S& b
三、工程建立
工程中需要三个project,分别是 bootloader application firmware 如下图:
1627979-20200118161053289-1264155561.jpg : x# |! S) N- P& Z1 f
四、分散加载
因为程序存放在不同的区域了,并且每段区域的程序是独立的,所以在链接每个程序的时候需要告诉连接器,程序怎么放,程序加载启动的时候又应该怎么加载,堆区和栈区的位置这些都要告诉链接器。我们可以通过分散加载文件.sct 文件来告诉链接器。下面来看一下这个文件
1.原来的分散加载文件7 o# l$ ]* a( h" l
  1. ; *************************************************************# P- m6 Z1 G# ^# ?0 n, t
  2. ; *** Scatter-Loading Description File generated by uVision ***+ g( A% \) S- [; X6 L; i
  3. ; *************************************************************
    ) N5 g0 g, z" q2 k: `3 J5 ]4 b: P" r
  4. ;LR_IROM1 段名/域名
    3 F9 L' n0 \, }: T; {
  5. ;0x08000000 程序加载的起始地址" J0 {( j! G3 H6 J% J2 Q
  6. ;0x00080000 加载域的大小2 f& F% i, Q! d
  7. LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
    9 f+ E( S/ m5 A0 ?3 a- \
  8.   ;ER_IROM1 执行域的名称  
    7 r  N6 y5 a( Z/ N- m
  9.   ;0x08000000 程序的执行起始地址
    , f0 S: B4 Y8 S" {$ S) f
  10.   ;0x00080000 执行域的大小
      x$ r+ X' H) S% F6 n8 f; J- Q  D$ d
  11.   ;一般程序是在 flash 里面运行的所以 程序的执行地址等于加载地址,如果想要让程序运行在RAM中,执行地址修改为RAM的地址
    ) D' y9 h6 T3 }1 f9 V
  12.   ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address! r$ ]  g4 @. l/ ~6 ?
  13.    ;下面就是指定某些段怎么链接了
    ( ~  k! v4 j% e
  14.    *.o (RESET, +First)   ;链接的时候最先存放的是 所有.o文件的RESET段,紧跟的是First段(RESET段在start_up.s文件中有定义)
    " e; R! X1 @- t  s, L# v
  15.    *(InRoot$Sections)   ;然后存放 __main 到 main的这段代码,这段代码主要是将flash的RW和ZI段加载到RAM中
    : I1 H6 m8 ^6 V2 Y) \/ `0 q" N
  16.    .ANY (+RO)            ;紧跟着的是所有文件的只读数据(RO段),一般是向量表、代码段和常量(字符串常量,和const修饰的数据)
    0 c& `6 ~+ q8 G; c
  17.   }% E2 h( ?! t' p  J, F( |
  18. ;RW_IRAM1 可读可写数据的段名' q) d, ]9 a2 P. v
  19. ;0x20000000起始地址  
    + L+ y6 M8 @  s4 f7 j% U, E4 N3 H- Z
  20. ;0x00010000大小
    6 c2 u: X. z8 K6 X
  21.   RW_IRAM1 0x20000000 0x00010000  {  ; RW data! _: o, Z9 a% Z$ e
  22.    .ANY (+RW +ZI);紧接着的是(RW段),(ZI)段
    " y$ l6 V( ?4 W# D: |& |/ n3 _
  23.   }
    2 ~4 \6 i2 D9 Z
  24. }+ O: P! \. l& Q' J8 x
  25. 6 p3 m: t& K7 P+ G
复制代码
4 U2 u& Z* o2 {+ V6 |2 P  \
Region的名称可以自己定义或者修改,重要的是地址要分配对就可以了。
& }% W3 \1 ]" y& f  P* mHeart_of_Eagle这位博主有一篇比较详细的博文值得参考,不过不是MDK的sct文件的,原理都是大同小异
! |. i0 |3 j; [# @! JMDK也是有详细的帮助文档,不过是纯英文的,想用好sct可以阅读里面的内容
, o4 }5 A" t: x/ s- i; a
1.
1627979-20200118161128852-617757783.png " V% s4 M( B' Y# Z7 b
4 \  j+ I- {9 M) k1 A
2.
1627979-20200118161146238-1228850186.png ' h4 s6 t4 q+ C/ w; l! }' ^
2.修改bootloader的分散加载文件
根据上面的flash和RAM的划分修改sct加载文件,如下代码块:
  1. ; *************************************************************, ~1 N  L0 x; R  n
  2. ; *** Scatter-Loading Description File generated by uVision ***5 y4 e9 E4 G4 K0 l7 V7 G
  3. ; *************************************************************0 ~8 q1 k! A8 y9 B& I
  4. ;因为bootloader是第一个启动的程序,而且机器上电复位的时候是从0x0800 0000开始执行(因为被映射到了0x0000 0000)地址& Z* c( i) z4 g* y
  5. ;所以bootloader加载域的起始地址和执行地址都是0x0800 0000: N, x4 ]% f6 {( @0 l5 v
  6. ; 0x0000B800域的大小(46kb)也是通过上面的设计的分区来填写  Y% H- M+ p6 q- x  W
  7. LR_IROM1 0x08000000 0x0000B800  {    ; load region size_region
    7 t7 h* o) U( ?$ D* r# P) l
  8.   ER_IROM1 0x08000000 0x0000B800  {  ; load address = execution address/ L# v5 O: ~8 t/ ?" p0 e$ z
  9.    ;里面段的存放位置使用默认的就可以$ M' Y5 I# Y1 f! P+ h* k+ a
  10.    *.o (RESET, +First)
      U: c/ a1 t+ g( c9 k0 t
  11.    *(InRoot$Sections)
    0 e5 g# K7 F5 @( e! b5 l
  12.    .ANY (+RO)' e1 B; |9 u) f) l2 y
  13.   }$ u& ^, I( ~+ v1 X) [! G# h
  14. ; 0x20000000 这个也是根据上面的RAW的分区填写,5 `& {/ v' R6 L
  15. ;0x0000FC00 大小是 63Kb
    3 b$ `# C0 t+ d- L4 d; \
  16.   RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data. C& E! F: _# u* h" y$ B8 w
  17.    ;段的存放位置使用默认的就可以了# w2 }$ U  N8 J. ]( U& n& H  g+ N
  18.    .ANY (+RW +ZI)' K1 N& l5 x3 s* t9 o8 T  G
  19.   }& g# n) h# o* F; A& @
  20. }7 N# e- d9 g& v/ |9 y2 k% t( \
复制代码

% F& v! E7 S+ k7 m3 C  h
0 |! z2 Y3 w. L; n3 r- N8 r" _3.修改application的分散加载文件
修改如下,跟bootloader一样,就不啰嗦了
  1. ; *************************************************************
    * @) `! ?* Z& E( n% `
  2. ; *** Scatter-Loading Description File generated by uVision ***
    - d) [, }2 u* C- r9 z) Y
  3. ; *************************************************************8 v' `3 u# v, h
  4. LR_IROM1 0x0800C000 0x00038000  {    ; load region size_region
    3 h! `8 w/ U  j
  5.   ER_IROM1 0x0800C000 0x00038000  {  ; load address = execution address
    9 [8 J0 s5 H+ N. I$ m7 U" o! Y
  6.    *.o (RESET, +First)
    " V0 }0 v) ~$ [, L0 m
  7.    *(InRoot$Sections)
    1 J* d# b9 X7 m/ ]. Y( y/ G
  8.    .ANY (+RO)
    $ S) O- O( M6 q$ z
  9.   }- W% A6 k% M( K1 Z* P; D, U
  10.   RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data    0x0000FC00
    $ C7 ^9 g: C6 T  g- U6 o% A$ R
  11.    .ANY (+RW +ZI)
    ) _  ~$ {, a, }2 G9 Z
  12.   }
    1 M6 V% a% G0 b5 |: M) D1 d
  13. }* K6 Q# X2 O- g
复制代码
1 n- Y2 A. ?5 G3 |: C8 H% x; r

) r2 |( a4 C8 K; r4.修改firmware的分散加载文件
*(InRoot$$Sections) 被注释掉了,因为 firmware 的程序是没有 __main 到 main 函数部分的代码的。下一章节写程序的时候会有讲解。其他的内容也跟bootloader文件差不多,上面的分区来写就可以了
  1. ; *************************************************************# t# r0 a$ n) n' Q1 H
  2. ; *** Scatter-Loading Description File generated by uVision ***7 [" Q$ ^; R% m4 V% B
  3. ; *************************************************************
    - r; T  n- [  Q8 r: s1 X6 ]1 ^
  4. 4 e8 d1 T3 P* O! A
  5. LR_IROM1 0x0807C000 0x00004000  {    ; load region size_region
    % h8 k! {3 d5 O$ J& `" |
  6.   ER_IROM1 0x0807C000 0x00004000  {  ; load address = execution address
    2 X7 _& q1 ^+ O7 R: K. k& v
  7.    *.o (RESET, +First)
    # r  k  E9 y; z# x
  8.    ;*(InRoot$Sections) % A+ Y) I0 _6 N0 D$ J
  9.    .ANY (+RO)! U; f" j8 [; X: M1 R8 M
  10.   }
    / f/ H+ g. I4 ]. {5 S; J% u: [# G
  11.   RW_IRAM1 0x2000FC00 0x00000400  {  ; RW data  $ }$ G1 W# K, |3 V3 q; g! s4 e
  12.    .ANY (+RW +ZI)
    ) n& ~. |" Q% f" c4 M3 ^
  13.   }% `; m# V+ N* }8 p+ ?$ e
  14. }! ~. r3 c3 p( q3 E2 V$ U
复制代码
$ q' R) O( J1 W+ V
  \$ m$ o8 J9 p. n- M* e1 ?
5. 注意事项
在MDK的默认设置里,链接的时候是不使用分散加载文件的 xxx.sct 文件。要使用 xxx.sct 文件需要将下面的设置去掉
LLK)B5}W)WA(Z28_DYZVX0H.png
0 G, e3 n$ t2 g8 m
五、程序的下载设置
  • 由于本章还没实现IAP这部分的程序,所以 bootloader、application 和 firmware的程序都是使用烧写器来烧写到falsh的不同区域。所以需要设置一下。
  • 设置的地址跟大小也是根据上面的flash分区来设置的。
  • 主要设置MDK里面的 Debug -> Flash Download 的这两个地方,设置完这里就可以用Jlink将不同的程序烧写到不同的区域了。
  • 下图是 bootloader 的设置,其他两个也是根据实际来设置
    7 ~" a+ l! O. n: z# h %IM8%5@HK}METIUD`XBCXXG.png ( ?! g1 b4 }) D& ?. h% g$ ]! L
六、实验现象
说了这么多先来个实验现象吧, 对于下面的程序分析和编写就下一章再写了。/ x0 R7 K8 B- R3 p% n
工程文件已经上传到码云---->
4 t4 H9 e+ L- Y0 V5 K; Q; L; K' `代码可能存在问题,有问题可以留言讨论。
  • hello bootloader 是在bootloader运行的时候打印出来的,打印完后就跳到应用程序执行了
  • num = 10和 num1 = 0 这两个值是通过函数指针调用firmware固件区的函数接口来获取的
  • 打印完上面的两个值之后循环打印hello app; c* D; O% G" c, e1 U# ]- R
    现象如下图:0 H- ^+ `8 A5 R3 j
    T6PYBAQPXKFJ3H`NS)G6C2H.png / N6 J% @- g. s* E1 b
' D3 J' ?) D+ K, n8 r% J
6 T8 ?) e! N! c; Y
赞 收藏 1 评论0 发布时间:2022-1-15 22:19

举报

0个回答

所属标签

相似技术帖

官网相关资源

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