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

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

[复制链接]
STMCU小助手 发布时间:2022-1-15 22:19
章节说明
STM32 IAP固件升级实验分为一下的章节(加粗的字体是本章节的内容):
一、Flash和RAM的区域划分、工程建立、程序分散加载、程序烧写
二、Stm32 bootloader、application、firmware 程序的分析和编写
三、使用DMA收发串口的不定长数据
四、通信协议的设计
五、STM32 IAP程序的设计- r% B/ U1 p9 H3 a5 x9 n7 z
六、上位机的程序的编写8 ^0 `2 m2 _( `& i

4 s4 Y) H& s! n$ v# m' Y0 p
一、Flash区域的划分1.区域划分
  • 实验使用的是 STM32F103VET6型号的MCU。这个单片机的型号的内部flash的大小是512Kb, RAM的大小是64Kb。
  • 因为一般使用的都是flash的启动方式(即flash 的起始地址0x0800 0000被映射到 0x0000 0000。STM32的启动方式可以查看《STM32中文参考手册》) 所以flash的区域划分如下:
    4 `$ B" j: h* l) s0 C
1627979-20200118160928915-2018591605.jpg
$ _) a  N' i/ v; z$ s4 _+ a2. 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( R& I; a2 l  `* f, G* ~9 O
3. 每个分区作用
  • bootloader 启动加载程序,主要用来加载和启动应用程序,还有更新应用程序
  • parameters 主要用来记录信息,bootloader 和 application 的信息交互
  • application 应用程序区,主要用来实现所需要的业务的程序
  • update region 程序更新区,主要存放更新下载的程序,当然也可以直接下载到 application 区,但是如果更新失败了,应用程序就不能执行了。所以单独划分一块区域,存放更新下载的序,更新完后再覆盖到application然后复位运行
  • firmware 固件区,主要存放一些函数接口,用户可以通过函数指针直接调用。像tiny-4412、smart210、esp32等这些板子的芯片在irom里面都提供了一些函数接口,通过地址可以直接调用这些函数。' Q: H8 ]0 J& W& w2 t
