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

STM32F072使用SD卡进行IAP升级  

[复制链接]
zhumx 发布时间:2017-9-15 17:31
本帖最后由 黑色裂变 于 2017-9-18 09:22 编辑
7 Q8 R5 m+ G" U$ `9 T
' V  q2 O, X- ?( q7 d5 w: H之前做的一个小项目,因为刚开始没有考虑到以后会经常升级,而每次升级都要旋开4颗螺丝拆壳,然后烧程序,再装壳,如果只要更新几个倒没啥感觉,但是一下更新几百个,那工作量。。。。,正好板子上有SD卡,就想着写个Bootloader程序,通过读取SD卡中的Bin文件进行IAP升级,这样可以大大简化以后的升级。IAP升级原理就不多说了,网上相关的资料和帖子一大堆,这里简单介绍我做的IAP方案,欢迎大家批评指正!
/ f! u9 l: C' v! R7 f" `5 l
Bootloader程序设计# f" R* ^7 r3 b. |7 {
bootloader程序的设计思路很简单,流程图如下:6 y, g! T7 t# C+ a( ^( S. g
% Y7 O1 r* _4 i! ~6 k- Y, W

- P% n3 Q: K0 a7 \
初始化程序就不介绍了,比较简单。主要介绍下Bin文件检测以及IAP过程。我将IAP过程分为5个步骤,如下:5 E, C! L  I% L- N! p# V$ i4 z
Step1:检查是否存在升级文件,若存在,打开后跳至Step2,若不存在或者打开失败,跳至Step5
& `3 i) G# ]- _! d( ]3 PStep2:擦除App程序对应的扇区,擦除成功后跳至Step3,若擦除失败,跳至Step5, V$ h' k  E& P+ l: I4 a# J
Step3:使用f_read()函数读取Bin文件,每次读取2048个字节,并写入Flash。当文件全部被写入flash后跳至Step4,若中间出现写入错误,跳至Step5
5 w4 y( g2 @" A* q3 PStep4:检查栈顶地址,跳转至App程序。若栈顶地址非法,跳至Step5
4 \# t" T) W: e' Z- Q+ b8 [$ KStep5:此步表示本次升级失败,死循环,同时LED提示升级失败,等待重新上电
3 i$ Z2 Q0 b% u7 v9 A9 l3 h6 {查找升级文件时我固定从Update文件夹查找,所以只要将Bin文件拷贝至Update文件夹就行了。
& R# r2 g- A- `- ?+ T9 b5 L五个步骤的转换是通过switch函数实现的。代码如下:0 J8 _% l# x0 @) x
  1.         while(1)1 f$ R9 r) C( d/ n' n
  2.         {
    1 \7 m* l( a. `" L" K( @
  3.             switch(iap_step)8 L1 X* o: D+ J- z' C/ ~. w& x
  4.             {- p3 j% f5 h' e$ Q1 {* B8 K
  5.                 /* Step1:检查是否存在升级文件 */1 J' ~# A" R9 ?9 f2 y% |% u3 R
  6.                 case 1:
    4 ?9 Y; j" O; \  ^% J: I
  7.                 {
    ' j" E# q8 f& L4 m% M7 S
  8.                     /* 查找升级文件 */
    5 F' X3 z% @( A: \3 i4 B; L' W) b
  9.                     result = f_findfirst(&dj, &fno, "0:/Update", "FDR_update*.bin");
    ; D1 o& c7 N3 c  e
  10.                     % _* i, b, f# x, J0 v4 [: ?
  11.                     /* 存在升级文件 */; [9 n9 h! q# h3 k
  12.                     if(result==FR_OK && fno.fname[0])3 ?" l4 m2 k& D0 a( _8 U, d
  13.                     {9 _5 v1 X8 i5 m+ I2 g3 ?
  14.                         /* 获取文件名字符串 */* h* z/ }6 t- b
  15.                     #if _USE_LFN9 j# V: i' |5 J9 H) `  t6 O" @
  16.                         fn_str = *fno.lfname ? fno.lfname : fno.fname;1 @, J& l5 U% M' \9 Y* ^9 N. e
  17.                     #else
    $ q& }8 Q5 S! z# t2 d9 `
  18.                         fn_str = fno.fname;6 v7 g7 ?1 r; `0 L' ^6 r8 \7 h! U
  19.                     #endif $ f$ x; q/ t  K! K. Y' g
  20.                         /* 得到完整的文件名路径 */- I7 p) {- S* N( z; h
  21.                         sprintf(fname_path,"/Update/%s",fn_str);   1 o8 D) p$ l* Y# }, B" f
  22.                         
    ) X5 T' _* E% y. q7 B8 d$ @% K
  23.                         /* 打开升级文件 */$ L! f" ?' I5 U0 D, S
  24.                         result = f_open(&file_fdr,fname_path,FA_OPEN_EXISTING|FA_READ);4 t* j/ k4 M3 h) g" S
  25.                        
    3 {9 `* {2 d3 R
  26.                         if(result==FR_OK)
    1 b8 M, ~% P4 J, {- ^: M: M
  27.                         {  }2 E4 S) i5 t. V9 S
  28.                             /* 打开成功,准备升级 */. o6 @9 W# P# U% i/ q# ]" d; b! ^
  29.                             iap_step = 2;4 r$ p( ~: e3 E
  30.                         }
    ' w* r" D) @% }9 m9 f
  31.                         else
    8 M# N9 R. S; Y7 v8 R' N3 y5 f$ D
  32.                         {0 b2 ?( V$ `" E# N. Y2 Y
  33.                             /* 打开失败 */
    - ]; x$ V# x$ h% I" G4 y
  34.                             f_close(&file_fdr);
    # ?1 Q6 n, ^% k& A- e
  35.                             f_closedir(&dj);  V# @+ |, l7 y7 D
  36.                             iap_step = 5;
    * `" q. k* \- W7 f
  37.                         }; R% l. F. E6 x
  38.                         , d6 U# l0 K! g# `0 P3 C1 J
  39.                     }
    : \5 \3 k. \+ m, I0 O
  40.                     else7 @+ X4 [; R. l- D
  41.                     {. \" Y" P  H3 A1 Z0 m
  42.                         : }" W9 A: S) B2 }% _
  43.                         /* 不存在升级文件,直接跳转 */
    + U0 ], i5 Z* l; v" W& H
  44.                         f_closedir(&dj);1 ^. q9 H9 G* `! W! r  t. y4 K2 ^* ?
  45.                         iap_step = 4;  q9 n& \9 V4 ]3 P! c% [
  46.                         $ D0 w/ d5 \  t$ y" F8 s9 J
  47.                     }0 I2 S# u- a+ \9 @" f
  48.                     break;
    6 w1 m& f2 y; D" r. h9 r
  49.                 }
    , n* c1 J# c! a; w2 H3 U' b  c+ L
  50.                 ) I% K4 K8 b$ N) j
  51.                 /* Step2:存在升级文件,先擦除扇区 */
    $ x1 P! M+ H( z& f) k9 ~9 `3 D) p6 `2 L3 c
  52.                 case 2:
    4 P4 V" x3 }6 v
  53.                 {) x1 z6 r9 ~$ y' F( n3 c
  54.                     FLASH_Unlock();# Q, `: B: ~, M& {1 J  L
  55.                     res = IAP_FLASH_Erase(APPLICATION_ADDRESS);; @0 i' z6 i- U) @: B
  56.                     FLASH_Lock();
    , }& v5 y2 p1 U) n; r- u6 |
  57.                     if( res )5 z0 y8 z3 E' k) a8 T$ N5 s, P6 @
  58.                     {
    ; ~: p3 z% o6 Z2 t$ n8 F
  59.                         iap_step = 3;
    8 W4 ~6 I2 m$ r  {5 K
  60.                     }' M2 H  Z  p: K+ @8 b% x/ ?
  61.                     else9 ?  g. C% }& n3 i) [6 b
  62.                     {6 \. }7 X) V; p1 d
  63.                         f_close(&file_fdr);
    ( ?. v' ?1 J2 i# B5 j6 b$ a+ z
  64.                         f_closedir(&dj);
    * h% B* G/ c8 `& z4 \
  65.                         iap_step = 5;
    / a+ ^. o# u3 Z; f& j. E2 S
  66.                     }
      U7 D( @  u  V! L
  67.                     break;
    ! t/ U3 |/ k+ ?6 l: ^
  68.                 }  |+ l4 `) L7 b9 O7 n0 d1 q
  69.                
    ; n* ], }! B6 m" S9 q9 E, Q3 N
  70.                 /* Step3:扇区擦除成功,准备依次读取并写入 */1 H5 H' x1 P4 l+ C9 w2 w
  71.                 case 3:
    1 l; t$ {# z% X; [( x/ V) J$ r
  72.                 {) D6 y* N8 X. v
  73.                     memset(appbuf,0xFF,2052);( K. H& c8 o# X6 u
  74.                     f_read(&file_fdr,appbuf,2048,&br);' j3 n0 o$ s. V7 d/ n: Y# ?
  75.                     
    & W: Z: i! \+ t" M) U
  76.                     FLASH_Unlock();' w/ Y8 q( e4 j
  77.                     . M: ^* P4 j$ m5 H% B6 r
  78.                     res = IAP_FLASH_Write((u32*)appbuf,(u16)ceil(br/4.0f));
    + Q$ b3 Z1 W* B5 ~1 j
  79.                     
    " y8 z3 G/ [, u: a4 l6 R; [9 y4 U% f
  80.                     FLASH_Lock();
    ! m, P; x* L9 g
  81.                     / r, I' I1 i- U" [/ ]3 T- r, s
  82.                     Toggle_LED_AP();1 |$ p. J6 ^3 C0 H$ B+ T! T
  83.                     
    8 v" ]$ z. @: I' _0 O1 i. d5 M
  84.                     if(res == 0)
    ) V- ]/ E4 Z+ q( P" H
  85.                     {1 e/ ]$ t6 w9 a( t" d
  86.                         f_close(&file_fdr);+ }! Y+ t$ J7 r( `
  87.                         f_closedir(&dj);8 m) w" C. W- Z, x+ y
  88.                         iap_step = 5;
    + {, A3 K* D' f4 N5 R
  89.                         
    $ i8 t, K% w5 ]& U
  90.                     }9 G5 b% ?( F, O5 ^/ r, \
  91.                     else
    # [9 }; ~: @* ~  p# g8 U
  92.                     {
    . i1 Y6 F  t/ Y1 @2 Z) `( `# l
  93.                         /* 文件读完了 */, @, @" _" |9 _$ E! L. Q
  94.                         if(br<2048)
      s" l& u! z- o2 p% I
  95.                         {7 T5 [! v4 P% R) s+ z6 @
  96.                             f_close(&file_fdr);
    & N7 n9 F, }# ?0 U
  97.                             f_closedir(&dj);- R" @( m# `$ N* U: W
  98.                             f_unlink(fname_path);
    7 b6 ~; @0 d7 R
  99.                             iap_step = 4;   
    $ A3 ?: `7 y# S: n8 p/ v
  100.                            
    + o  g; x+ C) @! w
  101.                         }
    2 i" E- Z# i+ k7 k
  102.                         
    3 R" D2 K9 `: f/ F. G$ `' {
  103.                     }1 Q& r3 o5 [7 t+ H# ?$ s! v
  104.                     break;
    & E; e. _2 l$ m* l7 k* h
  105.                 }( r3 v! N/ T' O+ B: o. z
  106.                
    1 H6 h! t+ {& {  {! t
  107.                 /* Step4:跳转至App程序 */
    , ~$ f  B% H2 t+ m0 M
  108.                 case 4:
    ! ~- |; J1 K# _. J- ~
  109.                 {  
    ' F4 s5 ]- u% X) G, E# T; w$ w
  110.                     /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */' B! N1 Q! n0 A5 u
  111.                     if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    & K7 f4 U0 P2 S
  112.                     {
    # m% G1 r! j2 Q3 \0 g- ~2 Q
  113.                         /* Jump to user application */$ j9 G) ^  R% E* x
  114.                         JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);% R$ |- H2 k% m: J2 t' c
  115.                         Jump_To_Application = (pFunction) JumpAddress;
    0 l& u( o5 V0 N) O$ \( U; ~7 a6 W' c
  116.                         
    . z5 [' z: s, W0 A
  117.                         /* Initialize user application's Stack Pointer */- Q2 p* D7 ?4 {: T3 P
  118.                         __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);; U, m3 _) U0 ^3 U+ c
  119.                         
    - C/ O3 S" z- o  Z
  120.                         /* Jump to application */- t1 O; _: L; O
  121.                         Jump_To_Application();
    . }( d  Z8 u5 w9 ~; I
  122.                     }
    ; B7 a1 b( v2 a
  123.                     else
    , P& o, \' ?2 g# C; o/ G4 J3 s- s2 f( {
  124.                     {
    " i9 X7 c3 N1 n# \$ p8 Q
  125.                         iap_step = 5;
    % p$ Z; J+ j. L2 V! o! t3 |$ R5 b! O
  126.                     }6 T3 T! N. E. K( a
  127.                     1 P8 j5 G) v' T% I
  128.                     break;  E9 l3 t" |: g& ?4 O
  129.                 }0 k# g% I% J- J! |3 h( q! x
  130.                
    ! q2 k4 |% N! Z2 F7 T
  131.                 /* Step5:升级失败,等待重新上电 */
      I7 Y4 O/ S2 t+ F5 f7 @* z
  132.                 case 5:/ i+ T7 q* D, ]/ J
  133.                 {
    " W( Z! L" G& g& i; j
  134.                     if(GetFreqFlag(FREQ_0_5HZ))
    8 F" r* z4 i8 F
  135.                     {, M2 G/ e2 [0 O& l
  136.                         Toggle_LED_AP();+ P, r9 {6 o( Y6 i( o
  137.                     }
    ) o7 L, K1 r: y/ q+ Z5 S- w; U
  138.                     break;
    ; `2 ]/ g" P7 @' T7 ?0 ~4 ?7 e
  139.                 }5 F+ p4 P2 d- g6 g2 w
  140.                 7 U3 }1 f3 x6 E* y
  141.                 default:8 I) v% [& _, m) V
  142.                 {3 {" V4 U. g5 }. F+ l7 k% w
  143.                     iap_step = 1;
    3 q2 e/ Z6 }7 B4 J
  144.                     break;# \8 A6 v6 o* j9 G
  145.                 }* ?' o  m: ]/ P1 V
  146.                
    7 \, @# c# [6 ^/ }9 b9 d6 r6 {  S6 V
  147.                 2 x# ^4 g5 _1 S& c* T
  148.             }//iap step switch
    6 H7 `, i4 M; O5 A* K% j
  149.             + F! D. }4 ]; v) U! y$ M$ m, p
  150.         }//end of bootloader while(1)
复制代码
特别要注意形参uint16_t Datalength是指的字数,就是uint32_t类型变量的数量,而f_read读取的是字节数,要除以4进行转换,刚开始就是没有转换导致写的flash数据不正常,跳转后死机。
8 P& V0 N! S9 d3 @; h0 c跳转程序也是参考的官方例程。我设置的App程序起始地址为:0x0800 A000
3 G% d& L; a: s& c& e9 e+ G0 K8 X
此外bootloader程序的IAR工程配置如图,flash地址范围:0x0800 0000 - 0x0800 9FFF,占用40K
0 h; Z. _0 J& u
, ?# P7 ]7 @( j4 `5 ?! V
% R$ i0 S( P& l1 m
App程序设计* y' Q% a% a: v3 z
1、App程序主要在原来的程序基础上修改flash起始和结束地址,以及中断向量偏移。Flash地址范围我设为:0x0800 A000 – 0x0801 FFFF,占用88K,IAR配置如下:7 j$ f) S( q. b* I8 F; _

" n' V+ c( S( q# T( V
6 ~6 r& N5 e6 P& N. n8 h7 F9 \

7 p/ x* @, q5 z5 e# \: G0 j) u' ]
' H6 H* p1 h1 i

* R. R: m  H, l. t6 E  M' t
) T4 S# O  }4 X3 q! w; m: y2、由于STM32F0没有像F1,F4那样的中断向量偏移寄存器,需要通过进行内存地址映射来实现,具体实现原理参见http://www.51hei.com/bbs/dpj-40938-1.html, @9 Y3 H0 u! @& R1 _3 g
所以在App程序main函数开始的地方加如下代码:(参考官方例程修改)

