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

【经验分享】STM32F103C8T6单片机IAP升级

[复制链接]
STMCU小助手 发布时间:2022-3-23 14:00
关于IAP升级的方法和原理,网上已经有很多资料了,这块就不再说了,现在就将bootloader和app配置方法整理如下:
. {4 a2 a. H. iAPP程序就是一个简单的LED闪烁。0 h" a! P# o; S
APP设置为从FLASH中启动:
$ y3 D  B) u- T' O4 O" o' C! S JCY{4{B3{IDHAO2FM}%JD.png
! K% ^' G4 V: w5 u' @7 x2 G) r6 i, ]- z/ O' q( Z$ ]
STM32F103C8T6单片机flash有64K,前20K空间留给bootloader,从20K之后开始存放APP程序。所以IROM1开始地址设置为 0x8005000,大小为20K。如果APP程序比较大的话,可以修改这个大小值。! n: n$ ^2 @. l7 p+ n
然后在程序开始位置设置重新映射复位向量表。让程序从0x8005000位置开始执行。+ d/ {6 i/ K0 s. y" o
APP设置为从SRAM中启动:* ^7 C% A5 l" e/ b4 O
, L+ {5 d/ G. {  V7 G7 ~
]VQFOT(SZB7%@35IB(WSJ%S.png / H$ Q- A! \. _1 P6 U
) D8 Q0 b* A2 E
APP要从SRAM中运行,那么就要重新映射SRAM中的复位向量表。
2 ~' j/ a" e. W由于在bootloader程序中设置的是接收数据代码存储从0x20001000位置开始。所以此处也要设置为程序直接从0x20001000位置处开始运行。如要要改变SRAM中的复位向量位置,那么必须要和bootloader代码同时修改,只修改其中一个的话,程序运行时可能会出错。
/ E  K4 J: U3 [此处设置SRAM中起始位置为0x20001000,程序大小为10K,也就是0x2800。IRAM1的起始位置就是 0x20001000 + 0x2800 =0x20003800,大小为6k。刚好将STM32F103C8T6单片机的SRAM 20k空间分配完。由于STM32F103C8T6的SRAM空间比较小,所以设置APP从SRAM中启动时,APP代码不能太大。
  L: _7 l- h& {& S* l
, g1 d; s* ^/ L# R7 [APP代码要注意两个地方:一是程序开始时重新映射复位向量表起始位置。二是在选项中设置程序运行起始位置和空间大小。1 J7 A; U7 U+ z; y
5 u# g/ T8 @' [
下来开始配置bootloader代码,通过按键来选择接收APP程序的bin文件,然后通过按键选择从flash中启动代码。  l: Z- X$ n2 Q3 n3 ?3 u( A' I  W

- n: ?+ [- V1 X/ B- L( J
  1. int main ( void )
    ) f6 G/ c: D: ~. j
  2. {4 r7 F& [9 S$ w2 ~* L7 l$ e; u7 r
  3.     u8 key;4 I6 l6 @' M+ J+ w( W
  4.     u16 oldcount = 0;                                //老的串口接收数据值( ^# h, \& a! C% Z( J/ G* |
  5.     u16 applenth = 0;                                //接收到的app代码长度5 w' D. o. f3 R) f; v3 G, w* `$ S# Z
  6.     SystemInit();8 O+ g' K( `+ N3 E7 p# A
  7.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    4 d/ e% g  j5 @. P8 L
  8.     uart_init ( 115200 );        //串口初始化为115200
    % t8 l5 G& E8 S0 c
  9.     delay_init();                            //延时初始化
    8 a9 E5 r+ [7 @0 y2 l( P& _

  10. 4 K! J/ Z+ i8 H5 ^& x9 U/ `# T
  11.     LED_Init();                                          //初始化与LED连接的硬件接口& N. b0 Q0 t% u3 `1 K5 z1 X
  12.     KEY_Init();                                        //初始化按键+ U8 B" `: N& l) t, f0 Y( j; p

  13. 8 C9 c- ?1 H7 [- p: V; o, i
  14.     while ( 1 )# n: N" h4 S& q  F
  15.     {
    9 i9 b5 t* \" H' M
  16.         GPIO_SetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高
    ; _1 C/ P9 T, l+ w4 S4 C
  17.         delay_ms ( 1000 );
    + ^3 `2 g& ]0 ~+ T
  18.         GPIO_ResetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高) q8 f4 I6 }. w$ `
  19.         delay_ms ( 1000 );
      ^+ q2 D, H! ?% y
  20.         if ( USART_RX_CNT )
    * _1 O8 |. {/ I5 v4 s. W' p+ O7 z  v
  21.         {
    8 f" o) P% ?: i5 O! G
  22.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.& b, y0 V( z" A7 E+ Q
  23.             {
    # z$ Z' D5 s9 u0 K/ o/ I8 H
  24.                 applenth = USART_RX_CNT;* @# w8 c, `" o2 U$ W
  25.                 oldcount = 0;
    5 Q8 n+ d: J5 j1 K; R1 J
  26.                 USART_RX_CNT = 0;
    - A4 ]" Y6 M9 \/ c7 s- d
  27.                 printf ( "用户程序接收完成!\r\n" );9 v( `/ n$ Z; t) Q1 K: T
  28.                 printf ( "代码长度:%dBytes\r\n", applenth );/ @+ @$ X  \% E/ h5 u
  29.             }4 s/ J+ O1 z9 y; Q- N, B* q# m
  30.             else oldcount = USART_RX_CNT;
    + A0 X6 P1 \% w$ a
  31.         }9 n/ T( r* l" G( Z: }$ T; G
  32.         key = KEY_Scan ( 0 );
    4 _+ w. |4 ?& u! V  l" m6 z4 b
  33.         if ( key == WKUP_PRES )5 c$ p3 m' P: J2 |3 O) Y/ @
  34.         {
    2 ^0 r: j% D9 Y: y
  35.             if ( applenth ): o6 q0 d3 ?0 o7 B/ K* h0 t2 X
  36.             {
    & n5 ?. p" C( @: O" N  N
  37.                 printf ( "开始更新固件...\r\n" );5 l# y* |: c6 b" {% X" U& W+ ]! f
  38.                 if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.6 u9 P1 x  j. K+ D2 Z& k1 }+ `" _
  39.                 {! i% Z( r* ?0 `5 u
  40.                     iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码0 k& y; R0 N( e! c
  41. ' n0 l" I& W9 c& A
  42.                     printf ( "固件更新完成!\r\n" );
    8 {8 D7 {5 \2 L
  43.                 }! h+ W7 n) M" ^  S+ f0 s
  44.                 else
    6 n& r8 Q  G6 P& @/ c
  45.                 {
    - U- y" ?' O  E1 w) T% G
  46.                     printf ( "非FLASH应用程序!\r\n" );
    2 F& t% G1 S3 g$ `$ u- ]
  47.                 }
    5 l- ?& N5 J. q
  48.             }1 Q: D* K$ N$ F! w7 P
  49.             else# T9 y# E! E, H! l6 }
  50.             {
    2 i! J2 ]# @& ~& ?4 W6 z+ Q
  51.                 printf ( "没有可以更新的固件!\r\n" );7 {2 @- E" D$ b, K
  52.             }
    : a7 X  e1 Y0 m; k/ a9 {1 w, l
  53.         }1 v, a, R8 L+ e4 a% o
  54.         if ( key == KEY2_PRES )
    ! d$ P( w* E' _& J% V
  55.         {" a& \* L3 O+ m5 V# ~3 Z$ k# o
  56.             if ( applenth )
    . a& M3 X; T- f9 @( d  {
  57.             {
    8 O3 E8 z/ D9 ~& s; [* @
  58.                 printf ( "固件清除完成!\r\n" );
    0 s2 Q- q1 x/ Y4 R6 S
  59.                 applenth = 0;! }* q, z3 t5 c8 c, }
  60.             }
    % D1 E5 ^& b% x9 i. @  R3 V
  61.             else; p8 ~  z7 H8 C# h# R( D
  62.             {
    & t, h1 D. o9 R; x
  63.                 printf ( "没有可以清除的固件!\r\n" );
    & g! p+ e3 {/ W- Z0 e( x$ j- C4 r
  64.             }
    : K& j- j6 J" s/ q) X. k. h" ^% n
  65.         }
    0 a* c4 ^" q+ s+ i9 {& J
  66.         if ( key == KEY1_PRES )5 L' F! c3 u2 ~
  67.         {
    % ~# R5 v2 T2 k* s4 ]5 w( w7 V
  68.             printf ( "开始执行FLASH用户代码!!\r\n" );
    ( {( ^0 u0 f/ q* r; r
  69.             if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.+ J5 m# T! L8 E0 q4 {$ W
  70.             {
    + I# A1 k4 n0 V* X! U4 |% R
  71.                 iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    ; Z( w' `) {+ B# s0 z4 ]
  72.             }  E& N# C2 b# A8 F% s; Z
  73.             else
    3 E7 x/ C) u  R5 l+ T
  74.             {' H: A: j0 C# z% i: X: F7 s" e4 B+ ?8 n
  75.                 printf ( "非FLASH应用程序,无法执行!\r\n" );
    : ]8 a. f7 h; ~* [0 v9 I% i! J# c
  76.             }
    : _  D# G8 G- A" Q$ H  a$ F
  77.         }
    3 Y# W4 [# M8 A- @9 Q. p
  78.     }7 B6 ?: {% l) I" K5 c; n
  79. }  D9 o. }$ e2 s- v
复制代码
1 N4 _8 k& q2 G
通过串口将接收到的数据存到SRAM中,然后通过按键将数据从SRAM复制到FLASH中,然后再通过按键选择从FLASH中启动。
; q; [4 H% m2 J' }此处要注意设置数据在SRAM中的存储起始位置和在FLASH中的存储起始位置。8 f1 p0 Z! r7 G. u" t
) u1 x( f" f% k; y9 B
I2V@E8QCMLOSV(7T6V]YILU.png   `- D0 V& h, n! \' f$ u
) n3 ], u" j8 I/ \
将串口接收缓冲区的起始位置设置为 SRAM中的0X20001000位置处,如果APP从SRAM中启动的话,那么这个位置也是程序开始运行的位置。6 R& u& |8 v6 }: F. t/ I# ^

0 e; U, f8 Q3 b+ v/ M0 X- y 99GGZ9$QDPO$(X7}`ZVL9HL.png
9 A3 ?+ _! [- C+ @- n+ R
* }7 o& y, m) {. T! w$ ~将FLASH中复位向量表的偏移位置设置为0x08005000,如果程序从FLASH中启动时,那么这个位置也是程序开始运行的位置。
- L9 Y* f) E4 Z) v$ }, @% X, K" Y! P2 F
, o' L+ r# w/ d+ Y $N7170}2M@S@X[Y%~]3P]M7.png 8 j$ W1 E& n3 _5 ]7 a

: G6 q# f# B  s/ T. V+ t- _下来设置bootloader程序存储地址/ ~9 d9 d( D2 ]& w7 \: J
$ I* |  Y. }  }
2DVY963GVFL7`GT]]SFEKSI.png
) g5 R# e# a2 E' O
1 }% V: e1 T% T! c- F# Z! P6 t8 U  Kbootloader程序运行开始位置设置为0x8000000开始,大小为20K,也就是说FLASH中前面20K位置存储bootloader代码,20k–64k位置存储APP代码。1 H' L0 s$ H( _7 w5 O5 L9 ~
5 R. G! q" B/ L& x- |. X
主程序中的代码比较简单,就是从串口接收数据,存储到SRAM中从0X20001000位置开始处,然后通过按键将程序拷贝到FLASH中从0x08005000位置开始处。然后通过按键选择设置程序从FLASH中0x08005000位置处开始执行。5 d# ~4 ]; D( f) }4 S1 Y5 I" D& T
代码中有几处判断不太好理解,这里说说自己的理解。
9 x  F1 y1 m4 q5 X! b+ T/ C
6 h) _& j3 Q( A4 y- j5 i KP2}G`QS1ZJBKJ_}NDWUC0Z.png 2 H$ R! q0 z( X$ a( o# w7 r
5 ~: m9 J% f; t' e
0X20001000+4 是一个数字,前面加上一级指针 ( vu32* ) ( 0X20001000 + 4 )此时将这个数字变成了地址,也就是 0X20001004这个地址,然后前面再加上二级指针 ( * ( vu32* ) ( 0X20001000 + 4 ) 此时表示的是 取 0X20001004 这个地址中存储的数值。1 l! E- m8 T* U% p! a
此时先看看内存分布图。" k0 s' A* s9 G6 @1 H. ]; a
1 b5 J: [' l2 M! s5 {/ g
6Y]3YU79[PF4XYIZPSXRZPO.png
  j$ E% r" I( {# s; T7 S* s
5 J/ C2 f3 V) Q/ ^/ g" {9 d5 H: y, T串口将程序存储到了0X20001000位置开始处,而程序开始执行时首先要复位向量表位置。也就是说0X20001004位置开始就是程序复位向量表的位置,那么这个位置存储的就是要跳转的地址。而所有程序执行都是从0x08000000位置处开始。+ C! `, B/ C# X, W3 t* @
也就是说如果0X20001004这个地址存储的数值时程序开始执行的起始地址,就说明APP程序在SRAM中存储完成了。下来就可以开始拷贝数据了。
& X, ~& O5 v& T. g( S+ K7 S% x
1 F1 L* Q# B. N/ o- _% i ~H[3U(W(D4COBWQL86SZP1I.png
2 b6 v- I8 i! e: t, H+ \, K9 I" ~- H0 h
* a; e+ q3 h7 e( m! f$ n同理如果FLASH中存储代码开始位置+4处的值刚好是程序开始执行的地址,也就是说程序已经被拷贝到了FLASH中 FLASH中从_APP1_ADDR 位置开始处。5 A) V* e* l) |" ?; w: m- ]
+ X: |- P, i- b5 p7 g3 B
通过对比内存中指定位置存储的数据,是不是程序复位后的起始地址,就可以判断出数据是否拷贝完成。1 {! `' Q! J# m/ X: R8 q& d! ]
下来在看第二种方法,通过串口发送指令来控制bin文件接收和APP运行。! ~  {$ f$ |8 ^- H4 K8 ~5 U, o6 v
. F+ q( C/ r: K
  1. int main ( void )
    - E3 R% N8 P+ z, P: T: W
  2. {+ G8 X$ b! I+ M# J
  3.     u16 oldcount = 0;                                //老的串口接收数据值
    , p7 y, K8 F1 z" \: I
  4.     u16 applenth = 0;                                //接收到的app代码长度
    2 f' p* N* K" ?- q
  5.         u16 app_bin = 0;
    $ S7 K2 c# p! X; d3 a
  6.         u16 app_enter = 0;; S# I$ l  ]2 B: w; X! x6 R
  7.     SystemInit();
    : N+ l0 D4 L* d( a0 c4 k2 e8 S- b
  8.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级9 o" l4 a: t+ e
  9.     uart_init ( 115200 );        //串口初始化为115200
    ! b: Y: d1 j+ k* `' n
  10.     delay_init();                            //延时初始化  f# A, i1 |/ t6 u% t
  11.     while ( 1 )
    1 q# c$ Y6 r: V- o7 ~4 L; F! f9 k: |
  12.     {  M7 f; \; Y# C
  13.                 //         首先判断app代码的首地址是否为0x0800 000,是则进入app,否的话进行引导区。& Y( \' x, T2 l8 z; p: v
  14.         if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.3 E& K& C; ]$ @9 v8 n2 j" d
  15.         {
    ! K" M8 B% ]6 n8 F
  16.             iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    - ]9 b/ \$ x) h
  17.         }3 {4 G9 H, n: S# b$ J
  18.                 //   判断app代码栈顶是否为0x2000 000,不是则进入升级模式,代码如下,其中 FLASH_APP1_ADDR=0x8005000;: B6 F: v7 \9 F
  19.         if ( ( ( ( * ( vu32* ) FLASH_APP1_ADDR ) & 0x2FFE0000 ) != 0x20000000 ) )
    9 \8 B, H/ [# G
  20.         {
    % W, Q/ n  i- F
  21.             printf ( "/***** No APP! *****/ \r\n" );+ Q* I' i3 I9 ~' g9 f2 }
  22.             printf ( "stm32f103c8t6在线升级  \r\n" );( J' p# I  Y) i  W0 f1 _: |
  23.             printf ( "选择对应的app bin文件 \r\n" );
    ; V- W* \5 x) T( G) P
  24.             printf ( "输入 A 发送bin文件 \r\n" );
    , E2 d6 o2 y' B. k* \! c
  25.             printf ( "输入 E 进入app \r\n" );
    # c/ }4 R0 C1 ?/ I4 o  e, T
  26.             while ( 1 ). ~5 B0 {# F7 x3 \) ~9 a/ z% i$ C
  27.             {4 |2 s# m7 X+ A6 k8 v; A" a+ Y8 @
  28.                 if ( USART_RX_CNT )# t% w$ M6 ?: t9 i
  29.                 {7 M. C( z$ `  {4 \( ]5 W
  30.                     if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.
      k) G: s6 T  h' W' B
  31.                     {, A5 n+ W& T+ \- S1 c
  32.                         applenth = USART_RX_CNT;) P6 X/ O2 I! k* l5 v2 R
  33.                         oldcount = 0;
    * l0 o8 U7 q0 v: Q, u
  34.                         USART_RX_CNT = 0;
    $ P( W8 l  ]- L# \: g( u
  35.                         if ( applenth > 100 )
    , n9 Q. l* T% Z# o$ n
  36.                         {
    ! R) V; I* h; `- o
  37.                             printf ( "用户程序接收完成!\r\n" );3 \) }5 W1 ^5 v+ i
  38.                             printf ( "代码长度:%dBytes\r\n", applenth );
    ; ?0 c, F  @9 p- j. |9 T; j
  39.                         }
    # a2 A3 H3 M+ z1 z* x
  40.                     }9 [; `8 y# u& K9 g0 W0 U
  41.                     else - S( Z! E! k/ M- e4 D
  42.                         oldcount = USART_RX_CNT;
    1 w" _) B+ Y( e" t; h
  43.                 }8 s* U  j) O% F+ Y
  44.                 delay_ms ( 10 );7 G  w% s2 N" A+ @1 B" q/ z) X* q% Q
  45. 7 `5 X- w8 m, O. H& g
  46.                 if ( USART_RX_BUF[0] == 'A' )
    0 a4 ]9 t3 F# H" o
  47.                 {$ P8 F6 o! @: b) X! M3 S* b* v
  48.                     if ( applenth )
    7 O; m; m4 A1 R# @. S  o
  49.                         printf ( "\r\n 请发送bin文件 \r\n" );
    5 _' s+ G$ V$ a' ]$ i3 Z
  50.                     app_bin = 1;
    , p' Q9 C, Z& l( e
  51.                     applenth = 0;0 d- [7 k& X% I
  52.                 }
    ) }6 c4 Y& `4 T5 u
  53.                 else if ( app_bin )
    8 E$ }% v2 W) t! j; j" G! a1 l( Z! H9 z
  54.                 {
    : I0 |' p: y" X: M+ X
  55.                     if ( applenth )
    " A7 y( |, `8 u; N# z0 D) y/ n" y
  56.                     {( l7 d; w! k, B5 u( B! P/ p: t- S9 E
  57.                         printf ( "开始更新固件...\r\n" );
      t7 A+ Q* J5 O( q6 `
  58.                         printf ( "Copying APP2FLASH..." );  q$ w5 m2 H: X9 `$ K& }
  59.                                                 //此处 0X20001000 地址为串口缓冲区开始接收数据地址
    " Q' q1 C4 T. b* o3 ^2 A
  60.                         if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX. 串口是否接收到数据
    % Z  E" A% M% J2 |! W, d8 \
  61.                         {                         , g9 K0 d8 p0 b* f8 O' y5 V
  62.                             iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码 $ }+ [! E* e( h. _
  63.                             printf ( "Copy APP Successed!!" );+ r3 r* ]/ i& e9 O0 r% m* H
  64.                             printf ( "固件更新完成!\r\n" );
    " [. n0 H+ S5 O. B, ?# o5 Y
  65.                             applenth = 0;
    / \2 ^: Q" v- ?0 P
  66.                             app_bin = 0;1 e, E- }* G6 G4 ~: W
  67.                         }( |& @1 A0 s9 z" E
  68.                     }/ o5 d  Y; c% L2 H% N3 |( `
  69.                 }
    . X3 a( [# C- I3 J9 v6 i1 l
  70.                 if ( USART_RX_BUF[0] == 'E' )
    ; M5 D7 C3 U) ^$ {3 p2 r
  71.                 {
    * {% v- w, T% Y7 y4 H* u
  72.                     if ( applenth )
    % ?, V, p( D6 v% e/ X
  73.                         printf ( "\r\n 将要执行APP \r\n" );0 d+ `4 c, E8 {
  74.                     app_enter = 1;2 k) E; |  h# `# J
  75.                     applenth = 0;; c% r/ K! ?# q% O- _3 X
  76.                 }
    & [7 M7 g/ R. }6 U2 D4 W, Z( d
  77.                 if ( app_enter )
    & B; U: p' ?4 g
  78.                 {
    6 ?. T2 C$ @* j  \+ k4 a" p$ `
  79.                     printf ( "开始执行FLASH用户代码!!\r\n" );
    7 G: {% G9 l& E+ L" j
  80.                     if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.2 c' C+ ]; v; v0 J
  81.                     {                       . v! G6 N+ B5 B8 l
  82.                         iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    1 U* e6 }0 l; Q
  83.                     }
    # t# i7 U) C8 q& P
  84.                     else 7 w! @2 W2 w+ ^$ H
  85.                         {# v" V# m3 r" ^' d! k! j
  86.                             printf ( "非FLASH应用程序,无法执行!\r\n" );
    . |  e2 l6 X  V, b0 t: k# I2 }# I- g
  87.                             printf ( "Illegal FLASH APP!" );                            6 r1 }8 b/ l& ], u& P, K0 M2 V
  88.                         }
    1 Q; @9 T6 n+ Y: B. Y1 |7 Y- c+ w
  89.                     }7 t' ^7 |9 a% n8 F
  90.             }
    1 T" S# M, ^& J
  91.         }5 c+ o- [+ s( i
  92.     }
    * |" ?3 c1 i" O% O( r  @
  93. }
复制代码

  R) }& L( _! H+ S% y! a. hbootloader代码开始运行后,通过串口的指令来选择要执行什么动作,如果发送的是字符"A",那么就开始接收bin文件,然后将接收到的文件拷贝的FLASH中。如果发送的字符是"E",那么就开始从FLASH中运行程序。( p* o. e4 ?. r/ X, B
% o8 ]. J0 B$ N6 b* E2 W3 \
下来在看第三种方法,自动判断串口是否接收到bin文件,如果接收到了文件就将bin文件拷贝到FLASH中,然后开始自动执行FLASH的中APP程序。
  1. int main ( void )- K" ^+ Z: w) W$ s% j) P
  2. {! H( c: F4 [% X- @. E) j: \
  3.     u8 bit_new = 0;                                        //接收到程序标志
    $ A& C) y% M: |+ {# [6 P
  4.     u8 bit_10s = 0;
    2 F6 {+ {0 G. H
  5.     u16 oldcount = 0;                                //老的串口接收数据值
    # V+ }: `" K, I# y0 h1 c( y
  6.     u16 applenth = 0;                                //接收到的app代码长度
    # r- c$ C, d: f. k" ^) e; X
  7.     u8 t = 0, clearflag = 0;
    . A1 L, S4 t1 `0 T  A" ]
  8. , `. f* d' i( o$ L9 t
  9.     SystemInit();
    8 g/ c1 E3 ?8 C' h* K
  10.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    4 ?7 l0 n9 W% {8 O( _
  11.     uart_init ( 115200 );        //串口初始化为115200
    2 N3 V4 A4 V9 @: ?; d8 [
  12.     delay_init();                            //延时初始化
    ) t' x2 E1 j5 f0 V8 P: r8 e1 G8 |4 \  G
  13.     while ( 1 )
    + L% I: I! V! w5 J1 M8 o* C; t
  14.     {* i3 W6 i8 Z0 O% D& X) L
  15.         if ( USART_RX_CNT )
    0 B: t! W8 {3 J4 e8 A: M2 n7 [
  16.         {
    + O, S' s; p9 y& {5 x+ e
  17.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.
    2 G/ z0 Y3 k4 ~" [* a5 F# K) B
  18.             {
    5 y  q8 e  o1 q5 _2 H5 A; k" m
  19.                 applenth = USART_RX_CNT;4 G. o0 P) y# B# m
  20.                 oldcount = 0;) ?& x$ l' c5 X# K/ ]9 f/ c
  21.                 USART_RX_CNT = 0;0 t6 P3 d& ?& }$ |' R) S
  22.                 printf ( "用户程序接收完成!\r\n" );
    9 g( r8 _! Z( k* w( _9 ]! t
  23.                 printf ( "代码长度:%dBytes\r\n", applenth );
    : f. w# E+ e* g
  24.             }) v7 z. r+ T2 L( f- F& S
  25.             else oldcount = USART_RX_CNT;
    6 o& u; ?9 ^6 Q
  26.         }: w2 h0 @. U4 x3 t: o; Z: e
  27.         if ( applenth != 0 ), S  z( K; u! e5 M9 {: X
  28.         {$ k: u5 R( @6 T
  29.             if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.! j5 ?3 [1 o9 x0 V6 {' S
  30.             {
    9 V' V6 t- |7 {& h' l* @2 j$ u
  31.                 iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码- r4 ?6 M4 V: A9 [" s
  32.                 printf ( "固件更新完成!\r\n" );
    ' c; `: ?2 y' p8 \+ ?
  33.                 bit_new = 1;; a+ |: \( a/ T( J* z  N, X8 H
  34.             }
    3 D9 P- m  R! t) }
  35.             applenth = 0;# O* R- `+ ?7 R) [1 d+ k! ?
  36.         }
    , X" Q8 l- P6 D# z1 m, K
  37.         if ( ( bit_10s == 30 ) || ( bit_new == 1 ) )5 i5 z- A# z0 q7 Q7 \/ m5 j4 O
  38.         {- z7 s, o# I( }* J9 s
  39.             bit_10s = 0;
    ( p, ~8 d& a+ n! \* Q7 ^, [
  40.             bit_new = 0;6 t5 F2 C: I$ _2 F# Z. q
  41.             //执行FLASH中的代码9 H. i0 H  Q8 A* k$ `& n! F9 d0 h
  42. # {7 Y5 n* a5 N0 T4 F; Q
  43. //            if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    5 W1 ~* a% ]+ |, V2 A+ T/ L& U. h
  44. //            {
    3 s& K- `+ X: W/ W% m& ~0 W7 }
  45. //                printf ( "开始执行FLASH用户代码!!\r\n" );1 g2 H+ ^# s9 M/ D' @
  46. //                iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码6 L( S) s+ v" R# ]% o+ L, `$ O9 a
  47. //            }% Q2 C$ Y3 v! @  p% h  E/ c: A
  48.             //执行SRAM中的代码9 }( n1 o9 Z% N, u+ H. {
  49.             if(((*(vu32 *)(0X20001000 + 4)) & 0xFF000000) == 0x20000000) //判断是否为0X20XXXXXX.
    0 B0 L$ P6 j/ _$ b
  50.             {8 j. m  Q( N$ b/ G
  51.                 printf("开始执行SRAM用户代码!!\r\n");/ j  K# n; K) ~; K1 u' |
  52.                 iap_load_app(0X20001000);//SRAM地址: c  a, E6 Q' U7 y! g; b
  53.             }
    2 x: w+ y( Y* q( Q
  54.         }; K# }2 H, O; q4 L  w% }4 r
  55.         t++;; z& [/ D: {7 l( `1 S' l
  56.         delay_ms ( 10 );
    $ x" s9 w! h7 e
  57.         if ( t == 20 )" Z+ m0 V  S2 b+ ?  P
  58.         {
    4 v6 f  V7 X. N
  59.             bit_10s++;           
    " O' B3 i- g/ b3 V. e! v
  60.         }
    ; |4 \! `/ d- o
  61.     }
    * h/ l5 r3 ~2 t1 B1 F' V; b' o4 h
  62. }4 [% h$ a- @8 \( N% Y3 Q9 q, Y
复制代码

, [& s( r3 ]7 I8 U) R) z程序开始运行时,串口一直等待接收bin文件,如果收到了数据,就将数据拷贝到FLASH中,然后开始执行。如果未收到数据,等待一段时间后,自动从FLASH中或者SRAM中开始运行。这块可以自己设置程序在从FLASH中运行还是在SRAM中开始运行。1 v7 l7 c9 V2 Q& ?+ w. d

6 H6 P2 n  X) p4 oIAP升级主要是要搞清楚bootloader和app的地址范围,只要将地址设置正确,IAP功能编写起来还是比较简单的。9 y/ D# f) M" f, W7 ]% u

8 C( J! l9 h3 S% G- }9 j1 J9 L
! s/ U' c! w, n5 k- C& ^/ {
* _! F% r% L. P5 ?
收藏 评论0 发布时间:2022-3-23 14:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版