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

STM32F072使用SD卡进行IAP升级  

[复制链接]
zhumx 发布时间:2017-9-15 17:31
本帖最后由 黑色裂变 于 2017-9-18 09:22 编辑
8 t4 d7 ]6 L3 M" V- D4 p" `' _7 u) M
之前做的一个小项目,因为刚开始没有考虑到以后会经常升级,而每次升级都要旋开4颗螺丝拆壳,然后烧程序,再装壳,如果只要更新几个倒没啥感觉,但是一下更新几百个,那工作量。。。。,正好板子上有SD卡,就想着写个Bootloader程序,通过读取SD卡中的Bin文件进行IAP升级,这样可以大大简化以后的升级。IAP升级原理就不多说了,网上相关的资料和帖子一大堆,这里简单介绍我做的IAP方案,欢迎大家批评指正!
& t9 ?) d; Z  y- p; E+ v- E: |, ~
Bootloader程序设计$ ^6 p" z; W) Y! ?, B
bootloader程序的设计思路很简单,流程图如下:
. ~, ]7 K0 O8 U! g* d/ V. G
" f) H# G/ Q& L$ b1 H8 q
6 S% J5 _! ?0 f) u6 A
初始化程序就不介绍了,比较简单。主要介绍下Bin文件检测以及IAP过程。我将IAP过程分为5个步骤,如下:
+ z, ~, ?6 T* N2 ?2 {3 kStep1:检查是否存在升级文件,若存在,打开后跳至Step2,若不存在或者打开失败,跳至Step53 V) o5 h% B# r$ @" g) i
Step2:擦除App程序对应的扇区,擦除成功后跳至Step3,若擦除失败,跳至Step5
# I. t5 s" }' K( B9 `Step3:使用f_read()函数读取Bin文件,每次读取2048个字节,并写入Flash。当文件全部被写入flash后跳至Step4,若中间出现写入错误,跳至Step5
+ P$ h6 H& d5 f; G% O. d1 k5 i% A2 k& sStep4:检查栈顶地址,跳转至App程序。若栈顶地址非法,跳至Step5
* J; E$ U. u) |2 G' @. jStep5:此步表示本次升级失败,死循环,同时LED提示升级失败,等待重新上电8 R: W& H! z1 p5 @. q$ E
查找升级文件时我固定从Update文件夹查找,所以只要将Bin文件拷贝至Update文件夹就行了。
! j6 q/ [& e0 r8 ?4 s/ f, [五个步骤的转换是通过switch函数实现的。代码如下:
1 M( o" ]4 i* [5 r' j7 W
  1.         while(1)  \+ _7 Z8 ?+ }# q+ F/ X% K
  2.         {
    4 f! M$ n7 {' P2 t3 Y3 V5 }) h
  3.             switch(iap_step)
    6 [( c& j7 C: h2 X  U! R
  4.             {
    # G2 R. o8 u7 ^4 y7 _- z
  5.                 /* Step1:检查是否存在升级文件 */
    + \9 ~7 P3 ^0 b' ?
  6.                 case 1:, j! Z6 e3 G1 z* B
  7.                 {; k1 x% o$ e, S3 B
  8.                     /* 查找升级文件 */" t* e9 v+ z3 c+ R2 f
  9.                     result = f_findfirst(&dj, &fno, "0:/Update", "FDR_update*.bin");" }/ j0 Z7 L( W' j
  10.                     
    ! m* ]; q7 ]/ W% [& s
  11.                     /* 存在升级文件 */; f. ]) U4 M# u! V" `) p, b4 @
  12.                     if(result==FR_OK && fno.fname[0])
    4 T8 }) ^9 i& S1 U
  13.                     {6 N4 @$ e! o+ o! V& h; ?8 b
  14.                         /* 获取文件名字符串 */$ a1 H+ E+ K* B) P, Y8 p
  15.                     #if _USE_LFN$ E; t$ A8 M- b9 a. L
  16.                         fn_str = *fno.lfname ? fno.lfname : fno.fname;/ x3 w( Q3 J  u  S' T& F: O/ S
  17.                     #else/ R+ J" u$ e4 T) d
  18.                         fn_str = fno.fname;; G* S( {8 T2 U, c2 [9 x- [
  19.                     #endif ! v# Q" \) g- I" W' i& K
  20.                         /* 得到完整的文件名路径 */
    6 N& o7 s- Y+ _' K
  21.                         sprintf(fname_path,"/Update/%s",fn_str);   ( f- n2 C9 G" E- Y4 p) O2 q
  22.                         
    & R! n" k, T, q  b1 z
  23.                         /* 打开升级文件 */: ^. ?( G) w0 f, D0 i! _5 k
  24.                         result = f_open(&file_fdr,fname_path,FA_OPEN_EXISTING|FA_READ);+ z" y& L$ S5 X; t4 R
  25.                        
    1 h* O7 c* K* B- O& j8 T2 \
  26.                         if(result==FR_OK)
    , ~9 D8 ^* ?3 P1 j. ^+ r! r: V
  27.                         {' Z6 `' m( V- D* `
  28.                             /* 打开成功,准备升级 */
    + W" N% J  m9 j6 p
  29.                             iap_step = 2;4 o) W) J$ Y! u; O  `/ D
  30.                         }
    & D8 P6 i- }: k% @7 K3 }
  31.                         else  r6 g7 Q  \" Q. j- v* v* M
  32.                         {
    ; Q6 O: {2 U- {. \  Y/ K
  33.                             /* 打开失败 */; Q+ Y* r# F2 Y5 |( F3 h3 n" @
  34.                             f_close(&file_fdr);/ c6 v- B! M6 `% ^7 c
  35.                             f_closedir(&dj);* `3 |; k$ F9 b4 z( E8 q
  36.                             iap_step = 5;
    / e+ F( m5 {9 q( O( O
  37.                         }
    " T: _* l; @+ T* p: N+ l
  38.                         ) u# c5 R: H: I0 _( M& k9 Y# K, {
  39.                     }
    2 ?* Q; S' ^6 U2 H2 ^3 b
  40.                     else
    - z9 R/ {+ j' I% x7 L6 N3 N( j) i4 S
  41.                     {
    6 g' [5 G5 o  O$ ^5 m4 V/ B
  42.                         $ ~3 M* O8 Y& f( r3 j7 L- B; ~5 z% T
  43.                         /* 不存在升级文件,直接跳转 */6 {. L- e9 d! \( B' x+ E
  44.                         f_closedir(&dj);& R) c5 U8 |2 |
  45.                         iap_step = 4;
    ' f$ T' q  H0 x
  46.                         . x9 o8 g- F+ g
  47.                     }
    / @1 {7 v$ q( k/ B( y, S& U
  48.                     break;
    2 o) f3 i& w% x7 I
  49.                 }
    $ N0 E+ ~" A+ _% i
  50.                 4 v* H6 F6 V. e/ Z) z
  51.                 /* Step2:存在升级文件,先擦除扇区 */7 f: r1 \# ~! F
  52.                 case 2:5 P6 v! x$ s& O3 O! e+ u
  53.                 {5 u1 _4 J. D4 v9 ?0 j
  54.                     FLASH_Unlock();) z9 @$ W+ z, N# {) Z4 U
  55.                     res = IAP_FLASH_Erase(APPLICATION_ADDRESS);
    + K% H, R9 i/ t
  56.                     FLASH_Lock();
    7 B% s& \! Z; [& S, w7 r0 L8 W
  57.                     if( res )
    . |0 Y7 a; F. [
  58.                     {$ `& b* V  F$ @6 r0 O
  59.                         iap_step = 3;5 a; g: }3 m: L% L& [% D/ H6 W
  60.                     }
    : _; t& V6 j1 t. d
  61.                     else+ G7 j: q6 d; ^" ]6 p. P% \
  62.                     {6 f* Z5 c% [5 t9 c
  63.                         f_close(&file_fdr);
    6 d! i: J  [+ z  }1 k% m
  64.                         f_closedir(&dj);& z8 }; g8 ?5 b+ d/ z
  65.                         iap_step = 5;/ U* V1 W0 C6 Z% X; @) G& k' \
  66.                     }+ m' B; b" ]! \
  67.                     break;  K' C9 s2 n) d: Z2 F
  68.                 }8 f* r- B8 b; u' _: ~
  69.                 ) G$ _  \  S6 ^; {* p/ S+ s% f
  70.                 /* Step3:扇区擦除成功,准备依次读取并写入 */7 d0 X& O5 Y0 a+ Q6 N. _
  71.                 case 3:
    5 Z' `. Y- k* ~! s) @1 [
  72.                 {# v1 U( Y1 l" n, o' H
  73.                     memset(appbuf,0xFF,2052);) G6 P& H5 k3 n; a
  74.                     f_read(&file_fdr,appbuf,2048,&br);" K0 H' D. x1 e
  75.                     5 `! r3 z6 A" F+ i: m7 U
  76.                     FLASH_Unlock();0 I' e8 k, }) @- W
  77.                     ( _* T6 c: P6 a9 l/ n) c/ S
  78.                     res = IAP_FLASH_Write((u32*)appbuf,(u16)ceil(br/4.0f));" Y1 O6 Y& y  |' L9 I' f; K, ?
  79.                     ' ]) M* E' T7 d6 f
  80.                     FLASH_Lock();
    ) @. F! T# i* H% D8 m* C# C' \
  81.                     5 z" o0 p7 X  V# c4 x% d8 z: g
  82.                     Toggle_LED_AP();
    ' T3 h5 l3 x" V/ e4 v
  83.                     
    9 p3 l! K) k. R3 J- C) U) V
  84.                     if(res == 0)" n8 s5 U: ~* r9 A2 p$ [; i
  85.                     {
    , |' c, p/ I1 x
  86.                         f_close(&file_fdr);
    ) D' a: i2 k& f' a) x+ l
  87.                         f_closedir(&dj);" S- C1 f2 K. ]0 ?+ N! f
  88.                         iap_step = 5;
    1 s$ L3 j. A% h
  89.                         ' L1 a) z# W& y/ u  D
  90.                     }
    $ b; h8 {8 F5 p1 m, I. i
  91.                     else1 ^. a8 n* @8 s  z/ ~
  92.                     {3 ]" A" F4 j. O0 |$ y
  93.                         /* 文件读完了 */
    . x. N$ t0 A( h7 n! b1 I0 u# S% y8 j
  94.                         if(br<2048)) b# J% a' z7 u( L! [. |  ?
  95.                         {( ~, Q; C' a, v" N
  96.                             f_close(&file_fdr);+ k7 d% o! m) {3 r" y" W9 i
  97.                             f_closedir(&dj);
    ) \! d0 N' C# X+ U- W
  98.                             f_unlink(fname_path);6 `. O( Y1 L0 ^0 p& x. c4 ^
  99.                             iap_step = 4;   
    3 g1 _! u# e  T3 k
  100.                            
    * G1 A6 W" v5 o/ Y
  101.                         }6 g- S- s* ^: y7 O* q( M
  102.                         : c3 E$ I+ G4 n0 L
  103.                     }
    0 ]* h+ x4 y& _0 m7 @
  104.                     break;
    , `, w. I4 _4 D
  105.                 }  z1 t9 b9 U) g$ T
  106.                
    + U8 s8 g% u. Z2 Z( \
  107.                 /* Step4:跳转至App程序 */
    * [8 V* K% ?3 a0 k
  108.                 case 4:* d. ?7 t2 A4 c
  109.                 {  - K6 L9 U+ {1 s+ i+ [
  110.                     /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
    ; V8 s: _) h1 J* p, K: M5 G
  111.                     if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)8 M3 K) c; _; i8 d4 k, H2 k
  112.                     {
    - V9 O: d4 r/ D  s! \
  113.                         /* Jump to user application */
    ( w0 _; k: w* d  p5 U8 s; x
  114.                         JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);  r# [( t+ M' r1 b
  115.                         Jump_To_Application = (pFunction) JumpAddress;5 Y6 m2 J* B! C2 |: h. |" E" ^( o
  116.                         
    $ [( j: v' d- _# U( c
  117.                         /* Initialize user application's Stack Pointer */
    : N* [7 Z6 |$ b: v+ A
  118.                         __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
    8 h) o: T# a& R( V1 ^7 H) Z5 W+ P4 L
  119.                         4 Y' l/ y3 U& t$ d3 [
  120.                         /* Jump to application */
    & q0 L2 j  U7 z) b, v
  121.                         Jump_To_Application();, d+ V9 D, ^! O1 K) Z
  122.                     }
    * X  D% U" U9 Z0 p5 p
  123.                     else4 i; X# \/ S! I" V, A& q
  124.                     {
    / O5 [' j, T" o; w, ^
  125.                         iap_step = 5;
    : g5 b9 E$ ^* o2 f+ W7 \
  126.                     }( s% y/ T. H; d" I- T/ k  P
  127.                     2 A" Z/ x3 q  a; v/ t& f
  128.                     break;
    % d2 i: v8 w) J5 B# e% g4 @% _( s
  129.                 }3 w1 s# M1 y& g  C; V% n* P
  130.                
    8 B) v# [  B- U4 I8 u: `3 w! M2 X
  131.                 /* Step5:升级失败,等待重新上电 */
    ! S+ T/ \2 [; r) @1 k( w
  132.                 case 5:, n' b1 W1 L3 v  \! g% m
  133.                 {
    # N7 p1 L4 h8 _, s7 k% Y: S
  134.                     if(GetFreqFlag(FREQ_0_5HZ))
    ' ?8 B% E; x5 @
  135.                     {4 D) n* p' ?. k- x$ _. b4 G
  136.                         Toggle_LED_AP();
    , j  d3 }3 p/ D( f& H1 G: w; n
  137.                     }1 ^" t4 {8 Y( x7 Y& x9 {8 J
  138.                     break;1 t- }+ ]! e- p7 o0 l( s
  139.                 }
    & v5 o5 `$ X9 K! u  c4 g
  140.                 ! ?  U% u: N/ S
  141.                 default:& q3 d3 K" f( v! o6 z# y
  142.                 {4 k) F1 H- R5 P
  143.                     iap_step = 1;: y' y* L$ Y' d& R6 j
  144.                     break;) Z" C9 F6 W9 J7 h7 o- m$ A3 h1 G
  145.                 }
    & c3 T6 d) M. ?+ B" @5 ?0 i
  146.                 ) y# J7 F. \! `/ ~
  147.                 3 x+ J) F7 u! P
  148.             }//iap step switch! Z6 L2 `4 P/ `7 c6 o. C
  149.             
    5 l/ y6 d/ O5 _  C" [' V+ T/ _
  150.         }//end of bootloader while(1)
复制代码
特别要注意形参uint16_t Datalength是指的字数,就是uint32_t类型变量的数量,而f_read读取的是字节数,要除以4进行转换,刚开始就是没有转换导致写的flash数据不正常,跳转后死机。
! m& Z0 c$ _/ ?' Z. a  T跳转程序也是参考的官方例程。我设置的App程序起始地址为:0x0800 A000

- B& x0 }; l5 `1 P1 H此外bootloader程序的IAR工程配置如图,flash地址范围:0x0800 0000 - 0x0800 9FFF,占用40K
8 O  V3 d0 L! G/ Q: `8 N4 M1 i

$ v$ {# d% y3 W2 j& L3 V* LApp程序设计5 [7 S* y% ?% r3 C
1、App程序主要在原来的程序基础上修改flash起始和结束地址,以及中断向量偏移。Flash地址范围我设为:0x0800 A000 – 0x0801 FFFF,占用88K,IAR配置如下:7 c- k' a" D8 {/ I) m
+ B6 Y  V9 o9 \8 ^9 Y

1 l: J2 j1 R/ K; p) m* [: a/ `; Q6 \
! j2 W$ M5 d) [- r6 P

% z7 x0 A6 }$ \! c& c3 Q  f; N" C% @7 U3 O- `- _
2、由于STM32F0没有像F1,F4那样的中断向量偏移寄存器,需要通过进行内存地址映射来实现,具体实现原理参见http://www.51hei.com/bbs/dpj-40938-1.html! f& j- v( G4 o  F$ T
所以在App程序main函数开始的地方加如下代码:(参考官方例程修改)

app设置

app设置
2 e% m6 ^& J% ?1 `' k$ J! \
其实在官方例程中为 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);这并没有打开系统配置时钟,应该改为RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);我也是看到网上其他帖子才发现并改正过来的,在这里感谢网友们的分享!, n1 v' p9 F4 H% }" C0 m! J% s
以上就是我做的STM32F0的IAP升级方案,实际测试感觉速度很快,可能我的App程序不大,50K左右,升级过程基本在3秒以内。: m/ u9 [9 U4 S! N6 b+ m( f* _

  L2 C9 K; h2 g* H+ Q; b( f3 f; L' @1 s
8 b% X$ k4 V" p' p
6 n6 I" W) F6 c

评分

参与人数 1 ST金币 +10 收起 理由
MrJiu + 10 很给力!

查看全部评分

赞 收藏 9 评论17 发布时间:2017-9-15 17:31

举报

17个回答
zhumx 回答时间:2017-9-18 09:23:26
MrJiu 发表于 2017-9-16 09:23
6 ]% ?- G4 \& G4 Q3 B不过,支持一个!!!

* P1 e7 _3 ]" C# s, z谢谢版主,发现少了一幅图,重新编辑上传了
zhumx 回答时间:2017-9-18 17:59:53
ts2000 发表于 2017-9-18 15:57
0 i- K8 v9 ]) l0 Y" ~$ W8 E做过类似的,顶一下楼主~

0 Q" y. e' y( o1 \9 L谢谢
包子不 回答时间:2017-11-30 15:04:15
谢谢分享,很实用的教程。
yongjun 回答时间:2017-9-16 07:58:09
支持一下
MrJiu 回答时间:2017-9-16 09:23:03
不过,支持一个!!!
小小超 回答时间:2017-9-18 15:57:27
做过类似的,顶一下楼主~
epochal 回答时间:2017-9-18 20:40:54
谢谢分享!
搬砖工 回答时间:2017-9-20 15:00:10
谢谢分享
Lxiao 回答时间:2017-10-14 15:33:42
; y) k/ q7 B& B" \% P& _: p
谢谢分享,支持一下!
网络孤客 回答时间:2017-10-15 13:48:05
谢谢分享,很实用的教程。
jamesliutao 回答时间:2017-10-17 14:04:45
zhao.zhao 回答时间:2017-10-24 11:10:07
谢谢分享
zhukm1988 回答时间:2017-11-9 09:57:46
谢谢分享,支持..
xmshao 回答时间:2017-11-9 17:29:03
谢谢分享!
anny 回答时间:2017-11-29 16:07:49
多谢分享
12下一页

所属标签

相似技术帖

官网相关资源

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