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

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

[复制链接]
STMCU小助手 发布时间:2022-3-23 14:00
关于IAP升级的方法和原理,网上已经有很多资料了,这块就不再说了,现在就将bootloader和app配置方法整理如下:
8 d* t7 W  a) w2 d3 T) K! u, P2 ?APP程序就是一个简单的LED闪烁。
% ?. V7 I- `% l' k+ }APP设置为从FLASH中启动:" [8 O9 x- t2 b- l. C, R5 ?/ N1 c4 G- O) t
JCY{4{B3{IDHAO2FM}%JD.png
' O' h# z7 X7 h& c% u' b# V% ]9 a7 c8 ]
STM32F103C8T6单片机flash有64K,前20K空间留给bootloader,从20K之后开始存放APP程序。所以IROM1开始地址设置为 0x8005000,大小为20K。如果APP程序比较大的话,可以修改这个大小值。. e; \2 ]  W" C
然后在程序开始位置设置重新映射复位向量表。让程序从0x8005000位置开始执行。
/ T- C0 n0 a5 n) N( zAPP设置为从SRAM中启动:% B3 n" ^" S/ V2 N! w8 K: C7 {9 s

0 |2 P1 |4 {" [8 ~+ p) y& M6 f7 w ]VQFOT(SZB7%@35IB(WSJ%S.png 2 H2 ]: Y1 D$ q. ~

1 }4 w% B1 g- B' n2 K0 x! Z$ uAPP要从SRAM中运行,那么就要重新映射SRAM中的复位向量表。
" T% u% A/ h( t- P# e3 @& ]由于在bootloader程序中设置的是接收数据代码存储从0x20001000位置开始。所以此处也要设置为程序直接从0x20001000位置处开始运行。如要要改变SRAM中的复位向量位置,那么必须要和bootloader代码同时修改,只修改其中一个的话,程序运行时可能会出错。- C3 q% m8 e9 m3 d4 V
此处设置SRAM中起始位置为0x20001000,程序大小为10K,也就是0x2800。IRAM1的起始位置就是 0x20001000 + 0x2800 =0x20003800,大小为6k。刚好将STM32F103C8T6单片机的SRAM 20k空间分配完。由于STM32F103C8T6的SRAM空间比较小,所以设置APP从SRAM中启动时,APP代码不能太大。+ `3 V/ q3 B! V/ {1 K9 f
, G" K1 D! N5 X' k" |9 v- }8 q# A
APP代码要注意两个地方:一是程序开始时重新映射复位向量表起始位置。二是在选项中设置程序运行起始位置和空间大小。
  x' I6 m- q* T