二、RAM内存的划分7 j) S- @$ ^: T; z0 `7 T
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这类堆内存管理函数。; N" t, |9 k. X5 l. s
3、简单说明
  • 因为STM32的flash 是norflash 读的时候可以像内存一样读,但是写的时候不能像内存那样子写,所以这些 RW 段 ZI 段都是加载到内存里。加载到哪里,这是由分散加载文件.sct文件(和链接脚本一个意思)里面说明。至于怎么加载 ,stm32 函数库的start_up.s文件的__main 到 main函数的过程就是加载数据到RAM空间。后面再介绍.sct文件% F4 f( {. ^" K6 @2 S1 c6 _" k9 E
三、工程建立
工程中需要三个project,分别是 bootloader application firmware 如下图:
1627979-20200118161053289-1264155561.jpg
1 k4 U8 U  |* z  z9 w- r; D
四、分散加载
因为程序存放在不同的区域了,并且每段区域的程序是独立的,所以在链接每个程序的时候需要告诉连接器,程序怎么放,程序加载启动的时候又应该怎么加载,堆区和栈区的位置这些都要告诉链接器。我们可以通过分散加载文件.sct 文件来告诉链接器。下面来看一下这个文件
1.原来的分散加载文件
  j$ Y. O% [& S4 ]
  1. ; *************************************************************) u" H* ?- T! v5 Q: m# O# \
  2. ; *** Scatter-Loading Description File generated by uVision ***& G" Y7 i4 S1 X9 I
  3. ; *************************************************************
    * D* G7 [9 r* p: W3 O
  4. ;LR_IROM1 段名/域名7 B2 ?6 _% v+ w- f
  5. ;0x08000000 程序加载的起始地址
    / W% B8 m1 D% E6 u& X( [7 F
  6. ;0x00080000 加载域的大小
    ( j% X6 J% q+ l$ e" M- R& @+ Q
  7. LR_IROM1 0x08000000 0x00080000  {    ; load region size_region2 V$ [" }! L. C$ V! G  g/ D
  8.   ;ER_IROM1 执行域的名称  7 B+ n8 e( A. L
  9.   ;0x08000000 程序的执行起始地址
    " [, g: A! [' m
  10.   ;0x00080000 执行域的大小* I% N2 d" i7 g; \  ^
  11.   ;一般程序是在 flash 里面运行的所以 程序的执行地址等于加载地址,如果想要让程序运行在RAM中,执行地址修改为RAM的地址
    * p! X7 q; V. G
  12.   ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
    - S, u4 D* h$ Q
  13.    ;下面就是指定某些段怎么链接了3 r# k4 H8 d1 z- J2 u0 u! |( t" U
  14.    *.o (RESET, +First)   ;链接的时候最先存放的是 所有.o文件的RESET段,紧跟的是First段(RESET段在start_up.s文件中有定义)
    : M/ k( r7 @) Y; J7 z6 l2 `  v
  15.    *(InRoot$Sections)   ;然后存放 __main 到 main的这段代码,这段代码主要是将flash的RW和ZI段加载到RAM中
    6 G/ b4 K3 b6 G
  16.    .ANY (+RO)            ;紧跟着的是所有文件的只读数据(RO段),一般是向量表、代码段和常量(字符串常量,和const修饰的数据)
    4 Q7 \9 P( V: i
  17.   }+ U  O( \5 }# _# ]
  18. ;RW_IRAM1 可读可写数据的段名
    # d/ Z$ W/ H1 B! _1 ~0 n
  19. ;0x20000000起始地址  * P" E/ ]- I9 u1 C' G
  20. ;0x00010000大小& E5 B# @  p7 {  Y7 [' }2 \
  21.   RW_IRAM1 0x20000000 0x00010000  {  ; RW data
    6 }2 n9 p% a: B3 r5 o
  22.    .ANY (+RW +ZI);紧接着的是(RW段),(ZI)段, u7 ~& n! ~. H1 c( _
  23.   }. E3 T, o1 x/ p% A2 ^0 P- Q* c
  24. }
    3 y  q- h% v4 {4 A1 Q' G

  25. 8 P" a  s; U1 S* n5 X$ X5 P* n
复制代码
& o/ P6 ]/ O1 h1 {/ h
Region的名称可以自己定义或者修改,重要的是地址要分配对就可以了。& A& C6 p8 e2 D/ Z2 w  {8 k8 \
Heart_of_Eagle这位博主有一篇比较详细的博文值得参考,不过不是MDK的sct文件的,原理都是大同小异
& Q' X$ O% H8 j/ H$ b- iMDK也是有详细的帮助文档,不过是纯英文的,想用好sct可以阅读里面的内容5 b! c. N2 ~: V5 A5 u# X
1.
1627979-20200118161128852-617757783.png
+ |( r7 C5 n: a, _7 q6 ]1 [8 |3 `" v8 H. j, S, Q# K( E) B
2.
1627979-20200118161146238-1228850186.png
8 v0 X6 S6 X/ `. \( z9 H* ?! E
2.修改bootloader的分散加载文件
根据上面的flash和RAM的划分修改sct加载文件,如下代码块:
  1. ; *************************************************************5 k* r" S0 f7 Z5 A: ^2 b& H
  2. ; *** Scatter-Loading Description File generated by uVision ***
    & Y3 }  s/ R* Q; c, O( ?" ?5 j
  3. ; *************************************************************
    7 a# [  t3 w, ^' K0 u3 V) J5 c9 y) H
  4. ;因为bootloader是第一个启动的程序,而且机器上电复位的时候是从0x0800 0000开始执行(因为被映射到了0x0000 0000)地址- c" J- }8 b2 T' H& E4 T
  5. ;所以bootloader加载域的起始地址和执行地址都是0x0800 0000
    & w0 s) d* y3 i" ~4 ?  M4 @+ H# X
  6. ; 0x0000B800域的大小(46kb)也是通过上面的设计的分区来填写3 c' X( g. p/ k- B1 W: t, l/ m- {
  7. LR_IROM1 0x08000000 0x0000B800  {    ; load region size_region# e" x. {% J( d" Y3 @
  8.   ER_IROM1 0x08000000 0x0000B800  {  ; load address = execution address
    & Q. V8 b1 @+ ]4 [
  9.    ;里面段的存放位置使用默认的就可以2 A0 C* w" m+ X3 k
  10.    *.o (RESET, +First)
    1 K$ q$ A" Q  ^* k% |! q! U
  11.    *(InRoot$Sections)
    : j! n" b* K' e4 P1 ?1 c3 H
  12.    .ANY (+RO)
    % f0 @* F# k+ S8 W$ Z6 r, b, [
  13.   }
    ! C8 Y4 O* K1 N9 q
  14. ; 0x20000000 这个也是根据上面的RAW的分区填写,: k, V0 t5 {, B3 G  P; o% f
  15. ;0x0000FC00 大小是 63Kb
    ( P4 T  p" O# T6 {" a8 A% T, p
  16.   RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data+ v/ G! P# `, h" ?0 \+ q% m
  17.    ;段的存放位置使用默认的就可以了
    4 p% {1 V4 q; q6 H  m/ [
  18.    .ANY (+RW +ZI)
    & N+ t- a, V6 N( r3 X
  19.   }
    . X# B+ a3 r3 Q) q9 s( y; @! e
  20. }
    8 q; V: J: D1 N0 R8 g, S; ^
复制代码
" u. B0 h7 O  Q  i. B( S) h
3 t! s* Z9 o1 }! r
3.修改application的分散加载文件
修改如下,跟bootloader一样,就不啰嗦了
  1. ; *************************************************************
    ; o8 e, r  U7 q+ ^: Z! x* h0 W* a
  2. ; *** Scatter-Loading Description File generated by uVision ***: N$ [4 G: W& |0 h8 m; U( L
  3. ; *************************************************************( d/ `) G" Y6 Z$ N# ~; ]
  4. LR_IROM1 0x0800C000 0x00038000  {    ; load region size_region& ?# x% s5 A: l, t9 t1 {' Y) F& I
  5.   ER_IROM1 0x0800C000 0x00038000  {  ; load address = execution address
    4 K1 z0 _" h; x; l- N
  6.    *.o (RESET, +First)0 u, x7 d4 Y: [& v4 n+ T
  7.    *(InRoot$Sections)
    2 U; I3 G# O0 ~1 C$ O
  8.    .ANY (+RO)* q: a3 ]" n# S9 \5 m
  9.   }, b5 r% {6 s( O
  10.   RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data    0x0000FC006 {# j" P" ~' P, M
  11.    .ANY (+RW +ZI)6 q; I) R4 R- ]1 I0 x  Y
  12.   }; G0 h) ?  w% M+ K1 @, ^' s. v
  13. }* B) l" e8 [/ m$ [. D/ p! r
复制代码
  [2 K4 W$ a- c% \% v( \' b

- @) ^* d4 w5 ^4 ?: S4.修改firmware的分散加载文件
*(InRoot$$Sections) 被注释掉了,因为 firmware 的程序是没有 __main 到 main 函数部分的代码的。下一章节写程序的时候会有讲解。其他的内容也跟bootloader文件差不多,上面的分区来写就可以了
  1. ; *************************************************************0 |3 o: A- e5 C6 a% Y. C/ W; P
  2. ; *** Scatter-Loading Description File generated by uVision ***1 g7 q7 a, E, k3 {
  3. ; *************************************************************2 u; K* l7 z8 d1 o# b

  4. 0 P; r& q9 E6 x( B
  5. LR_IROM1 0x0807C000 0x00004000  {    ; load region size_region
    ' U0 D/ }5 Q$ N, i: O1 `
  6.   ER_IROM1 0x0807C000 0x00004000  {  ; load address = execution address; c: m  G! N3 b, T4 N  T( ^
  7.    *.o (RESET, +First)
    / B, U% y8 c+ k: r. A6 ^) I$ w
  8.    ;*(InRoot$Sections)
    8 ?: v9 ~7 _; m. A9 p0 {
  9.    .ANY (+RO)- I- L  }, @* i7 x6 U/ z( u6 B+ d
  10.   }$ n: n2 {/ L- b  l6 d4 `; Z
  11.   RW_IRAM1 0x2000FC00 0x00000400  {  ; RW data  
    ; S* }4 h8 D; W7 r0 @' c7 }4 p
  12.    .ANY (+RW +ZI)
    7 @- ?; d7 m. H. o! v7 ^
  13.   }
    7 E$ U- v$ H. s0 n; F, N
  14. }; Z5 |+ u& Q2 Y  @0 D! U4 _( c3 I
复制代码

- V  ~0 p* z' c% H
8 S1 A* T& r& {, B5. 注意事项
在MDK的默认设置里,链接的时候是不使用分散加载文件的 xxx.sct 文件。要使用 xxx.sct 文件需要将下面的设置去掉
LLK)B5}W)WA(Z28_DYZVX0H.png $ F7 q9 D! A* H% l3 F  Y; E: v
五、程序的下载设置
  • 由于本章还没实现IAP这部分的程序,所以 bootloader、application 和 firmware的程序都是使用烧写器来烧写到falsh的不同区域。所以需要设置一下。
  • 设置的地址跟大小也是根据上面的flash分区来设置的。
  • 主要设置MDK里面的 Debug -> Flash Download 的这两个地方,设置完这里就可以用Jlink将不同的程序烧写到不同的区域了。
  • 下图是 bootloader 的设置,其他两个也是根据实际来设置- p, ]7 q! [9 E" A: m
    %IM8%5@HK}METIUD`XBCXXG.png
    , _  ~6 G9 t/ c: V" }2 g6 P
六、实验现象
说了这么多先来个实验现象吧, 对于下面的程序分析和编写就下一章再写了。
! P8 h3 A5 ?6 w; f; O% v2 O. w' S3 R工程文件已经上传到码云---->" D0 p% |; }! R' k; j+ x5 j2 G
代码可能存在问题,有问题可以留言讨论。
  • hello bootloader 是在bootloader运行的时候打印出来的,打印完后就跳到应用程序执行了
  • num = 10和 num1 = 0 这两个值是通过函数指针调用firmware固件区的函数接口来获取的
  • 打印完上面的两个值之后循环打印hello app
    , q  V, _; G( F; @8 a5 b现象如下图:' P# ~- @2 b4 u, b3 `  ]" {+ M: {2 @
    T6PYBAQPXKFJ3H`NS)G6C2H.png 9 H5 }! R3 b* R- o( N
; D# A/ p3 i8 b! ^

; D2 L4 W$ X0 b/ G4 m9 x" j# g
收藏 1 评论0 发布时间:2022-1-15 22:19

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版