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

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

[复制链接]
STMCU小助手 发布时间:2022-3-23 14:00
关于IAP升级的方法和原理,网上已经有很多资料了,这块就不再说了,现在就将bootloader和app配置方法整理如下:- x. \  r! T3 g7 x/ j
APP程序就是一个简单的LED闪烁。
( u$ M1 g1 M5 a& i$ k( WAPP设置为从FLASH中启动:
( m. o' x5 d9 w1 E  Z JCY{4{B3{IDHAO2FM}%JD.png
& N1 B" e* e/ ]0 }4 d# b' ~3 T+ U9 t0 I0 z
STM32F103C8T6单片机flash有64K,前20K空间留给bootloader,从20K之后开始存放APP程序。所以IROM1开始地址设置为 0x8005000,大小为20K。如果APP程序比较大的话,可以修改这个大小值。# T% _0 ^6 {. S+ Y" V- p( _
然后在程序开始位置设置重新映射复位向量表。让程序从0x8005000位置开始执行。
0 ~8 N9 |8 `* ~; DAPP设置为从SRAM中启动:
( F5 w  x* x0 b3 s( x" u9 a( I/ y& h3 a
]VQFOT(SZB7%@35IB(WSJ%S.png + ]* N1 Y/ ]& g  c6 l

7 r, U3 F/ O# \& h& p/ GAPP要从SRAM中运行,那么就要重新映射SRAM中的复位向量表。3 {0 m  Z: ~* @
由于在bootloader程序中设置的是接收数据代码存储从0x20001000位置开始。所以此处也要设置为程序直接从0x20001000位置处开始运行。如要要改变SRAM中的复位向量位置,那么必须要和bootloader代码同时修改,只修改其中一个的话,程序运行时可能会出错。
% E2 E9 E4 S/ f9 S6 f0 U2 h此处设置SRAM中起始位置为0x20001000,程序大小为10K,也就是0x2800。IRAM1的起始位置就是 0x20001000 + 0x2800 =0x20003800,大小为6k。刚好将STM32F103C8T6单片机的SRAM 20k空间分配完。由于STM32F103C8T6的SRAM空间比较小,所以设置APP从SRAM中启动时,APP代码不能太大。  Q9 B! O2 A  i& v1 d- N6 `( [

+ G: S) c- M0 w" HAPP代码要注意两个地方:一是程序开始时重新映射复位向量表起始位置。二是在选项中设置程序运行起始位置和空间大小。
: U. ^1 w# L+ x* |
+ Y% Y3 y+ v; |: k# e下来开始配置bootloader代码,通过按键来选择接收APP程序的bin文件,然后通过按键选择从flash中启动代码。: L- `1 F4 V! B5 u* X5 d4 l& O8 ^
* |7 S3 S; p# D4 A
  1. int main ( void )' ]. b* `+ d# c; `, `* ^
  2. {
    . Y# A0 l. V  A6 V! s9 j
  3.     u8 key;/ J4 X3 ~; Y+ Y* d1 X4 d( X
  4.     u16 oldcount = 0;                                //老的串口接收数据值
    / ~0 P7 W8 B2 E
  5.     u16 applenth = 0;                                //接收到的app代码长度
    $ B$ B6 X+ f; X  D! X& w
  6.     SystemInit();
    1 u# ?- q. J7 p) d6 Z. Q, _" g
  7.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    ' e& _# H1 R" L( k* t  @
  8.     uart_init ( 115200 );        //串口初始化为1152001 \! N6 r) Y: }1 p
  9.     delay_init();                            //延时初始化1 m% ]6 G2 e( U: J

  10. % l% q; E( G" E$ O6 n8 Q
  11.     LED_Init();                                          //初始化与LED连接的硬件接口
    0 l, d+ E; }5 Q4 v% F: k% t- W0 {
  12.     KEY_Init();                                        //初始化按键  ~  m6 O9 X! X

  13.   p% m! e1 y/ q# J" j5 [
  14.     while ( 1 )  Z! r+ w! |0 _" i
  15.     {$ ~9 S/ x6 e/ o$ v1 V" J# ~# x
  16.         GPIO_SetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高
    , ^7 H' m+ n# F; m+ p) i
  17.         delay_ms ( 1000 );9 T8 U, s: e6 x  D: |
  18.         GPIO_ResetBits ( GPIOC, GPIO_Pin_13 );                                                  //PE.5 输出高- v& T# E' T: |9 R8 D0 Z, C5 b
  19.         delay_ms ( 1000 );" k: V* C4 `; R( t
  20.         if ( USART_RX_CNT )
    ! R, w2 `4 U. I( T" G0 H& ~7 L4 h
  21.         {, t! v4 U9 ]. O
  22.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.' Q9 P0 h/ u' D8 r, E$ C1 t
  23.             {* \8 p5 a# S; u$ T  X( J. f
  24.                 applenth = USART_RX_CNT;
    . w2 `$ m' F$ A7 f
  25.                 oldcount = 0;
    : o- D& b* A( l
  26.                 USART_RX_CNT = 0;  Q# C+ T+ @5 T/ w
  27.                 printf ( "用户程序接收完成!\r\n" );1 H9 B; d/ j" _* L* b' y' T
  28.                 printf ( "代码长度:%dBytes\r\n", applenth );; r2 F, Z* x" [4 @! b0 X* P: V- M
  29.             }$ A/ M1 P( e: n' D
  30.             else oldcount = USART_RX_CNT;
    9 C- ]# p: A2 ?* E: f, o
  31.         }( _. ^  a; S, o1 n/ L0 \0 P7 ]8 D
  32.         key = KEY_Scan ( 0 );
    ) t' ^8 I+ ?. t) g7 c. }
  33.         if ( key == WKUP_PRES )6 \! Z: f6 z1 V1 ?3 r# Z
  34.         {
    8 F, j. Q5 \; u4 n
  35.             if ( applenth )
    . X# O% m" i( o7 [6 y! s$ d
  36.             {( S# E5 k6 S% i9 D/ y7 v
  37.                 printf ( "开始更新固件...\r\n" );+ F: n' o5 K- ]  n/ ]7 H
  38.                 if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.
    - X9 l0 H2 j' W5 n. D# ^) a
  39.                 {
    " r( E; N; O3 ^  D* J5 P
  40.                     iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码
    ! o# @, }6 H" `/ w2 {( A5 n
  41. 9 J! w: s6 R5 e! v3 v' C+ p
  42.                     printf ( "固件更新完成!\r\n" );
    3 H8 \/ y) ^( _( x
  43.                 }5 K% j! H7 \8 V" o* s1 D% B& S+ U* o
  44.                 else
    4 ]9 I9 a# |( w7 F& g
  45.                 {1 g- H5 w  _/ s. W% s6 d
  46.                     printf ( "非FLASH应用程序!\r\n" );
    5 d) d7 W+ R( Y
  47.                 }1 N9 c5 J! i5 U9 @( I
  48.             }
    # F" O2 Z, W, Y5 s9 O4 X6 L
  49.             else
    ( M2 `. e2 _  I( `- A0 G: a
  50.             {
    % I% U* @0 R; r/ C
  51.                 printf ( "没有可以更新的固件!\r\n" );% G5 ]( z) i5 [# |" Y, {) [4 G
  52.             }: @4 p* [, L) m. Z1 ?6 g) J
  53.         }
    & v; ?" |: ]6 T' {
  54.         if ( key == KEY2_PRES ). }+ p+ Y9 j' l. M7 k! Q4 S
  55.         {
    + c/ H& w9 ^' [
  56.             if ( applenth )0 t! ]2 u: A1 N. \/ q9 z' J$ }4 Z
  57.             {
    6 f. p0 _% @8 U, G
  58.                 printf ( "固件清除完成!\r\n" );0 s2 y7 ~* A$ \3 [( w0 r% F
  59.                 applenth = 0;: q; E- l9 F3 h/ P& b& ]2 O0 l6 R
  60.             }& m; c1 D% w+ n
  61.             else
    4 t1 i0 r9 E" U+ [& m
  62.             {5 g5 o9 O  @2 u: p1 M
  63.                 printf ( "没有可以清除的固件!\r\n" );2 C4 F* O, f3 {* d
  64.             }# ]8 P* P5 K1 v( |6 Z
  65.         }5 x; [6 h( ~" T, g+ d$ h: D( |( V
  66.         if ( key == KEY1_PRES )0 h; Y' y. n+ c* ?4 _
  67.         {$ {0 m- z" I) R8 }1 N6 g
  68.             printf ( "开始执行FLASH用户代码!!\r\n" );
    ; Y4 S7 n6 V1 L3 ^, O4 z( b
  69.             if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.0 d' f+ _9 I* L3 ]' w1 ]: X
  70.             {
    3 _; x' E2 {! ?# s
  71.                 iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码2 \6 b' E& F9 b
  72.             }
    : i1 M" C! s' }8 ^4 x
  73.             else1 _/ m% h  C  D3 W% S
  74.             {
    7 ~1 J6 h$ e/ n. u, r
  75.                 printf ( "非FLASH应用程序,无法执行!\r\n" );& e  v! _0 l) N8 k% W1 w' [
  76.             }7 Q9 P- I4 l  `- w, |% @
  77.         }
    : E& |0 F; y/ w8 Q
  78.     }9 B" E9 N# o( K4 Y. T& e/ h9 `
  79. }
    6 A7 C$ z) X6 u. ?( l' S" |
复制代码
+ ]4 n6 Q! C. o) o/ }
通过串口将接收到的数据存到SRAM中,然后通过按键将数据从SRAM复制到FLASH中,然后再通过按键选择从FLASH中启动。
; n8 _# A  `; Y5 g% k+ n1 Q此处要注意设置数据在SRAM中的存储起始位置和在FLASH中的存储起始位置。
  i6 s& V0 L. V8 }6 \& f: \% t& k) v2 X, u  B; e0 h9 b9 `4 S
I2V@E8QCMLOSV(7T6V]YILU.png
& L, O# [0 |8 C$ A7 @" f+ T
/ f4 \8 P! P! [( h/ `. i将串口接收缓冲区的起始位置设置为 SRAM中的0X20001000位置处,如果APP从SRAM中启动的话,那么这个位置也是程序开始运行的位置。
  F) P% b) V% ]8 x8 K
' B& D3 _' x5 a( ]% j5 |% N 99GGZ9$QDPO$(X7}`ZVL9HL.png
5 l, \- v. m( B9 o% M6 G# ~& _5 ]. Z4 w) K/ I" ]6 s
将FLASH中复位向量表的偏移位置设置为0x08005000,如果程序从FLASH中启动时,那么这个位置也是程序开始运行的位置。1 [: }! X  ^, p  W7 G, u% Z
" h, o4 R7 V, @* l8 d% o
$N7170}2M@S@X[Y%~]3P]M7.png
! G# u8 R8 `3 s& u7 y
5 F- J' x  W5 l& r* Y5 {7 T下来设置bootloader程序存储地址2 n7 y0 J0 b% {, S

) F( x: t$ F0 [4 V6 I8 ?+ P8 C 2DVY963GVFL7`GT]]SFEKSI.png - \+ x! E$ Z0 d2 y' A+ @, h  F
2 K; ?8 b. u9 o6 M
bootloader程序运行开始位置设置为0x8000000开始,大小为20K,也就是说FLASH中前面20K位置存储bootloader代码,20k–64k位置存储APP代码。
  V3 B9 x7 s8 ]) R' j: G2 |
+ f) t: H1 m; }7 \2 U7 x主程序中的代码比较简单,就是从串口接收数据,存储到SRAM中从0X20001000位置开始处,然后通过按键将程序拷贝到FLASH中从0x08005000位置开始处。然后通过按键选择设置程序从FLASH中0x08005000位置处开始执行。/ `: c: f' [# S7 {, @# n( X9 L2 @
代码中有几处判断不太好理解,这里说说自己的理解。
% {6 t3 t3 |# a6 @$ ^* ~. ^1 O1 T& o# o$ k0 U
KP2}G`QS1ZJBKJ_}NDWUC0Z.png 4 I7 f5 z1 R9 ^. l
. G' k9 W& G; M2 ~
0X20001000+4 是一个数字,前面加上一级指针 ( vu32* ) ( 0X20001000 + 4 )此时将这个数字变成了地址,也就是 0X20001004这个地址,然后前面再加上二级指针 ( * ( vu32* ) ( 0X20001000 + 4 ) 此时表示的是 取 0X20001004 这个地址中存储的数值。" L$ |2 x. Q. q
此时先看看内存分布图。
7 }) X' d5 h- l, F- Z. Q4 E2 q# Z+ X" o; }% A1 a  h
6Y]3YU79[PF4XYIZPSXRZPO.png . B( F6 H1 l3 V/ \

1 w! u) c7 g* U, ~串口将程序存储到了0X20001000位置开始处,而程序开始执行时首先要复位向量表位置。也就是说0X20001004位置开始就是程序复位向量表的位置,那么这个位置存储的就是要跳转的地址。而所有程序执行都是从0x08000000位置处开始。
; R  ^- {* `, ^6 Z5 w$ |也就是说如果0X20001004这个地址存储的数值时程序开始执行的起始地址,就说明APP程序在SRAM中存储完成了。下来就可以开始拷贝数据了。/ h( r1 Q% U6 E  f6 S& j: t
3 ~, s8 u2 r( Z/ H/ _- t: P" C
~H[3U(W(D4COBWQL86SZP1I.png
0 |2 o5 Z7 a) F0 y
' g) K8 a/ L: o同理如果FLASH中存储代码开始位置+4处的值刚好是程序开始执行的地址,也就是说程序已经被拷贝到了FLASH中 FLASH中从_APP1_ADDR 位置开始处。
7 ]' C& a9 \: S6 g6 g
! H  g6 u1 s& F. v9 ^通过对比内存中指定位置存储的数据,是不是程序复位后的起始地址,就可以判断出数据是否拷贝完成。9 I$ [  C9 K% X7 b
下来在看第二种方法,通过串口发送指令来控制bin文件接收和APP运行。
# I; z0 M- y. i5 i! j
6 e6 x2 H# I$ k, P
  1. int main ( void ): u: m# P4 K. @% f8 K
  2. {
    % V4 X! w8 S  K% ~5 p5 F1 r
  3.     u16 oldcount = 0;                                //老的串口接收数据值$ V% y* c9 O/ J/ @2 a5 X
  4.     u16 applenth = 0;                                //接收到的app代码长度2 u  Q/ E& y& a- W
  5.         u16 app_bin = 0;0 ^/ G# ]* o3 i
  6.         u16 app_enter = 0;; J$ d/ s+ b' [9 V
  7.     SystemInit();
    2 \/ [. u% [: L
  8.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    - r, ~" B9 V; y& Y. S: J
  9.     uart_init ( 115200 );        //串口初始化为115200
    * [, D4 X5 P, d8 l5 I
  10.     delay_init();                            //延时初始化+ l+ Z5 b( j" R1 @- Q' h
  11.     while ( 1 )
    0 n& X2 @; _  v: n6 o7 Q' Y' _+ u
  12.     {
    0 D+ H! g$ ]( L9 f0 M7 v8 W
  13.                 //         首先判断app代码的首地址是否为0x0800 000,是则进入app,否的话进行引导区。
    / s8 G+ Z/ [# U/ I$ O# P! C; h
  14.         if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.3 E: r2 q* b$ |. k& |" E
  15.         {
    ) @, m! N( X( b; }2 O) R
  16.             iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码1 s! l0 N5 d# A: X! Y) @: c# s
  17.         }
    " \4 k( V7 R$ C5 z+ g( {. M
  18.                 //   判断app代码栈顶是否为0x2000 000,不是则进入升级模式,代码如下,其中 FLASH_APP1_ADDR=0x8005000;
    8 v/ X. w9 ]" j- p
  19.         if ( ( ( ( * ( vu32* ) FLASH_APP1_ADDR ) & 0x2FFE0000 ) != 0x20000000 ) )
    7 k8 j6 u- C1 d
  20.         {
    ( n( X% k! T' a) p2 K
  21.             printf ( "/***** No APP! *****/ \r\n" );
    : Y: G0 ?! f. l. o4 w
  22.             printf ( "stm32f103c8t6在线升级  \r\n" );
    0 u# F8 i! m% g! X+ D
  23.             printf ( "选择对应的app bin文件 \r\n" );3 U+ j. C# o. E+ z2 q" v; Q
  24.             printf ( "输入 A 发送bin文件 \r\n" );9 Q3 \4 ~! I) p" S
  25.             printf ( "输入 E 进入app \r\n" );
    . Y! C: Q7 F+ p4 |
  26.             while ( 1 )
    ' M) ~& ]& w3 h5 h; u; J, ?/ W
  27.             {) H" T6 @) @6 y0 u, |7 @
  28.                 if ( USART_RX_CNT )
    % N( i3 c5 i7 }0 l( a: F
  29.                 {
    * @& Y; j& h' }; N" S6 C
  30.                     if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.
    / j7 Y! h6 S7 ~4 k) X
  31.                     {
      I9 G+ W3 H1 O; J! ^$ T, c
  32.                         applenth = USART_RX_CNT;! ^& R' U* ^2 g! X1 R
  33.                         oldcount = 0;
    0 f0 p' M; Z4 s2 k* r
  34.                         USART_RX_CNT = 0;
    4 V. ]1 R! u8 s/ M
  35.                         if ( applenth > 100 ): V0 @, |+ S' j! m
  36.                         {1 X1 V. L" y3 n1 P) R: N
  37.                             printf ( "用户程序接收完成!\r\n" );
    5 O& a$ t4 x( t1 ]
  38.                             printf ( "代码长度:%dBytes\r\n", applenth );
    4 q+ X7 k  U3 y; X4 a
  39.                         }
    3 @0 M# z2 n5 Y+ u8 m  b
  40.                     }1 z& M' T' x  @
  41.                     else
    * V7 ?, V& X3 `! @$ V! O$ k
  42.                         oldcount = USART_RX_CNT;
    9 X- _* v2 T; N  n* S
  43.                 }
    & [" O; M4 e2 H# G6 q7 A2 h+ I
  44.                 delay_ms ( 10 );+ H1 R3 r6 f/ U( _' G2 ^
  45. 3 j0 C9 K& l% {" P1 |" k
  46.                 if ( USART_RX_BUF[0] == 'A' )
    ( R- _  k& l3 G1 x% ]) W
  47.                 {2 T$ ^* {& V1 R! l
  48.                     if ( applenth )3 C; w5 n4 J( W
  49.                         printf ( "\r\n 请发送bin文件 \r\n" );
    5 _# J0 s8 B! }5 I
  50.                     app_bin = 1;
    7 @0 t4 |2 c2 V- f) {$ t6 H
  51.                     applenth = 0;
    5 g3 A; g" m* `5 N7 Z- ]2 l
  52.                 }
    & V7 X+ }% }3 }: }0 u$ `4 U
  53.                 else if ( app_bin )6 p2 p) B9 R+ d2 H" N: p) v7 c3 C
  54.                 {1 x" j& ~/ j: Q6 L- q
  55.                     if ( applenth )) ~" ^1 g% X1 A# M* T: w. x
  56.                     {, p; t; U# b; ]/ e( u& I5 [! P
  57.                         printf ( "开始更新固件...\r\n" );
    ! R' A- P. n" ~/ J7 M# U4 I2 g
  58.                         printf ( "Copying APP2FLASH..." );
    5 I9 z$ L( h. l# ]/ r
  59.                                                 //此处 0X20001000 地址为串口缓冲区开始接收数据地址
    6 o4 W4 A5 N' i9 z; P
  60.                         if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX. 串口是否接收到数据, H7 R" |4 X; M0 }3 B" w
  61.                         {                        
    + u6 F# I( p% g. Q2 `
  62.                             iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码
    : E7 J& P! g* H. i$ M
  63.                             printf ( "Copy APP Successed!!" );; h* `! s7 a  i1 v
  64.                             printf ( "固件更新完成!\r\n" );
    ( q' l7 i, g2 s; F* l
  65.                             applenth = 0;
    5 F( l; r" D% g7 v; W( r2 y/ y7 k
  66.                             app_bin = 0;
    $ C7 Z; }5 y& P6 I, s- Q
  67.                         }9 I* t5 E  K# f, _; G# s
  68.                     }9 T8 S& N! q; `) z! j
  69.                 }' E2 |" c8 \  U& K+ S$ v
  70.                 if ( USART_RX_BUF[0] == 'E' )
    4 {; R  i/ g2 s+ H. o; i8 {2 S
  71.                 {; ?% _* K: N5 t& T
  72.                     if ( applenth )/ x2 r8 k$ w% Y
  73.                         printf ( "\r\n 将要执行APP \r\n" );: V& ?# _8 q* K) L: ?" l
  74.                     app_enter = 1;! o5 y1 R: ?1 o; O! f$ ?! G8 r
  75.                     applenth = 0;
    ( z; c2 X0 j4 x1 O. _
  76.                 }
    1 p  U# [: L( v2 k% I) B9 \
  77.                 if ( app_enter )
    8 Q! l8 C; ?/ F! m, R
  78.                 {
    $ Z: G8 Q1 F1 y4 }+ X' D0 H" D, Y
  79.                     printf ( "开始执行FLASH用户代码!!\r\n" );2 u' u) D7 p4 r) |$ T2 D) s
  80.                     if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.3 ]8 k/ G& }( P+ j9 `( R  d) Q
  81.                     {                       
    * r; a% d- h. G0 }5 T" h
  82.                         iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码
    0 O- \" F. r) i0 x
  83.                     }9 K+ L* I8 j6 b) y. O
  84.                     else
    ) F9 F$ ?$ B& s5 i& x! e
  85.                         {
    & u" I" t5 ]5 [! S, ~
  86.                             printf ( "非FLASH应用程序,无法执行!\r\n" );
    ! y) H( M" T0 V) H, T$ j+ Z
  87.                             printf ( "Illegal FLASH APP!" );                           
    * \  w* }2 _% s
  88.                         }
    $ T+ X: \% q8 R# y8 j# y
  89.                     }
    / d3 h' t9 G* x: u" q; L  b( v
  90.             }
    9 s  R2 l- U: v7 Q' J$ H$ l
  91.         }
    * i7 q0 F# q3 A# i" S; F0 _
  92.     }
    " u5 [* p+ a; C9 V1 [5 S( A
  93. }
复制代码

2 z2 x2 }) M, y$ }bootloader代码开始运行后,通过串口的指令来选择要执行什么动作,如果发送的是字符"A",那么就开始接收bin文件,然后将接收到的文件拷贝的FLASH中。如果发送的字符是"E",那么就开始从FLASH中运行程序。- \  w! s. m$ G: \0 \
4 I/ P, H8 u$ [
下来在看第三种方法,自动判断串口是否接收到bin文件,如果接收到了文件就将bin文件拷贝到FLASH中,然后开始自动执行FLASH的中APP程序。
  1. int main ( void )' ~- W5 I5 |* o
  2. {( c" }. G! J9 I) C4 A0 @: U
  3.     u8 bit_new = 0;                                        //接收到程序标志) v9 S* r% k! ~1 x2 G: i6 J
  4.     u8 bit_10s = 0;
    4 ?2 i1 n4 o: P2 {# X+ h) ^1 Z
  5.     u16 oldcount = 0;                                //老的串口接收数据值4 F* [" _- X. c8 a& M  x8 \/ ^: H+ m
  6.     u16 applenth = 0;                                //接收到的app代码长度
    ' t" B& B; X3 S( s2 @1 s/ y! V' ]
  7.     u8 t = 0, clearflag = 0;* ]. @$ N3 u/ S8 |) g% J

  8. 6 C3 \$ F# I8 g( }9 o" F+ V
  9.     SystemInit();
    0 L4 I$ u  W% a
  10.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 ); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级$ p! _, V; q1 D
  11.     uart_init ( 115200 );        //串口初始化为115200
    2 B9 d6 u0 ^- e7 m8 U  a0 P' T
  12.     delay_init();                            //延时初始化* j6 ?8 K. e; n$ t+ |% X4 M- y9 j
  13.     while ( 1 )( `# _7 Z. b. e9 e6 V9 n
  14.     {
    ( A+ j8 p, g3 z
  15.         if ( USART_RX_CNT )
      J. ^; g+ R  u8 @  x5 _5 ^/ M
  16.         {
    % s7 B% W; ~5 _4 |" x" O7 `
  17.             if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.3 l6 @- u9 N- O1 j% z/ f" S
  18.             {  G/ N" v. P0 E
  19.                 applenth = USART_RX_CNT;
    0 t/ n4 |! F/ P* Q( h9 @
  20.                 oldcount = 0;8 U1 H/ W1 o1 l% }- @; u
  21.                 USART_RX_CNT = 0;  T' V; j6 N- u8 e; Y
  22.                 printf ( "用户程序接收完成!\r\n" );
    0 l1 s* X) F  [6 i9 w+ |
  23.                 printf ( "代码长度:%dBytes\r\n", applenth );" }# F4 W" V0 [2 s6 ]
  24.             }* `9 \3 ]' a8 g% W
  25.             else oldcount = USART_RX_CNT;2 A, p6 @" e' ~2 V, c  A4 o
  26.         }: C. T% l1 K" L' V- u# U
  27.         if ( applenth != 0 )! M5 P, A, ~3 f' y) }: z
  28.         {
    ( C/ o# Y1 i' e# W0 Z
  29.             if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.% B( G& c+ n; F8 R3 }+ L& c
  30.             {; y2 v% m7 {/ ~0 w$ b& Z
  31.                 iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码6 B. {3 B% b- L2 T, V
  32.                 printf ( "固件更新完成!\r\n" );
    8 ]( K5 R) c  p, C  I0 o& m
  33.                 bit_new = 1;, W+ A* c1 H' a+ v
  34.             }
    9 e3 _8 I5 x0 Q  p
  35.             applenth = 0;7 V" h3 N3 i: P# u& m3 f
  36.         }* N. c( l, {- b- g) ?
  37.         if ( ( bit_10s == 30 ) || ( bit_new == 1 ) )
    % }* w2 c2 }' h! P4 a' J
  38.         {  o! c& m5 U; g3 Y( |( T
  39.             bit_10s = 0;$ ?9 l6 a- h0 G  p6 I( {7 C
  40.             bit_new = 0;
    , @, Y8 u5 Y! |7 R4 O  D% B
  41.             //执行FLASH中的代码
    , h2 p9 _8 s- [  {2 ]

  42. 0 \5 W2 q0 K+ U) p7 R
  43. //            if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.: c0 U& V' u6 O2 f+ m. C
  44. //            {- e0 G* q+ D  s3 m: ^
  45. //                printf ( "开始执行FLASH用户代码!!\r\n" );
    & n9 b+ h% {3 L* H
  46. //                iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码4 \" p0 W7 r, h; `0 ?
  47. //            }6 `- z! w8 t6 Q
  48.             //执行SRAM中的代码
    7 s7 e5 N; ]0 e3 X, F5 S6 p
  49.             if(((*(vu32 *)(0X20001000 + 4)) & 0xFF000000) == 0x20000000) //判断是否为0X20XXXXXX.
    ; G' y7 A: D0 x6 E4 e3 w
  50.             {
    ) M/ F; p. ]5 D8 f9 I8 B
  51.                 printf("开始执行SRAM用户代码!!\r\n");
    0 j; u" U  _- L: q2 X
  52.                 iap_load_app(0X20001000);//SRAM地址% i( r8 I( r& ?9 L, Q
  53.             }* t6 h/ k+ \  f& f# e! G
  54.         }5 `1 p5 S; C8 j$ L3 }
  55.         t++;
    ) K; t) p3 E% |- z
  56.         delay_ms ( 10 );  E( d0 H& G, q
  57.         if ( t == 20 )
    & i& v7 y, I/ w) T/ a. w! e8 Q. v6 r
  58.         {
    2 t5 Z5 F! S1 e; O
  59.             bit_10s++;           
    * K, b/ b, r0 K9 l% W' h
  60.         }
    : x0 U! j7 g4 Y) W7 \
  61.     }+ j9 S: Z3 x6 Y: k4 ]9 J- S
  62. }& `5 [1 D& M' @7 N3 U, `
复制代码
% I3 m8 y0 V7 E' ?) k- [
程序开始运行时,串口一直等待接收bin文件,如果收到了数据,就将数据拷贝到FLASH中,然后开始执行。如果未收到数据,等待一段时间后,自动从FLASH中或者SRAM中开始运行。这块可以自己设置程序在从FLASH中运行还是在SRAM中开始运行。/ P$ |& L+ H9 \9 S1 d, \
, K, p! H' P* M8 R% O
IAP升级主要是要搞清楚bootloader和app的地址范围,只要将地址设置正确,IAP功能编写起来还是比较简单的。
1 H" p$ h/ Y9 Z1 a( m' F) W7 t/ M
( c5 x2 v( s. L3 Z7 V, M5 e
- Q6 ^, |& A: Q7 \' Y9 ]9 F$ a* s7 b4 R2 G' B! ~& C$ m3 m
收藏 评论0 发布时间:2022-3-23 14:00

举报

0个回答

所属标签

相似分享

官网相关资源

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