2 n, I4 L% Q6 ~. \+ N7 h下来开始配置bootloader代码,通过按键来选择接收APP程序的bin文件,然后通过按键选择从flash中启动代码。
3 s4 \4 ?3 v3 q9 m( c
4 S* L" u; g4 X) a$ M7 ]: [. z
  1. int main ( void )
    6 D0 F" Z, w3 k8 }' p+ K0 n
  2. {
    5 n6 |4 L: @2 B: k* D+ X% A- V
  3.     u8 key;+ T( h* J( g, h# t0 X9 l
  4.     u16 oldcount = 0;                                //老的串口接收数据值
    & U  a! T& l" Y, T/ A
  5.     u16 applenth = 0;                                //接收到的app代码长度
    & Q0 J4 Q3 n1 Z2 m+ e# B) i. f
  6.     SystemInit();
    / U! a) n2 o. X( E: E( y
  7.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    1 a; N& w, O' ~; C  {, ?
  8.     uart_init ( 115200 );        //串口初始化为115200
    2 A+ C& V6 b' k0 L; y
  9.     delay_init();                            //延时初始化& j* O% \% J  [* l) J9 d
  10. 1 ^! a- A2 S% e# O, n+ @1 @! q. V
  11.     LED_Init();                                          //初始化与LED连接的硬件接口9 m: h; S1 H4 R5 r% E5 [
  12.     KEY_Init();                                        //初始化按键
    ; |/ Z3 f; k1 v. o1 k8 O5 T

  13. " s& X4 e8 a$ Q9 y8 f. D" Z' w
  14.     while ( 1 )
    % X/ ^( r' I9 L3 y3 y$ ?
  15.     {8 Z. r4 A2 @7 P* h& Y
  16.         GPIO_SetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高
    , R( C+ t$ k6 `8 h1 X' [
  17.         delay_ms ( 1000 );0 r5 A" m- j3 ~$ [. I- A) K
  18.         GPIO_ResetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高, I6 k; m# p, j6 U1 ]9 q  f; G
  19.         delay_ms ( 1000 );
    % [1 I6 \: e; n7 [& c/ W! y! t
  20.         if ( USART_RX_CNT )
    6 u8 `0 E2 `9 h3 m3 p
  21.         {  X7 b) }0 E) t" G
  22.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.8 j9 j9 m+ W3 e) _$ u
  23.             {
    - @+ v" m( u+ _6 a0 E9 c
  24.                 applenth = USART_RX_CNT;' ?5 L$ r1 w  _; V0 |% Q
  25.                 oldcount = 0;
    0 E& B; I4 ?+ F/ S% H9 P
  26.                 USART_RX_CNT = 0;$ m. f3 [3 g" C% B1 y
  27.                 printf ( "用户程序接收完成!\r\n" );8 ]% s. b. M* y6 c2 f) [& g
  28.                 printf ( "代码长度:%dBytes\r\n", applenth );2 B# p$ Q5 l5 o0 i
  29.             }
    : g) J4 p* n0 P
  30.             else oldcount = USART_RX_CNT;* o9 C2 @3 j8 h
  31.         }
    ' g3 P, j. v# }  R: K
  32.         key = KEY_Scan ( 0 );, V4 k2 B7 Y: B4 b
  33.         if ( key == WKUP_PRES )8 f3 m; f; p) [+ j: Q
  34.         {
    ( y2 r) M+ ]( A
  35.             if ( applenth )
    1 n, u1 j/ W2 p; t: ?  j5 a
  36.             {; }$ D9 I7 L/ |
  37.                 printf ( "开始更新固件...\r\n" );
    8 I9 J! G6 D$ {0 M( I( v
  38.                 if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.6 R; ?2 m0 r; d% w' X
  39.                 {
    6 U" S' O) b' q% `0 v+ D3 k3 _
  40.                     iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码( {: K: D* S( _
  41. % c0 K: I/ |" Q. r  }
  42.                     printf ( "固件更新完成!\r\n" );
    8 ?1 o% k+ J$ S% p) S
  43.                 }4 q! I/ U# m, l6 ~
  44.                 else( r& m& W, s/ E2 @
  45.                 {
    : U" }$ f+ o5 F" \, a8 r, i
  46.                     printf ( "非FLASH应用程序!\r\n" );/ e( _" w5 m7 H( {
  47.                 }
    3 w0 R% Z$ @+ Z4 B. o) a6 E
  48.             }1 S9 a: ]! Y4 f+ h0 }$ x$ ]0 o# @* I
  49.             else! c  O- N2 J1 a* k1 J/ f1 {" M
  50.             {0 `& r; F; Z1 t7 u, c% B" M
  51.                 printf ( "没有可以更新的固件!\r\n" );
    ( H6 Y4 H. \/ w
  52.             }  y' N( p4 _- @) ~
  53.         }( v& R( u) i5 Z1 o
  54.         if ( key == KEY2_PRES )
    ; P2 D" M6 k- B% n, G' e5 ?
  55.         {3 L: d" ?) ^4 S6 R, P
  56.             if ( applenth )
    9 X* p) ~9 G$ x1 S7 }
  57.             {4 Z4 T( ?( |2 J8 d
  58.                 printf ( "固件清除完成!\r\n" );7 ]5 ~( A3 {- K$ m) k# b8 l0 M6 s' k% P/ q
  59.                 applenth = 0;. t& U" }  t& Q7 m. T
  60.             }
    & e6 u$ q% ?7 X
  61.             else2 r; O( m! y) S
  62.             {; v9 j! ?! q" u7 z- @
  63.                 printf ( "没有可以清除的固件!\r\n" );
    0 d5 U0 @9 h6 @* M0 U
  64.             }
    ! j2 X- Z( T& ?7 `
  65.         }% w- b6 r; R8 P' c( ^) o1 L
  66.         if ( key == KEY1_PRES )
    ) V+ B" C8 T+ B( x2 p% }4 U# a4 m
  67.         {4 {; d9 E5 f4 [" d# ~! W3 |
  68.             printf ( "开始执行FLASH用户代码!!\r\n" );4 `% n4 V2 V- a5 v0 b: u
  69.             if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.6 m8 I  X0 H% K. T# U* K3 H
  70.             {
    " M" H) t& a/ U' P5 `1 Y
  71.                 iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码$ U# I5 S1 g/ u6 m2 ?5 F
  72.             }" Z5 T+ f2 @1 b+ H9 G  i( Z
  73.             else5 S8 _/ X3 \. G. T: X" {
  74.             {
    * C4 }) G1 m! @0 H$ B  D1 v6 Q
  75.                 printf ( "非FLASH应用程序,无法执行!\r\n" );
    6 T: T$ n. j1 m% W& I
  76.             }
    * y/ w  L; P* J0 d$ n( ~) ]& S- o
  77.         }
    $ L3 v* ]* i" L# p7 `' M
  78.     }0 o! e( E& Y5 B9 n
  79. }4 ]  Q- F, S- \: ]