app设置

app设置

, Y) r" b" ^! Y' t9 |) ~9 ~, A 其实在官方例程中为 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);这并没有打开系统配置时钟,应该改为RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);我也是看到网上其他帖子才发现并改正过来的,在这里感谢网友们的分享!! _( G, j, b6 U
以上就是我做的STM32F0的IAP升级方案,实际测试感觉速度很快,可能我的App程序不大,50K左右,升级过程基本在3秒以内。
  L; a7 e/ f& g% Z2 H! l
: A9 l) h8 o( d* \
4 @4 c# r2 r: c: ~+ R. S* m6 L0 a6 x# c* F8 n

3 j, w: g  z5 z. b

评分

参与人数 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
. {3 t/ U" l4 J' I不过,支持一个!!!

2 T6 M6 e5 N# V* l: C' O6 B/ n$ u谢谢版主,发现少了一幅图,重新编辑上传了
zhumx 回答时间:2017-9-18 17:59:53
ts2000 发表于 2017-9-18 15:57
4 p- ?3 G. O* G% c; r- m4 _做过类似的,顶一下楼主~
0 ]+ Y9 t, W1 d* A1 Z1 N
谢谢
包子不 回答时间: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

7 l6 K  F5 M, n& r0 w1 I谢谢分享,支持一下!
网络孤客 回答时间: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管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版