IAP介绍 IAP(In Application Programming)即在应用编程,IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。通常实现 IAP 功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如 USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在 User Flash 中,当芯片上电后,首先是第一个项目代码开始运行。4 K1 k) q0 C% t4 T8 v
简单来说,就是程序首先运行在boot升级区,检测是否有升级程序,当有升级程序的时候,用户将升级的固件通过某种通信接口(如串口)传输到开发板的某个位置中,之后放在APP的位置。当没有升级程序,直接运行APP中的程序。
; a6 L* a- g* V" s j, c 功能设计将最新的产品固件通过串口上传到开发板中,按下按键1,开发板将固件更新到设置的功能程序存放地址,按下按键2,执行功能程序。 $ t" M. O0 y, ]; ~- v; w+ k
# _) L4 X" N. {/ r" ?* X" ?& c
2 L# W( l& }# ~" f硬件设计使用的MCU为STM32F103
' m$ ^9 }( }! P4 e# Q0 e使用元器件为两个按键和两个LED灯 6 x2 t/ }9 N3 A o8 q+ t; L
软件设计软件设计流程如下具体实现
$ y6 ~( d; X7 z8 c% R8 @设计功能程序主要为两处: 在main()函数中最开始处,添加 ( ~" k6 N! [% f5 l1 i! l" v3 R
' a9 [ m0 {# |- SCB->VTOR = FLASH_BASE|0x9C00;
复制代码
8 I3 _9 C2 x* y' q2.在keil 5中Target的程序的Flash起始地址和大小
& ^. |0 k1 W9 ]6 H' U
3 a8 `! e% ~+ p, ^+ c8 d
生成bin文件:我们通过在 MDK 点击 Options for Target→User 选项卡,在 After Build/Rebuild 栏,( I6 j7 |9 d! I$ u( N+ e
勾选 Run #1,并写入:D:\32\Keil 5\ARM\ARMCC\bin\fromelf.exe --bin -o …\OBJ\LED.bin …\OBJ\LED.axf
' s, s( w& \$ L8 P0 ]) t4 v
7 Z" q ^3 H0 B R9 }' B ?编译后,就会生成.bin文件了。 * B6 {) Z( H9 y8 ^0 Y9 _- A
IAP实现程序IAP写入程序
- u; u" o; R3 I9 Z o2 `: t将暂存在RAM中的程序存放到Flash的对应地址中
* ]3 D# X: z$ i' n8 M! uappxaddr:应用程序的起始地址
) p5 `' f7 v8 M) O- |appbuf:应用程序CODE.# V7 z" C; x C, H( L; ^9 S% f, ^, a! L
appsize:应用程序大小(字节). - void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
4 i3 _- U C8 I - {
4 r) _4 r4 Y4 n9 V& u* j G - u16 t;
. }7 ]4 z$ b7 z' W - u16 i=0;' `0 B9 i' T/ P, Y3 P
- u16 temp; i/ k8 _! K5 r
- u32 fwaddr=appxaddr;//当前写入的地址
0 k0 a+ k, V5 X8 p* R+ ~ - u8 *dfu=appbuf;6 ]2 l* {' w7 c+ T
- for(t=0;t<appsize;t+=2)
$ t7 @) o3 o" _& S" S - { / \# E3 R' n. o, X W0 m. `
- temp=(u16)dfu[1]<<8;9 ]6 X8 ?- F! z- d4 h
- temp+=(u16)dfu[0]; ; W3 \- G+ V- R' R1 O9 d4 K) m
- dfu+=2;//偏移2个字节
9 |. x( \; A/ M- E - iapbuf[i++]=temp; & X; P$ {% {! Z: j
- if(i==1024)
+ ~6 U1 o) \5 S8 y" W - {
! ?. K& q3 ~; h( P - i=0;
' @" F- O B4 e4 |. v - STMFLASH_Write(fwaddr,iapbuf,1024);
) P" k! M& E/ f. [5 ~ - fwaddr+=2048;//偏移2048 16=2*8.所以要乘以2.5 s- Z" {$ P$ T' _# b6 @
- }
0 I' k3 X6 W) h A- o; t - }
4 I b( Z: u9 V4 C3 s4 `! V - if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去. + J% J8 D" z ` ~" j! Z1 K
- }
复制代码
2 S/ g; Q& h4 D3 _/ A 2.运行地址偏移程序 y2 q/ ?; V2 E3 N
程序转移到指定地址运行
9 H! H0 t3 i# l) n: N+ r跳转到应用程序段7 T; _2 s5 ^ @6 \" o- @ ]
appxaddr:用户代码起始地址.
. b! ^' k: A) a- void iap_load_app(u32 appxaddr)
% z* U! b" @# s- j+ z1 n - {7 ?8 R- j6 ]1 |, s* Z* ?
- if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
1 T7 T9 x+ G; v6 s/ x' q - { 0 g) u5 o. ?. Q0 Q+ |+ V2 n; e- @
- jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址) ! l+ w% m, ~* _, d% L* c; M1 n6 w
- MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
6 t k& I, C o7 m5 s - jump2app(); //跳转到APP.$ b( L5 Z, y" {# m! q! d/ \
- }- q! m3 ?7 f+ [% K7 L4 X/ ~ G! j
- }
复制代码
4 |+ T/ O; g: V# q& _1 }! h9 s+ r
1 q1 n0 |1 P, k( `, ~* U/ g6 D2 N d9 o3 b6 @3 x/ Y
主程序通过按键对接收到的升级程序进行更新,或者直接转入到功能程序地址。 - while(1)) N F# r1 m& B: z1 [% }
- {9 G9 u+ x$ N9 K- E9 `
- if(USART_RX_CNT)
) ~8 L1 J5 B8 Z8 A+ R9 e" ^ M: P. d - {
6 M3 M; S. E+ D7 Q; k. E4 j - if(oldcount==USART_RX_CNT)
: K3 T) b+ i2 O# w - {
# ?% h( j' r! Q - applenth=USART_RX_CNT;- }0 T8 k* s# b9 \
- oldcount=0;: G- D+ C. A5 L2 r3 D0 I
- USART_RX_CNT=0;
" {% {# R- e9 z1 _; t; l - printf("代码长度:%dBytes\r\n",applenth);% e* J S: e/ L$ X
- }else oldcount=USART_RX_CNT;
; N9 I9 j0 e, o - }
5 a. I h$ y- ?) G& m( O/ j2 X - if(key==WKUP_PRES)7 T2 m6 ?% c* ^) Y
- {+ U- |) u8 @* X- j5 m3 j9 T
- if(applenth)
. w% o0 j! U2 l7 S/ }) K# D - {5 o- i) ^( `/ M3 e7 ~/ L" L
- printf("开始更新固件...\r\n"); ' P5 K; Q# {/ O/ H' [, P' m" z
- if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
a. K) g' K: |: z0 X9 s- v5 y - {
3 h) O- z7 x+ U - iap_write_appbin(FLASH_APP2_ADDR,USART_RX_BUF,applenth);//更新FLASH代码 3 E# ]2 V% @# P) \$ p
- printf("固件更新完成!\r\n"); . s$ [/ W/ o( D
- }else
0 H ?! N4 P4 G: D - {
6 L+ D: H* }' v; h& I; R8 j2 s$ r - printf("固件更新失败!\r\n");& T2 ^6 H. j" C
-
0 K. n) }% W* ~5 l/ q& S) Z - }( q9 o# Y' V3 V$ o. R7 i# R) k
- }else
& o P" y9 _1 U/ F% h6 g: X4 L - {* `+ n% j) k+ J4 e! T
- printf("没有可以更新的固件!\r\n");
. t2 p4 q/ ~1 o: G0 H) D - }
( s9 q. c2 l% Z - } 7 W7 Y7 i7 P, l4 H
- if(key==KEY1_PRES)# ]- Q8 [5 `) E" ~
- {
3 Y: R& @8 e6 j: y, l3 z% y4 P - printf("开始执行FLASH用户代码!!\r\n");
; j, v8 E" _% X - if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.0 R5 z- f D3 F9 e. B
- {
9 o D: N# T( P K2 i3 _ - iap_load_app(FLASH_APP2_ADDR);//执行FLASH APP代码: k& Z6 u' X$ H- y. H
- }else
& Z. |" X% x5 Y - {& h* Y% U3 N! d( P
- printf("非FLASH应用程序,无法执行!\r\n");
8 I: H* l: z/ R$ v# E - } % P; x, {7 f- O* c: N @) ?
- } 6 Y; t- ?5 `" ~% ~2 c
- }
复制代码转载自: 跋扈洋 6 ^% L0 E! R4 q1 h
|