复制代码
# l- ~  b* z' O- P+ U
通过串口将接收到的数据存到SRAM中,然后通过按键将数据从SRAM复制到FLASH中,然后再通过按键选择从FLASH中启动。
- @/ f# ~, G2 G此处要注意设置数据在SRAM中的存储起始位置和在FLASH中的存储起始位置。; L$ b6 |, z  j# d$ l: _

3 Z& ~1 y6 z" k I2V@E8QCMLOSV(7T6V]YILU.png
$ {8 u9 b) z6 g$ @, g3 u$ N! {% c0 |4 C" m
将串口接收缓冲区的起始位置设置为 SRAM中的0X20001000位置处,如果APP从SRAM中启动的话,那么这个位置也是程序开始运行的位置。
/ i9 r. s; ^/ G" E7 t8 n+ \- B* p. a  U8 D4 [
99GGZ9$QDPO$(X7}`ZVL9HL.png
4 s% j6 z, x, ^  E" {
6 `; d! N1 E5 K/ Y) B将FLASH中复位向量表的偏移位置设置为0x08005000,如果程序从FLASH中启动时,那么这个位置也是程序开始运行的位置。
) C3 p( C, c7 e! m+ c6 `; W/ Z# f+ P4 \# p, D/ k
$N7170}2M@S@X[Y%~]3P]M7.png 6 F9 L, Q7 o' W

$ K5 ^% o  A/ _2 o1 B: f% r/ }下来设置bootloader程序存储地址
# ?$ B7 G, ?0 f5 `, y0 @
" _! B$ ?) ^9 |8 J1 R# o 2DVY963GVFL7`GT]]SFEKSI.png 8 }) N% y+ L+ O. b$ }* z

% e. y9 i7 J) B: {2 Obootloader程序运行开始位置设置为0x8000000开始,大小为20K,也就是说FLASH中前面20K位置存储bootloader代码,20k–64k位置存储APP代码。. j) Q; M! l* ]" I5 s* ?% f. h

3 e; i/ D3 i0 Q主程序中的代码比较简单,就是从串口接收数据,存储到SRAM中从0X20001000位置开始处,然后通过按键将程序拷贝到FLASH中从0x08005000位置开始处。然后通过按键选择设置程序从FLASH中0x08005000位置处开始执行。5 X* r+ Z- w% }" Z9 E" ^
代码中有几处判断不太好理解,这里说说自己的理解。
! ~9 q! m& c7 P/ B$ T* j0 e, {) }( C+ l0 @: `" _( P
KP2}G`QS1ZJBKJ_}NDWUC0Z.png + l& b5 t% v2 e* O

