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

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

[复制链接]
STMCU小助手 发布时间:2022-3-23 14:00
关于IAP升级的方法和原理,网上已经有很多资料了,这块就不再说了,现在就将bootloader和app配置方法整理如下:
; f9 W! {) `( [8 K$ h/ \" y: tAPP程序就是一个简单的LED闪烁。6 C6 x& L* k: f6 h  k' a, G' t6 W
APP设置为从FLASH中启动:4 c+ M, p% v: w, j2 ~
JCY{4{B3{IDHAO2FM}%JD.png 8 w; i& c- d. s$ _( W

+ O7 O+ G$ f( m6 }' P- @STM32F103C8T6单片机flash有64K,前20K空间留给bootloader,从20K之后开始存放APP程序。所以IROM1开始地址设置为 0x8005000,大小为20K。如果APP程序比较大的话,可以修改这个大小值。0 O0 L5 _3 ]% |1 }2 ]' W3 i6 x
然后在程序开始位置设置重新映射复位向量表。让程序从0x8005000位置开始执行。) [" V2 r+ z9 J# p. q. M
APP设置为从SRAM中启动:
# L0 D' Z! k+ \* I. o- P* n
5 _! O' O& D, N% D7 i ]VQFOT(SZB7%@35IB(WSJ%S.png - W" q+ h7 o0 ]; E3 A
- T! B8 l7 f% [- O9 e( t7 a
APP要从SRAM中运行,那么就要重新映射SRAM中的复位向量表。
" D- C8 F# O: p2 s% J, V7 _由于在bootloader程序中设置的是接收数据代码存储从0x20001000位置开始。所以此处也要设置为程序直接从0x20001000位置处开始运行。如要要改变SRAM中的复位向量位置,那么必须要和bootloader代码同时修改,只修改其中一个的话,程序运行时可能会出错。  ^$ ~6 l3 ^% r5 S. ~% R
此处设置SRAM中起始位置为0x20001000,程序大小为10K,也就是0x2800。IRAM1的起始位置就是 0x20001000 + 0x2800 =0x20003800,大小为6k。刚好将STM32F103C8T6单片机的SRAM 20k空间分配完。由于STM32F103C8T6的SRAM空间比较小,所以设置APP从SRAM中启动时,APP代码不能太大。
( [2 ?0 V% {3 m0 @; a$ b( Z; [
1 F2 q: n2 s4 ~/ u( UAPP代码要注意两个地方:一是程序开始时重新映射复位向量表起始位置。二是在选项中设置程序运行起始位置和空间大小。. d+ W; d. R$ f0 m2 D9 T- f
* v- ]5 r2 \' ?1 }9 O3 i& r
下来开始配置bootloader代码,通过按键来选择接收APP程序的bin文件,然后通过按键选择从flash中启动代码。
0 v4 K" N' ]* @0 E3 D7 p2 _, J$ r' z: x2 T$ q4 K
  1. int main ( void )/ E) J" ?4 M- _: S9 L0 V- ^' }
  2. {8 c- Z- u( g* i
  3.     u8 key;
    & D% h3 @# j  y. T. a! t( s
  4.     u16 oldcount = 0;                                //老的串口接收数据值, @3 N8 e9 U: v1 k6 ~
  5.     u16 applenth = 0;                                //接收到的app代码长度- E* c: d6 u( z  [5 P
  6.     SystemInit();/ a7 g$ @; I4 B# i0 t# }+ D$ f
  7.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级2 m) g1 w& b" _/ c
  8.     uart_init ( 115200 );        //串口初始化为115200
    9 S: ]' w# C) @% F: P# A
  9.     delay_init();                            //延时初始化
    1 z9 b9 r, C( h  \

  10. 5 O: S+ k2 y/ Y; h+ S5 Y* C, j& C
  11.     LED_Init();                                          //初始化与LED连接的硬件接口- C& K1 y; t6 w2 w0 L
  12.     KEY_Init();                                        //初始化按键
    # ?$ T# }& i( N% Y4 Y6 ?7 t
  13. - l% s3 U% ~/ e2 K# w! u# J' z7 ?# ^
  14.     while ( 1 )
    . ]1 p- `! j, g7 T: u! w
  15.     {/ m% r$ |$ x! f1 D1 B
  16.         GPIO_SetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高7 w0 ?& N( p9 G
  17.         delay_ms ( 1000 );5 p* b! G; M; G% x- ~
  18.         GPIO_ResetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高
    ) i/ O* D+ C8 M
  19.         delay_ms ( 1000 );5 C. A( u; L) ]" \( X6 l
  20.         if ( USART_RX_CNT )
    5 y1 ~4 s0 Z7 A
  21.         {) ^! B* }6 [/ W" x! V
  22.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成./ s' u5 I1 q$ b6 ]
  23.             {) ^7 k* i( [& R) b& x' W+ Z
  24.                 applenth = USART_RX_CNT;
      E, N9 _' h0 {2 J! `2 o
  25.                 oldcount = 0;* k3 t0 |- h( X+ R  H5 ^
  26.                 USART_RX_CNT = 0;
    9 i6 I* M$ \- _+ d9 ]  s+ }/ D. C1 }
  27.                 printf ( "用户程序接收完成!\r\n" );" z% I: P% j, ~3 x& w2 x5 j) V. O
  28.                 printf ( "代码长度:%dBytes\r\n", applenth );
    6 ]  \/ b( o! z8 z2 ~  V! F
  29.             }
    1 W# q6 k+ u3 f4 L! _: u
  30.             else oldcount = USART_RX_CNT;# n* y8 D3 O, v3 g4 _# W% t
  31.         }+ `; [+ t; c7 Z4 p
  32.         key = KEY_Scan ( 0 );
    3 {# k7 P1 k: f3 \
  33.         if ( key == WKUP_PRES ); z6 Q; i5 x; j: y
  34.         {# L% Z! s' F3 C5 |1 x/ c
  35.             if ( applenth )
    ( W- I1 S5 ^- @8 \& A
  36.             {  v' Q0 m# R! ?. |9 P4 E: f
  37.                 printf ( "开始更新固件...\r\n" );
    5 K+ }6 s8 o; B/ c$ }1 q: k
  38.                 if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    1 k! Q( p; {+ `6 A3 P. z1 g
  39.                 {
    $ t. a3 E! L- A& v# O3 U
  40.                     iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码$ \& K0 R* s# g0 r5 @
  41. 2 @' \: i$ @$ f: `. ^, M
  42.                     printf ( "固件更新完成!\r\n" );8 a2 b0 h+ X. @, o' ]3 _  I4 Q
  43.                 }
    3 ~$ h/ W* V% f6 d
  44.                 else2 {" o3 @3 H- ~6 |! u2 ]9 W
  45.                 {2 S4 E7 D' \3 U9 v! m) I
  46.                     printf ( "非FLASH应用程序!\r\n" );  e5 D: n5 D2 h
  47.                 }
    8 \- g% c* D4 j/ h+ P
  48.             }( i; x3 h, h2 P. U" q  e
  49.             else
    ( y& m% ]" m: S+ N9 R$ K
  50.             {
    : ^2 X5 I, p7 z- {+ I
  51.                 printf ( "没有可以更新的固件!\r\n" );  _, c$ p' r* B; W( Y* `
  52.             }! F! y% I% w  W" F) |9 Q
  53.         }
    * S- e* U1 I6 g0 K- y, V
  54.         if ( key == KEY2_PRES )
    9 X/ j7 m' t0 |
  55.         {: a9 k5 _( J& Y; B
  56.             if ( applenth )# A; S  F+ m8 ^
  57.             {
    & R7 S7 e: E9 h2 T
  58.                 printf ( "固件清除完成!\r\n" );* V/ M" f) C0 ]; q7 j3 ~- J8 j
  59.                 applenth = 0;* p/ i! N2 w, s. u/ p7 o* Y" B. ]0 D
  60.             }
    3 \  K( R7 [" Q, g
  61.             else& V$ j; [9 k3 U$ W& J
  62.             {) J2 |1 Y4 T1 M: C* r1 I9 B' d
  63.                 printf ( "没有可以清除的固件!\r\n" );3 R* M* o# j- h9 \
  64.             }! J; A" r  N7 O- i+ E( r
  65.         }0 q# O: K5 @3 L( h# |
  66.         if ( key == KEY1_PRES )- ?1 l% y( ~4 {" Z9 I" S4 Q
  67.         {
    5 B9 F2 @/ K2 w1 k  i9 h0 l" i
  68.             printf ( "开始执行FLASH用户代码!!\r\n" );. Q6 {( ]) a: k/ l+ h
  69.             if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    2 Q1 S. N! V$ d* L1 g, V" ]
  70.             {
    # G3 S, q9 T+ @4 k; B; {
  71.                 iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    3 s4 r: Y4 Z9 n- m' x
  72.             }
    5 m$ S4 l0 _: @- i& q
  73.             else, p. j! m4 W2 l/ w+ T- }; M" Y' A
  74.             {, p" p, [4 z' A5 s2 e
  75.                 printf ( "非FLASH应用程序,无法执行!\r\n" );
    + I- y5 p! X9 W# d
  76.             }
    5 |3 B( T& d7 v3 n8 j% o1 K, M% m
  77.         }# W6 E& I; s- N% C) B* G
  78.     }
    3 n% _4 w; L* ]  I8 Y& R1 I
  79. }1 U/ b; w  g' E6 e: }' Q1 v+ v2 `% Q
复制代码

8 ?3 {# L. S# _7 t- U通过串口将接收到的数据存到SRAM中,然后通过按键将数据从SRAM复制到FLASH中,然后再通过按键选择从FLASH中启动。
# V+ t" ]/ S( H5 a( j( S3 z) U此处要注意设置数据在SRAM中的存储起始位置和在FLASH中的存储起始位置。
% Z& i9 r. V$ I9 h& {4 F+ p  j7 `6 a  B$ ]9 a3 A- L; d1 B
I2V@E8QCMLOSV(7T6V]YILU.png & H; z6 p/ J4 p: n) {& o1 h. F3 A% c
: ]3 v( s+ ^( U8 `
将串口接收缓冲区的起始位置设置为 SRAM中的0X20001000位置处,如果APP从SRAM中启动的话,那么这个位置也是程序开始运行的位置。* s' V& ^' r6 z- U# c0 B

0 O, O# v" A  s1 z) y; V# k" T2 T 99GGZ9$QDPO$(X7}`ZVL9HL.png
, R( S% `6 p1 c: ]( Q/ x* u& k" U0 a7 N' m
将FLASH中复位向量表的偏移位置设置为0x08005000,如果程序从FLASH中启动时,那么这个位置也是程序开始运行的位置。
- S7 I' c0 B6 w6 T5 U( J( i* O1 y! T) F( o6 P! @1 p
$N7170}2M@S@X[Y%~]3P]M7.png
" P% s4 c8 C9 L& x3 d, y# ?+ T: l) |7 [: L
1 f; l  w9 L2 l/ [" T下来设置bootloader程序存储地址  J6 ]$ U) u: i
# m' n* R* q( S% J, g: d
2DVY963GVFL7`GT]]SFEKSI.png # A% m+ f  k1 [1 H+ j" w0 ?) f
2 j% }( k( ?. x. q  t8 O6 k& c
bootloader程序运行开始位置设置为0x8000000开始,大小为20K,也就是说FLASH中前面20K位置存储bootloader代码,20k–64k位置存储APP代码。$ e7 S1 _& S  _5 Q

8 x) J* [2 ~: K1 T" M主程序中的代码比较简单,就是从串口接收数据,存储到SRAM中从0X20001000位置开始处,然后通过按键将程序拷贝到FLASH中从0x08005000位置开始处。然后通过按键选择设置程序从FLASH中0x08005000位置处开始执行。" @4 C3 E( Y' y1 H* g6 c
代码中有几处判断不太好理解,这里说说自己的理解。
+ }8 {0 @! L) x8 f/ P
3 N, Q" K, {2 e4 I* b6 N  A4 n KP2}G`QS1ZJBKJ_}NDWUC0Z.png
4 _: s1 A, Y2 _  k0 K' j$ R
6 L/ t0 c/ t; u' i* e. J0X20001000+4 是一个数字,前面加上一级指针 ( vu32* ) ( 0X20001000 + 4 )此时将这个数字变成了地址,也就是 0X20001004这个地址,然后前面再加上二级指针 ( * ( vu32* ) ( 0X20001000 + 4 ) 此时表示的是 取 0X20001004 这个地址中存储的数值。3 N% g/ Q& f+ Q/ u, n4 D* w2 q9 X
此时先看看内存分布图。
0 f$ X+ x6 Q, ^+ E. M. i. b
; L0 v9 p# p  S 6Y]3YU79[PF4XYIZPSXRZPO.png
* e: \8 ]0 [  t4 |
; j! g; p# B& O/ K2 n/ Z串口将程序存储到了0X20001000位置开始处,而程序开始执行时首先要复位向量表位置。也就是说0X20001004位置开始就是程序复位向量表的位置,那么这个位置存储的就是要跳转的地址。而所有程序执行都是从0x08000000位置处开始。
7 E" z9 t7 F- X5 q0 y9 ^也就是说如果0X20001004这个地址存储的数值时程序开始执行的起始地址,就说明APP程序在SRAM中存储完成了。下来就可以开始拷贝数据了。; g+ l) z. y0 O2 X" O

2 y/ H# o& J# s" O# s/ [7 n0 m ~H[3U(W(D4COBWQL86SZP1I.png # P1 `- X- D$ q& j4 C
) {& U' m9 ]; {
同理如果FLASH中存储代码开始位置+4处的值刚好是程序开始执行的地址,也就是说程序已经被拷贝到了FLASH中 FLASH中从_APP1_ADDR 位置开始处。
$ ?/ S$ t/ R8 P
: [0 C/ Q/ A* C通过对比内存中指定位置存储的数据,是不是程序复位后的起始地址,就可以判断出数据是否拷贝完成。
8 Q; s4 N! _0 S* z5 ^% @2 Q1 e下来在看第二种方法,通过串口发送指令来控制bin文件接收和APP运行。+ X, B: p$ `7 Z! V
8 k) M- r" H6 {
  1. int main ( void )
    2 \. C2 Q: `4 g2 }2 ?
  2. {, t/ O; g+ q* o/ P& I0 w
  3.     u16 oldcount = 0;                                //老的串口接收数据值
    & q0 H. R: T4 F: p: o' [5 p, s
  4.     u16 applenth = 0;                                //接收到的app代码长度
    + o0 |2 Y6 e  x; P
  5.         u16 app_bin = 0;8 _( r8 K- E! d* o! r# n( v) H. {- H
  6.         u16 app_enter = 0;, H* Q5 o: y+ R; M$ ~* ]1 j
  7.     SystemInit();
    6 ^0 P, P9 `& k4 s8 s& V
  8.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    7 u. T* N5 `4 f, Q; F9 w4 a
  9.     uart_init ( 115200 );        //串口初始化为115200
    , P: t- O/ ^: s) u
  10.     delay_init();                            //延时初始化
    - d+ A! _! F7 n% S1 h
  11.     while ( 1 )/ H. [* _0 c# X$ z
  12.     {
    $ q, ^' p" [+ o8 S, y* z
  13.                 //         首先判断app代码的首地址是否为0x0800 000,是则进入app,否的话进行引导区。
    * F) I8 e) u- t
  14.         if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.5 |1 M" J9 L* A* T
  15.         {" i/ r7 ~( a+ x  a# \! p# m, t
  16.             iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    & W& y2 w# H% \
  17.         }1 |, U: ]" n+ w" p2 t4 t. h5 X
  18.                 //   判断app代码栈顶是否为0x2000 000,不是则进入升级模式,代码如下,其中 FLASH_APP1_ADDR=0x8005000;4 r+ y9 n! _: E
  19.         if ( ( ( ( * ( vu32* ) FLASH_APP1_ADDR ) & 0x2FFE0000 ) != 0x20000000 ) )
      C- `1 i" m# K5 X) P8 l
  20.         {
    : {; H) R2 z' L/ d# [( q0 a
  21.             printf ( "/***** No APP! *****/ \r\n" );
    ( U  Q. [9 H) ~$ s" D8 y
  22.             printf ( "stm32f103c8t6在线升级  \r\n" );
    . L1 I& I1 G: R5 a
  23.             printf ( "选择对应的app bin文件 \r\n" );
    % _, y( C, l3 h3 L. Z! I$ ]
  24.             printf ( "输入 A 发送bin文件 \r\n" );
    ) ^1 D3 @7 R! g0 S5 {# Q" i. u
  25.             printf ( "输入 E 进入app \r\n" );
    5 m- N( b* Y! Y$ F) a  i7 Y/ g1 E
  26.             while ( 1 )$ K3 P% K! }9 ?
  27.             {
    , B; d0 z  ]/ f) |& F* o0 ^) B
  28.                 if ( USART_RX_CNT )7 F. N& K+ ^9 w+ K2 Z
  29.                 {
    7 X( ?* @$ ]: a' c, Z8 r! ^8 P
  30.                     if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.
    6 M+ L  K5 y$ ^: x( P1 Y$ z% |
  31.                     {
    / A; z! ]$ A5 S" q8 P" R
  32.                         applenth = USART_RX_CNT;% f) u2 F; v# m+ f
  33.                         oldcount = 0;6 u  }, w6 `, D4 e) i
  34.                         USART_RX_CNT = 0;
    ( Z% E/ p4 f* q8 u/ a/ @
  35.                         if ( applenth > 100 )( B8 f% O/ a; k( W7 Y0 M% W
  36.                         {
    ! D4 b2 X3 ?7 R- o
  37.                             printf ( "用户程序接收完成!\r\n" );
    # h$ w% P1 h9 J" c- ]. O9 t* d
  38.                             printf ( "代码长度:%dBytes\r\n", applenth );  z! _! P% ^5 p$ W! q; L8 t
  39.                         }
    ( G4 ]* I3 _  }6 C& F8 v/ ?
  40.                     }
    8 a! [+ G3 A' N2 L0 I& W; t
  41.                     else 3 C+ i( X: {3 f' X! H9 c
  42.                         oldcount = USART_RX_CNT;
    ( B+ \- o/ }- Y5 O' K4 F4 u
  43.                 }# E, r- Y- X) W- |" r( N" a. t
  44.                 delay_ms ( 10 );
    & X# a% u- y  J  ~, o

  45. 3 Z( F) P# T' T8 U9 `, a
  46.                 if ( USART_RX_BUF[0] == 'A' )
    ; P( q# r4 C% _
  47.                 {1 m" P9 G9 E3 h4 v# Y( }
  48.                     if ( applenth )
    + i; P( A. r# W- ~8 {, `
  49.                         printf ( "\r\n 请发送bin文件 \r\n" );; {8 B. \/ s# G8 i' s
  50.                     app_bin = 1;
    ' N- X: W0 [# D2 g. ~' u7 P1 f
  51.                     applenth = 0;. b+ `+ V3 k" [+ u4 e5 t
  52.                 }8 E" z/ h: r  G
  53.                 else if ( app_bin )
    ! C7 w5 b: d/ ~, J3 i2 h7 C
  54.                 {
    * ?1 g( I; q# |
  55.                     if ( applenth )* l* d& p' N# H0 H$ d% l
  56.                     {; F; A/ ~1 P2 O6 Y1 }
  57.                         printf ( "开始更新固件...\r\n" );+ ]1 r1 `, b( Z. ?& I
  58.                         printf ( "Copying APP2FLASH..." );- K2 Y5 B3 U$ t6 u1 T& R
  59.                                                 //此处 0X20001000 地址为串口缓冲区开始接收数据地址$ Q# G% O5 B% m1 e' J( G  `
  60.                         if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX. 串口是否接收到数据
    . k4 W$ ~: t7 c: K$ S% x
  61.                         {                         % y( w' I+ W4 K3 L
  62.                             iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码 ; _( [5 {2 t: N7 _8 `: f
  63.                             printf ( "Copy APP Successed!!" );: t: O( K% W2 s! k. n/ b
  64.                             printf ( "固件更新完成!\r\n" );; h# h" ~0 b. R* [3 I
  65.                             applenth = 0;6 h* t5 B4 X5 M. S9 }
  66.                             app_bin = 0;' a( f! u; A1 E) C& `% ^
  67.                         }
    ! r  E* k7 o  E$ A! w
  68.                     }
      T2 Y5 }' b  A1 Q- o' n) ^# Z  I, `0 P
  69.                 }
    ( x. \, e  ~! \; x6 D% v5 Q
  70.                 if ( USART_RX_BUF[0] == 'E' )
    - v( V: z! s' O- T/ m5 K. H; D
  71.                 {& }7 [- M& Q5 D. D9 i
  72.                     if ( applenth )
    - Z) t1 D* O$ e; l) G- z
  73.                         printf ( "\r\n 将要执行APP \r\n" );( k1 G$ ^8 V" P: C7 v  @: c
  74.                     app_enter = 1;1 }! j" G6 A$ U- W$ A8 W5 G
  75.                     applenth = 0;$ z" a( c7 I) Y9 B
  76.                 }
    7 B5 @8 d  ^. k% b9 z" K
  77.                 if ( app_enter )3 o4 V5 Y" L" x8 ]
  78.                 {
    . A5 e/ y- X, J8 d1 @: A5 I! f
  79.                     printf ( "开始执行FLASH用户代码!!\r\n" );
    6 `% c" |% A$ U7 h. [
  80.                     if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    7 O6 m/ \8 ?  ^( i
  81.                     {                       ( k$ Y% G1 r# P7 Z; z
  82.                         iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    5 v1 u4 S# b/ `' {% n# s
  83.                     }' O) w4 }) g8 u+ @$ U) [/ R+ Y
  84.                     else
    9 P. n/ j( s" Q6 k. x8 n
  85.                         {
      y. P+ e6 c# V# I# T
  86.                             printf ( "非FLASH应用程序,无法执行!\r\n" );' V: X4 q2 U' c+ b1 `  ~
  87.                             printf ( "Illegal FLASH APP!" );                            % h: V# n% E3 H! o* a. b2 y
  88.                         }$ X+ C/ G1 h) z
  89.                     }& k: q) K( w& ]3 I" F
  90.             }7 B( o3 U& r% I
  91.         }2 i7 t/ u# `  \# c3 E, w
  92.     }. D. p7 g% n2 b% m" V( g4 k% b
  93. }
复制代码
. a2 r2 p$ P  l2 ^) l% S
bootloader代码开始运行后,通过串口的指令来选择要执行什么动作,如果发送的是字符"A",那么就开始接收bin文件,然后将接收到的文件拷贝的FLASH中。如果发送的字符是"E",那么就开始从FLASH中运行程序。
/ R. l+ `' Z( A% S3 G3 v. }/ o' }0 {; I/ Z" C
下来在看第三种方法,自动判断串口是否接收到bin文件,如果接收到了文件就将bin文件拷贝到FLASH中,然后开始自动执行FLASH的中APP程序。
  1. int main ( void )6 G/ g7 j2 ]+ m( C; j
  2. {
    # x+ a6 e2 ~* I
  3.     u8 bit_new = 0;                                        //接收到程序标志3 Y0 c% @4 Z, F) t
  4.     u8 bit_10s = 0;& T- ^% H& \( s3 {" E. q8 L% \8 {* y
  5.     u16 oldcount = 0;                                //老的串口接收数据值) c6 ^! H/ g; p* C4 Z
  6.     u16 applenth = 0;                                //接收到的app代码长度
    - m- j" ^8 Q& a7 k' _1 Q* i
  7.     u8 t = 0, clearflag = 0;
    8 t) \4 d8 `2 @% d3 M

  8. + x! S8 {! e$ \; T
  9.     SystemInit();
    8 V" {; a" B+ k" q
  10.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    # {. h- l& ^1 M3 M& g3 h
  11.     uart_init ( 115200 );        //串口初始化为115200( r( |" _1 O( Y- s7 w9 U6 W% C
  12.     delay_init();                            //延时初始化9 h5 @, _8 `3 d4 n- `) z
  13.     while ( 1 )
    $ b$ ?; C- M1 |/ _0 Z( u5 F
  14.     {, Q: f, s$ t2 N$ `  c% E
  15.         if ( USART_RX_CNT )
    + r+ {! b2 p% S
  16.         {
    $ z+ u6 U! k" ]- x; w
  17.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.# @- u3 M$ ~* @+ t# y3 ~: q
  18.             {
    ' X" z' z; i  S) r$ x: q
  19.                 applenth = USART_RX_CNT;
    ) B$ |( `0 H. [: l! l6 r
  20.                 oldcount = 0;
    % |, ~/ K. W1 K( H' Y* _- h  R
  21.                 USART_RX_CNT = 0;) B- y$ h# b2 h$ h& G9 G( l
  22.                 printf ( "用户程序接收完成!\r\n" );
    - Z3 @, q- a( Z1 D5 Y( w
  23.                 printf ( "代码长度:%dBytes\r\n", applenth );" N: X. Y# p2 y# A+ |' u2 \
  24.             }9 H$ r; E  ]5 K& {' Q$ o! A
  25.             else oldcount = USART_RX_CNT;1 {! @- j8 w9 ?6 S0 {5 W
  26.         }
    / B  F- F9 K7 V- H2 i) Z  W
  27.         if ( applenth != 0 )1 h! }7 E# E. m) g8 ^
  28.         {
    & `" T7 [( T( O; O  e
  29.             if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.* T. X5 G7 k* w: C3 P7 ^$ H4 d
  30.             {
    # h; f: `. p+ {  \2 y8 |# D& G( |
  31.                 iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码$ p8 l1 p3 F( `$ T5 p
  32.                 printf ( "固件更新完成!\r\n" );' p8 A: H" q( x: K
  33.                 bit_new = 1;; b  B2 [7 v3 }9 f! ?
  34.             }3 K& G5 R, Y6 H4 U9 U- o
  35.             applenth = 0;
    : b5 [( @. e2 m* f& r: Y
  36.         }
    & ]7 i+ t: U# }% Z$ {3 z/ B
  37.         if ( ( bit_10s == 30 ) || ( bit_new == 1 ) )+ {# o9 f" W  ]
  38.         {
    8 _" i3 `) Z- s4 L/ I) w
  39.             bit_10s = 0;
    6 A  B" s. f# f$ l' R; a9 p
  40.             bit_new = 0;( m6 ]) ?; a; o
  41.             //执行FLASH中的代码
    ( o  h/ K9 \( E# ~& ?

  42. - {! U" d1 ^9 ]+ N
  43. //            if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.4 T  L( H$ f' y
  44. //            {& S7 o( `* i* J7 c) J; g6 K9 E
  45. //                printf ( "开始执行FLASH用户代码!!\r\n" );
    $ B5 l! T' T8 m" g& U
  46. //                iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码2 Y9 x8 Y5 K( O, M& s+ ]3 r
  47. //            }
      N0 ]- c' F: y7 S: e9 b( _
  48.             //执行SRAM中的代码
    * ~& n7 U  V# G# v+ q: \
  49.             if(((*(vu32 *)(0X20001000 + 4)) & 0xFF000000) == 0x20000000) //判断是否为0X20XXXXXX.
    : R7 J! Q  y4 b
  50.             {4 @+ G# P; h: d/ |8 W3 m
  51.                 printf("开始执行SRAM用户代码!!\r\n");
    / r0 _- T( u. C+ _: k; v& c1 {& k
  52.                 iap_load_app(0X20001000);//SRAM地址! B6 s/ ]3 S2 p& W0 D; ]* q
  53.             }
    # W5 @7 B  L6 |0 n4 P5 W
  54.         }
    ; Q0 [$ U/ B* i6 a/ D- _* C
  55.         t++;9 b/ {7 ~; ]8 p& P( l
  56.         delay_ms ( 10 );
    ; H5 L% P  \" Q3 @7 a  Z7 r' s6 ~
  57.         if ( t == 20 ). X+ E3 B) Z( }7 R* m
  58.         {9 b4 H0 A  H# p( T2 U
  59.             bit_10s++;           ! B+ w7 Q/ f& b
  60.         }
    " e9 `5 }( h% I4 A; i* K, j. v+ A
  61.     }, J2 B. `% Z) y
  62. }( R( c, V  o& P5 P) J
复制代码

; u' a+ \. l  T% q& k程序开始运行时,串口一直等待接收bin文件,如果收到了数据,就将数据拷贝到FLASH中,然后开始执行。如果未收到数据,等待一段时间后,自动从FLASH中或者SRAM中开始运行。这块可以自己设置程序在从FLASH中运行还是在SRAM中开始运行。% @8 `) p6 m' g0 \% q# B
% n6 b% {/ C! L1 [4 y: c' E
IAP升级主要是要搞清楚bootloader和app的地址范围,只要将地址设置正确,IAP功能编写起来还是比较简单的。; e# u$ }0 {( x8 P

& M: @* o# s4 g* M. b  V# G8 e2 h, l# z9 n# U3 G
, G  ^& E& c! F( L  l9 ?& o, |
赞 收藏 评论0 发布时间:2022-3-23 14:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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