0 o$ o+ U( o- g5 d. q. R0X20001000+4 是一个数字,前面加上一级指针 ( vu32* ) ( 0X20001000 + 4 )此时将这个数字变成了地址,也就是 0X20001004这个地址,然后前面再加上二级指针 ( * ( vu32* ) ( 0X20001000 + 4 ) 此时表示的是 取 0X20001004 这个地址中存储的数值。2 E8 F0 ?; N. U8 v# B
此时先看看内存分布图。
# r! F7 W0 h! b9 i5 c6 J9 K4 N2 O0 g
6Y]3YU79[PF4XYIZPSXRZPO.png $ @* @6 }! C3 l+ F! {# ^- f" o/ }
# H; E3 F3 E6 r$ W& ]
串口将程序存储到了0X20001000位置开始处,而程序开始执行时首先要复位向量表位置。也就是说0X20001004位置开始就是程序复位向量表的位置,那么这个位置存储的就是要跳转的地址。而所有程序执行都是从0x08000000位置处开始。
. K) N/ X+ U& C0 C+ M/ `也就是说如果0X20001004这个地址存储的数值时程序开始执行的起始地址,就说明APP程序在SRAM中存储完成了。下来就可以开始拷贝数据了。; V  T8 P: {  J  u6 Q) _
5 U# V) d3 k& h6 L
~H[3U(W(D4COBWQL86SZP1I.png " M( p' C/ y) H/ X5 g
! n* X: v5 N: C. j6 n1 v
同理如果FLASH中存储代码开始位置+4处的值刚好是程序开始执行的地址,也就是说程序已经被拷贝到了FLASH中 FLASH中从_APP1_ADDR 位置开始处。  G4 H, }  ?' n5 `, r
4 i. ^& a9 o" ^$ C3 ~0 _/ l
通过对比内存中指定位置存储的数据,是不是程序复位后的起始地址,就可以判断出数据是否拷贝完成。
& O$ u& L; O' w! j6 h8 J. n下来在看第二种方法,通过串口发送指令来控制bin文件接收和APP运行。
, B( q5 S$ A0 w" P" g9 m/ i1 x1 I7 O! G; G
  1. int main ( void )
    & V8 s; A) }7 n* w
  2. {4 S: @0 G+ |9 R& E, X# F
  3.     u16 oldcount = 0;                                //老的串口接收数据值$ Z+ R, y" b- P8 U  u3 ^- l" @
  4.     u16 applenth = 0;                                //接收到的app代码长度9 J7 _" P5 l1 P9 I- B
  5.         u16 app_bin = 0;/ v$ ]4 r0 j# L; h
  6.         u16 app_enter = 0;& ]  J/ K! n2 f9 L! Y% t2 g
  7.     SystemInit();# w/ c) d' T' i: r, L
  8.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    ) O/ P8 \/ m) E! _% f
  9.     uart_init ( 115200 );        //串口初始化为115200( Y( ?7 W7 M5 n) V) {) d9 x5 @
  10.     delay_init();                            //延时初始化9 i$ W7 i5 |# ~& D( A9 T( {* p
  11.     while ( 1 )2 r) o% f* {# e3 n4 n8 {  A& y
  12.     {$ b, }2 \# |% E* A# `' s# W2 G
  13.                 //         首先判断app代码的首地址是否为0x0800 000,是则进入app,否的话进行引导区。" v' `, S! W4 v
  14.         if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    % c" W; U9 R) N5 ^
  15.         {
    4 r+ _% j  ~& S3 a4 b5 Q
  16.             iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    2 W: h7 R+ J& w  y* F
  17.         }
    * h) [* K. _* d9 X# |' V
  18.                 //   判断app代码栈顶是否为0x2000 000,不是则进入升级模式,代码如下,其中 FLASH_APP1_ADDR=0x8005000;
    ; q/ h1 M' s& z; m" s$ U& F+ i
  19.         if ( ( ( ( * ( vu32* ) FLASH_APP1_ADDR ) & 0x2FFE0000 ) != 0x20000000 ) )
    ! e; d( Z! T" U$ n
  20.         {% Q' j0 r; F4 s$ T" J; [& C4 o
  21.             printf ( "/***** No APP! *****/ \r\n" );
    ) \2 K* @2 Y* x- c
  22.             printf ( "stm32f103c8t6在线升级  \r\n" );
    + W( W! g) {7 n# D9 D; ~
  23.             printf ( "选择对应的app bin文件 \r\n" );
    $ r$ m' p9 u  N. y4 o- v: a8 F
  24.             printf ( "输入 A 发送bin文件 \r\n" );
    ; u! s, H7 i& }& ]& @/ |- }
  25.             printf ( "输入 E 进入app \r\n" );. L  B  ~3 ^* C) G: i7 S
  26.             while ( 1 ); z+ Z( p* ~  g; O: U
  27.             {% A  A, A6 ?# r+ u' r
  28.                 if ( USART_RX_CNT ): l% S; F& M; j; Y' H
  29.                 {/ n$ \& d- S! Z8 H6 L2 J+ E) }  i
  30.                     if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.
    " `! w) w( m  W& P" O
  31.                     {$ ?6 J2 A7 b+ d$ v
  32.                         applenth = USART_RX_CNT;6 s! k3 U" r- c. l& X
  33.                         oldcount = 0;
    1 @; [$ u; p. f2 z4 N. P, j* \1 [( H7 Q3 c
  34.                         USART_RX_CNT = 0;: x; l1 A  x$ V
  35.                         if ( applenth > 100 )) Y1 Q8 K# j& z
  36.                         {0 z% q$ r0 l& D* C3 H. ^
  37.                             printf ( "用户程序接收完成!\r\n" );
    & X; }9 k  r8 e5 ~! @2 p
  38.                             printf ( "代码长度:%dBytes\r\n", applenth );. o1 s( y: F% G% b0 S# x3 h  D
  39.                         }# b" v. f2 a  w) O) J# x
  40.                     }
    3 ^2 |  @% O8 `9 U3 ^
  41.                     else % g) l; f1 A) a4 R# y; ~
  42.                         oldcount = USART_RX_CNT;1 z7 B. s6 l" [" a* L
  43.                 }
    " U' Z7 E5 m- k$ v# o
  44.                 delay_ms ( 10 );
    ' v4 u, p- j1 t  A
  45. * W7 D  g5 A# b8 S% M- q$ ~% ]
  46.                 if ( USART_RX_BUF[0] == 'A' )
    5 z9 \; y4 r- @
  47.                 {
    % ]! x" L# G: V3 Q" I6 c& ?: g" U0 J: [
  48.                     if ( applenth )3 w9 [, I! p3 @: V
  49.                         printf ( "\r\n 请发送bin文件 \r\n" );
    $ W- i+ Z% m5 M% g% U  t; c
  50.                     app_bin = 1;
    ; K+ {+ ]2 \4 Z: k6 i/ n
  51.                     applenth = 0;
    9 R  j! x. @5 F$ {
  52.                 }
    $ `. O) i, k2 B; c' R. h
  53.                 else if ( app_bin )
    " u4 }0 J, e' \1 j9 h
  54.                 {9 N2 G  T& M7 T0 d; V
  55.                     if ( applenth )
    ' y9 O8 r( s5 d0 k/ |9 [
  56.                     {+ |+ P" T* j& ~/ V7 k$ s1 f
  57.                         printf ( "开始更新固件...\r\n" );8 A/ \* S2 T1 o
  58.                         printf ( "Copying APP2FLASH..." );/ o$ r" M* Q2 W$ J) t6 E& I: l9 p
  59.                                                 //此处 0X20001000 地址为串口缓冲区开始接收数据地址
    + g2 ]$ U# S7 _( u8 d! y2 R' e
  60.                         if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX. 串口是否接收到数据
    4 J9 K* I. }* E( a
  61.                         {                        
    + ~, G: O5 X7 y# H( @
  62.                             iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码
    , g/ m- S! X, n/ N
  63.                             printf ( "Copy APP Successed!!" );
    ; P8 O. i/ {# e& S6 z( g3 [
  64.                             printf ( "固件更新完成!\r\n" );
    % l" O3 Y. T2 ~  Q5 }" w+ @
  65.                             applenth = 0;9 t" T, X/ L" c5 D8 W- F2 O
  66.                             app_bin = 0;
    ' V/ O& Q! F6 ]" z% U: H
  67.                         }
    7 h2 Q# J8 ]5 L2 i% i
  68.                     }
    % |; c( M6 `* s
  69.                 }
    ) c/ n: N# D: D. f; ]
  70.                 if ( USART_RX_BUF[0] == 'E' ): ]1 v$ q5 W0 }! h
  71.                 {7 r% c6 t3 a9 [9 k. W
  72.                     if ( applenth )
    2 u2 s( @4 [( F% p
  73.                         printf ( "\r\n 将要执行APP \r\n" );( o( c, `. A# Y7 {) Z
  74.                     app_enter = 1;5 \9 S* k4 i+ a- x3 o3 G3 G
  75.                     applenth = 0;' P+ O9 {5 _3 S) t  W8 H$ E$ D
  76.                 }
    . B# q" A( \1 Y  P  O
  77.                 if ( app_enter )
    ; X1 O. t0 T' m+ n8 ]7 W% p# u
  78.                 {
    6 l$ c; ^/ w( E( K
  79.                     printf ( "开始执行FLASH用户代码!!\r\n" );3 z+ O& x8 v; \6 u- Y& I
  80.                     if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    3 ?2 S& h! ~- J1 C  D
  81.                     {                       
    3 W9 h- I  j1 X" |- @' q
  82.                         iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码% ?( m! Q7 R+ d4 `4 {
  83.                     }
    , m; }* h! @2 P8 @( u
  84.                     else 1 _6 C+ V( W3 }; J& C2 w
  85.                         {5 h4 L" V. C6 A4 `& E0 {! i0 j; j# |' B
  86.                             printf ( "非FLASH应用程序,无法执行!\r\n" );1 P5 z8 [- h8 ~. q- j
  87.                             printf ( "Illegal FLASH APP!" );                           
      A3 h& D7 G0 q' d& b  ?
  88.                         }
    : v# K9 i; t7 ~' t5 Y
  89.                     }
    * g8 r7 M5 U# e6 q$ n
  90.             }. ]  U2 {0 M8 B9 P
  91.         }& z: w9 I) b- {& i/ \9 l, m
  92.     }" F# }3 z9 z& ^0 A6 S
  93. }
复制代码

& R8 U, ^5 R* E- r; b# Abootloader代码开始运行后,通过串口的指令来选择要执行什么动作,如果发送的是字符"A",那么就开始接收bin文件,然后将接收到的文件拷贝的FLASH中。如果发送的字符是"E",那么就开始从FLASH中运行程序。
: {: E4 Z/ K" h1 }, H8 B+ {# U  F' Q. R0 J9 F" {
下来在看第三种方法,自动判断串口是否接收到bin文件,如果接收到了文件就将bin文件拷贝到FLASH中,然后开始自动执行FLASH的中APP程序。
  1. int main ( void )
    ! E1 O% w. U. O1 S5 s+ A: c6 o
  2. {
    " w$ V  o& g7 s( b: `3 f: r
  3.     u8 bit_new = 0;                                        //接收到程序标志
    # ]6 e. _  b3 K- t
  4.     u8 bit_10s = 0;4 |) L8 S) M' B5 M6 P# F
  5.     u16 oldcount = 0;                                //老的串口接收数据值
    . s7 c* Y: E# r0 O" E/ u+ s
  6.     u16 applenth = 0;                                //接收到的app代码长度2 @+ a- V( i/ y; }
  7.     u8 t = 0, clearflag = 0;
    7 J% m: ^6 a0 _+ @& g
  8. " H* X) r2 [4 S5 n3 f# t- D5 s5 y1 k
  9.     SystemInit();
    2 `! H; w, l1 `) L( d0 q# [
  10.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    3 [0 G: x4 X% u( E
  11.     uart_init ( 115200 );        //串口初始化为115200
    1 ~+ s: O0 E. a4 w* a2 ?9 O5 m
  12.     delay_init();                            //延时初始化
    * a# j. L" c7 ~# k# n9 a& G/ o
  13.     while ( 1 )
    : ~5 u( J* ]2 _. U0 T
  14.     {. e7 d; K& w  `5 R9 U4 [9 _
  15.         if ( USART_RX_CNT )
    . q2 n; V- q. X
  16.         {8 R0 R9 j# H% N/ Z
  17.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.& ?, h6 i; j5 s* `* S' u  r
  18.             {
    $ Y, X2 [1 B- a4 `1 a
  19.                 applenth = USART_RX_CNT;( x$ a. d5 h8 B4 ~! G$ X! b6 u
  20.                 oldcount = 0;+ c. }2 w: T+ B% U1 X, M. w1 O
  21.                 USART_RX_CNT = 0;
    - S5 R9 f: ~$ g
  22.                 printf ( "用户程序接收完成!\r\n" );
    ) q  |1 Q( C# I1 p5 W0 P  A  a
  23.                 printf ( "代码长度:%dBytes\r\n", applenth );5 \* m5 k  O2 ]4 U/ [6 _
  24.             }4 `3 e: o5 y; R
  25.             else oldcount = USART_RX_CNT;
    0 B. m9 x2 c1 L6 M0 B% w% C
  26.         }8 H4 q; g" n- A0 `
  27.         if ( applenth != 0 )
    ' i1 p& {/ T0 T
  28.         {
    ) g/ s6 g) J3 n5 ~, E% A
  29.             if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.% ^4 S! W0 e# H, p0 \  w
  30.             {
    % M  _" x) j* J9 ^" u2 l" L
  31.                 iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码6 I1 E% u, x0 L$ _/ }% F6 u
  32.                 printf ( "固件更新完成!\r\n" );" O* i; e" I1 W
  33.                 bit_new = 1;3 \) k' T+ @9 B. U7 w& X! `3 t
  34.             }
    7 Z8 k& I, N6 K. v1 C) V' w
  35.             applenth = 0;
    ( Z/ I+ X4 U1 o
  36.         }1 }; u/ h% a0 p6 F# X6 G( k
  37.         if ( ( bit_10s == 30 ) || ( bit_new == 1 ) )  X" l/ ?: }" `7 l
  38.         {
    3 Q" M) m7 i4 {
  39.             bit_10s = 0;
    2 r. \2 [$ S0 {6 S3 Y
  40.             bit_new = 0;
    ' u, ?: V- q5 ]1 R) ~' u9 _1 T9 _
  41.             //执行FLASH中的代码7 }/ a. Y$ ]0 R3 F+ D4 }, R* y1 D$ q

  42. / R: J9 m5 a$ B4 c: k. w' S! C" u
  43. //            if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.  b3 C5 ^3 T0 T- o
  44. //            {
    ; v( ?( C# J% j6 K, }4 l% |
  45. //                printf ( "开始执行FLASH用户代码!!\r\n" );
    ) ^1 F, f) B5 e) t3 j, E
  46. //                iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    . H4 E5 V0 x  _9 Z/ k0 V' P
  47. //            }
    & J' q. f+ P: U& f
  48.             //执行SRAM中的代码
    4 O8 J1 R' d4 d5 P3 R6 z' ]! U8 l: ]/ G
  49.             if(((*(vu32 *)(0X20001000 + 4)) & 0xFF000000) == 0x20000000) //判断是否为0X20XXXXXX.
    $ q0 _0 d" c" L/ n- F. |% Z" C
  50.             {1 X) |! ~3 F2 e) T: w4 d* G  l+ O
  51.                 printf("开始执行SRAM用户代码!!\r\n");
    : I' k0 z4 y: P1 O
  52.                 iap_load_app(0X20001000);//SRAM地址
    - M0 ~" i, ^. k5 u! s3 b
  53.             }
    4 q" b  b( L0 f" C. J
  54.         }
    , ^+ h  r  @$ [# M& r7 j  S' t
  55.         t++;; U+ ~6 s, q! \1 a' `$ {7 [3 W
  56.         delay_ms ( 10 );7 x9 B5 Y* \% M3 J4 h
  57.         if ( t == 20 )
    3 O. ~2 s, X5 d; h9 H
  58.         {' {5 J6 b1 p* m- p* x7 V2 W5 E/ ]: X
  59.             bit_10s++;           ( E- t! o( o4 _" d$ X9 ]
  60.         }
    * k, W9 o% B) F
  61.     }7 U1 q8 y/ d4 _
  62. }* l% M5 A4 P. d
复制代码

& a/ \* |3 y' L" ~: g4 H程序开始运行时,串口一直等待接收bin文件,如果收到了数据,就将数据拷贝到FLASH中,然后开始执行。如果未收到数据,等待一段时间后,自动从FLASH中或者SRAM中开始运行。这块可以自己设置程序在从FLASH中运行还是在SRAM中开始运行。
6 X  |0 e- a+ I& O
" N0 f- \. c8 }" W7 i/ z- QIAP升级主要是要搞清楚bootloader和app的地址范围,只要将地址设置正确,IAP功能编写起来还是比较简单的。
- A! P4 ~& b$ D4 O
3 g$ V* V) k( A
# M3 E/ O5 _" j3 Z$ r5 J+ N$ c) z! M; B& }- h$ N
收藏 评论0 发布时间:2022-3-23 14:00

举报

0个回答

所属标签

相似分享

官网相关资源

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