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

STM32F072使用SD卡进行IAP升级  

[复制链接]
zhumx 发布时间:2017-9-15 17:31
本帖最后由 黑色裂变 于 2017-9-18 09:22 编辑
; Q% c# ?! ?9 @& ^7 f! [1 Z7 V7 i' t* S1 q  k2 N, a% d
之前做的一个小项目,因为刚开始没有考虑到以后会经常升级,而每次升级都要旋开4颗螺丝拆壳,然后烧程序,再装壳,如果只要更新几个倒没啥感觉,但是一下更新几百个,那工作量。。。。,正好板子上有SD卡,就想着写个Bootloader程序,通过读取SD卡中的Bin文件进行IAP升级,这样可以大大简化以后的升级。IAP升级原理就不多说了,网上相关的资料和帖子一大堆,这里简单介绍我做的IAP方案,欢迎大家批评指正!
$ L7 K* z( ]2 b" Q
Bootloader程序设计
+ R' j$ Z! t9 W1 |4 ?bootloader程序的设计思路很简单,流程图如下:3 A' K! Y$ q: p% v' ]

, y" P: i! a8 o! d
" m* E  ~: M0 _
初始化程序就不介绍了,比较简单。主要介绍下Bin文件检测以及IAP过程。我将IAP过程分为5个步骤,如下:1 b0 C5 t+ c) r/ o! s
Step1:检查是否存在升级文件,若存在,打开后跳至Step2,若不存在或者打开失败,跳至Step5# h4 j8 q9 ^4 Q( D, S
Step2:擦除App程序对应的扇区,擦除成功后跳至Step3,若擦除失败,跳至Step5
/ }( R( G/ i3 F) `+ K& z* AStep3:使用f_read()函数读取Bin文件,每次读取2048个字节,并写入Flash。当文件全部被写入flash后跳至Step4,若中间出现写入错误,跳至Step56 M- v. ^( p: s6 V
Step4:检查栈顶地址,跳转至App程序。若栈顶地址非法,跳至Step50 {- I9 V3 E1 @/ P
Step5:此步表示本次升级失败,死循环,同时LED提示升级失败,等待重新上电4 e6 l' |8 ^9 ^9 A0 b
查找升级文件时我固定从Update文件夹查找,所以只要将Bin文件拷贝至Update文件夹就行了。; U! q4 I" d) U  f% L! H/ I" g
五个步骤的转换是通过switch函数实现的。代码如下:
: d" T2 [5 J% Y- u" `) o4 c- R
  1.         while(1)
      m2 A+ }) @& o
  2.         {
    7 ^( y$ j5 E: {  S) \
  3.             switch(iap_step); n/ I# H' U+ a- G. B$ R# ?, m9 b" z0 V
  4.             {1 \, F8 G5 Z% M
  5.                 /* Step1:检查是否存在升级文件 */" |% U! D& j  a/ Y5 R
  6.                 case 1:
    # E1 d8 \1 w# i# b1 Q
  7.                 {% @4 \1 j) q/ E4 V
  8.                     /* 查找升级文件 */
    0 @  ?9 m5 A1 u7 ~* R
  9.                     result = f_findfirst(&dj, &fno, "0:/Update", "FDR_update*.bin");3 V( q5 E, T& o8 `: ~  ~' |
  10.                     
    * A+ V  g1 l- |& p! q
  11.                     /* 存在升级文件 */
    0 n' d! |& P7 M" O! Z( z% I
  12.                     if(result==FR_OK && fno.fname[0])  ~! V% M( L! s" {, H! P: g
  13.                     {
    ! K, z7 K4 M, ~) V$ E
  14.                         /* 获取文件名字符串 */- s6 a. G# R( [3 J8 r
  15.                     #if _USE_LFN# u  O% x5 b  Q. c- H/ T# T5 C+ s
  16.                         fn_str = *fno.lfname ? fno.lfname : fno.fname;! e/ B6 e, p% p% U( E/ H) B: P
  17.                     #else
    8 O6 D4 \$ _  R) K5 V
  18.                         fn_str = fno.fname;5 E5 d! M! N+ E" N; [7 k
  19.                     #endif : U& Z! v" d3 D$ v( R) e0 W
  20.                         /* 得到完整的文件名路径 */; P! R5 C1 U' l1 J% D
  21.                         sprintf(fname_path,"/Update/%s",fn_str);   
    ; d# q* Q& p' o1 o2 a7 a; j& q% W8 |
  22.                         & \- J: }# A# W9 M& \6 }* d0 y! q
  23.                         /* 打开升级文件 */& o6 l* ^' B( x) D1 {7 K
  24.                         result = f_open(&file_fdr,fname_path,FA_OPEN_EXISTING|FA_READ);
    - p) T! w! V' f
  25.                        # Y" b: b# E" b
  26.                         if(result==FR_OK)
    9 h' S  \( b0 g7 @0 s" j
  27.                         {. s  O9 Q( x" L# ^" E$ O
  28.                             /* 打开成功,准备升级 */
    9 ^7 b% A' u: B" B8 {+ R0 l, {9 {
  29.                             iap_step = 2;
    & x1 a  s3 W0 L$ ]) e. ?
  30.                         }
    2 R- e/ n+ v6 d
  31.                         else, S% C" g1 z6 p+ J- d8 a9 U
  32.                         {9 W3 Z, j7 m. o! B- \2 Z7 H. c
  33.                             /* 打开失败 */. G8 `1 e/ @& G7 y; H- ]  I; Z
  34.                             f_close(&file_fdr);
    . Z# t$ ]. j: m( S
  35.                             f_closedir(&dj);$ S) k. n- O9 {! f) M
  36.                             iap_step = 5;
    $ w# J+ ^) q1 T. k! j1 f
  37.                         }3 R8 i1 r6 i$ o' B4 j' u' l/ z6 J
  38.                         / [( G) N2 i: W! D4 z
  39.                     }
    1 z5 f' {3 f+ Q4 e
  40.                     else
    & x& g0 t* t, @& W1 R8 d
  41.                     {+ {4 N1 B* P5 T2 w: D0 d
  42.                         
    4 P5 @# @8 W8 D' n* H4 L: P/ N
  43.                         /* 不存在升级文件,直接跳转 *// n* ~# ]2 L4 {
  44.                         f_closedir(&dj);
    * S: d6 u: X3 C* {* J
  45.                         iap_step = 4;
    + c8 k: V% u& Z1 g1 q
  46.                         % `$ U; D5 u+ G
  47.                     }
    + j2 O$ ~# D6 h$ Z# L: e) k# a% X! h3 U
  48.                     break;8 N% \0 u$ ~  P6 h
  49.                 }
    . v, z+ |/ y0 g  \4 D* b
  50.                 ! K% P: O) P8 k6 C
  51.                 /* Step2:存在升级文件,先擦除扇区 */
      L4 B  y# r7 y  D1 p0 F6 p
  52.                 case 2:
    # N6 b/ }* r& r* i+ i) Q' n& q
  53.                 {
    ! @8 |8 ]& Z7 ?# c) A4 h) y
  54.                     FLASH_Unlock();
    4 Y; s( w: o! }+ n6 m& v/ p6 ]
  55.                     res = IAP_FLASH_Erase(APPLICATION_ADDRESS);
    / R" e% @0 Y9 \5 ?* X5 A& v
  56.                     FLASH_Lock();
    3 F( n" X: b4 C' [
  57.                     if( res )5 [+ T' }! f. }4 |
  58.                     {
    4 B$ {+ g  D; G$ j; E
  59.                         iap_step = 3;) W- A; J7 Y9 B) l5 v" j
  60.                     }9 u7 W- f; t& I9 t! I+ E
  61.                     else8 o2 Y5 e- U2 w9 a2 M* W% N; G+ |
  62.                     {4 [0 o/ j) M; M& k
  63.                         f_close(&file_fdr);
    7 w; s! R# u$ M4 w. K( C7 p
  64.                         f_closedir(&dj);" s1 r" ^/ c' O! ?( L
  65.                         iap_step = 5;
    0 I2 q  f' r/ J% F
  66.                     }9 ?) @9 A6 b7 B4 c/ F8 X, A
  67.                     break;
    6 N, G; k2 q: i$ J
  68.                 }$ u4 s* h2 Y( d9 J' g, ^! W  p
  69.                
    % T2 b; F+ z( I, G2 N4 n& Z5 Q
  70.                 /* Step3:扇区擦除成功,准备依次读取并写入 */
    7 ^, T; U% u- f; G% ^
  71.                 case 3:' w3 F; W: R  c4 B& s
  72.                 {
    % P+ K- P: B1 X: v7 E! r
  73.                     memset(appbuf,0xFF,2052);
    - O1 y, m9 `% f- C# }4 I' E
  74.                     f_read(&file_fdr,appbuf,2048,&br);* q8 U5 @. s4 {6 H
  75.                     4 ~) }3 }+ W4 Q; k. ~! k& q
  76.                     FLASH_Unlock();- y" W2 e, m6 [) e
  77.                     
    4 s9 g. q2 o0 [3 s& C
  78.                     res = IAP_FLASH_Write((u32*)appbuf,(u16)ceil(br/4.0f));; S( l, x! Y+ p# z; t
  79.                     ( }, h1 E2 j* ?; V# Z
  80.                     FLASH_Lock();9 a/ ^$ v# ]3 Z3 M9 I( ~! O
  81.                     
    " b& J+ M" ^' r6 a& s# ^3 _
  82.                     Toggle_LED_AP();" Q& \0 ?& ?8 L& `: K- {- h
  83.                     
    2 e% l! o5 L0 H1 O$ G' A
  84.                     if(res == 0)
    4 K+ V% i4 T: T: `) w- S
  85.                     {
    : b. O2 }0 _0 G! V3 K# Y: @+ W
  86.                         f_close(&file_fdr);
    8 C+ ~( t* G  O+ S% Z
  87.                         f_closedir(&dj);
    ; n, m+ \- J3 H3 N; J
  88.                         iap_step = 5;7 @$ y7 w' d7 ~# a* H& A
  89.                         . _. J% y' F/ i) @% O
  90.                     }7 k9 D1 e, B- A! K
  91.                     else; t( }2 M% J8 {( f* X, r* a
  92.                     {3 ~) S9 K6 w3 A; k* i. U8 C! Z
  93.                         /* 文件读完了 */% Y8 Q* W- E: S
  94.                         if(br<2048); E' r) z6 |6 T# d+ w' C
  95.                         {
    ! b. w4 A; v3 T! s* S$ ?8 P5 H
  96.                             f_close(&file_fdr);
    $ r* U! ?8 ?# n; q( i3 W
  97.                             f_closedir(&dj);
    8 \" L9 W: D0 V4 {  @, V
  98.                             f_unlink(fname_path);
    & Q+ G+ n, c& S5 M
  99.                             iap_step = 4;   
    ' \+ J; r! E0 N2 m# V3 s
  100.                             / N* F) A! h2 g
  101.                         }
    7 \/ u. e  Q- q% q: H
  102.                         
    9 v" l3 |: C2 D6 Y7 u4 O# Q! R
  103.                     }
    1 V) u/ x% c" q5 C# X
  104.                     break;
    7 B$ I. B; W5 Z; K! n; s9 U8 u
  105.                 }
    * L8 ]# W" t4 k0 C+ F
  106.                
    ' f7 Z+ B" E# H2 ]
  107.                 /* Step4:跳转至App程序 */
    ) |/ z% D; P9 J6 U! n$ V
  108.                 case 4:1 n) M, q2 N8 O# h% s% y! U: e
  109.                 {  
    + W3 S% Z- q; `- |
  110.                     /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */2 |' j, z* Z! T+ @4 S2 F( |! e  k
  111.                     if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    1 L, a5 S( R0 o( ~
  112.                     { 4 r) q3 `! l+ ^2 S
  113.                         /* Jump to user application */
    0 Y. D8 Z" J7 f* T% ~! N3 L* K& B# i
  114.                         JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);$ N4 A* I/ [0 Z
  115.                         Jump_To_Application = (pFunction) JumpAddress;& ?9 [) a+ p) F, w" v  [
  116.                         
      W  B& m0 r' u: `  ?
  117.                         /* Initialize user application's Stack Pointer */' Q8 p! U4 h" D9 P0 J
  118.                         __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
    6 `: N2 }/ M# q' f* S/ S
  119.                         
    * b; X8 E: x- a& F& c
  120.                         /* Jump to application */
    ( S0 s+ Z0 `, D1 b9 c- j
  121.                         Jump_To_Application();
    3 H4 F- J& Q8 u% ]2 a. \$ B' Q
  122.                     }5 u& W- R# v- k7 M
  123.                     else" W* L4 M( w$ v# P; B
  124.                     {
    : _, T) y5 b- Y) i0 T
  125.                         iap_step = 5;
    1 c1 k: N$ A5 a6 G2 B3 d
  126.                     }" H" k+ I& `" [2 S* G5 m
  127.                     & c; S8 S( F9 c0 O. W0 C: N, u8 f5 ~
  128.                     break;
    . o6 l+ R' z, \% q( x; T4 C- ]
  129.                 }# P; Z" I* D3 l# P  x  `2 Y, i0 Z
  130.                
    * Y. a' c* _) `
  131.                 /* Step5:升级失败,等待重新上电 */
    2 Y! ^5 R! m1 t$ N$ r
  132.                 case 5:; m) z/ G- u; e
  133.                 {
      J; C9 Q7 P7 l0 \" @+ h
  134.                     if(GetFreqFlag(FREQ_0_5HZ)): c% x) _: u8 p* S  S
  135.                     {5 V/ B( b5 s$ c& w3 ~
  136.                         Toggle_LED_AP();
    * t: w2 b% U) J# }$ g
  137.                     }
    + U2 N1 k. |; a4 `0 X$ O, P7 T7 V9 \
  138.                     break;
    . K4 l: |) ^* g! ]7 [/ a+ P- y% [5 i
  139.                 }
    + o- T5 |7 a( }+ ]
  140.                 " Y& q* i6 z6 I# e  W- Q' W
  141.                 default:5 G. M7 Q7 b, a
  142.                 {6 U% N% s+ U& i$ P5 o; \8 v
  143.                     iap_step = 1;
    : Y& a  |5 `4 ^  m! L
  144.                     break;! z, N3 k+ I  o! w% f
  145.                 }" M' K% G; H$ w1 y6 U, C: N
  146.                
    ; g8 n6 W0 }5 H
  147.                
    3 b" g# Z3 ]2 l- {
  148.             }//iap step switch
    , U* x; @0 M1 f% h' k
  149.             0 R4 I1 @, U: x# R9 R
  150.         }//end of bootloader while(1)
复制代码
特别要注意形参uint16_t Datalength是指的字数,就是uint32_t类型变量的数量,而f_read读取的是字节数,要除以4进行转换,刚开始就是没有转换导致写的flash数据不正常,跳转后死机。
/ ?) a  m5 q9 \+ D# @% \' q5 H: v跳转程序也是参考的官方例程。我设置的App程序起始地址为:0x0800 A000
8 ]2 a$ S/ F8 P$ G
此外bootloader程序的IAR工程配置如图,flash地址范围:0x0800 0000 - 0x0800 9FFF,占用40K
2 o6 y! d- X/ |& F- |* c; [0 G
) w4 u2 W" s# ~. a. S* S* x+ E' I1 H7 U

6 K& w, [5 y5 i( q2 d6 _App程序设计5 p, y) d% e  }' u' g! k
1、App程序主要在原来的程序基础上修改flash起始和结束地址,以及中断向量偏移。Flash地址范围我设为:0x0800 A000 – 0x0801 FFFF,占用88K,IAR配置如下:
7 N0 q& B! g4 @
2 F! ?, K, W/ J7 i

( G2 ?. H* i( N  s! R- y( `
) q" w8 o9 D4 d$ s2 [& b

, d  J8 q  U6 ^- P& K8 Y6 X8 K- F
3 q2 ^) _+ h. w; S# k% `( H5 U7 }2 M: c* R% t
2、由于STM32F0没有像F1,F4那样的中断向量偏移寄存器,需要通过进行内存地址映射来实现,具体实现原理参见http://www.51hei.com/bbs/dpj-40938-1.html$ Q7 q" ?% D( G' O( o3 W3 E) y6 B
所以在App程序main函数开始的地方加如下代码:(参考官方例程修改)

app设置

app设置
3 d# a: o/ X$ B
其实在官方例程中为 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);这并没有打开系统配置时钟,应该改为RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);我也是看到网上其他帖子才发现并改正过来的,在这里感谢网友们的分享!" f& s+ `( ^+ @# k4 c
以上就是我做的STM32F0的IAP升级方案,实际测试感觉速度很快,可能我的App程序不大,50K左右,升级过程基本在3秒以内。
$ Y& }& c$ H/ d: D) ]: ~4 F: B8 b$ c+ L8 ^

+ O! ^4 h1 t) x- I" `5 f8 Z& O7 l- _2 h$ M7 {3 P

% Y* `- W1 E. d! `. ^8 G

评分

参与人数 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' A  |& u! z% R5 N( o3 k. n
不过,支持一个!!!
# _0 L5 @$ z, _, E  c
谢谢版主,发现少了一幅图,重新编辑上传了
zhumx 回答时间:2017-9-18 17:59:53
ts2000 发表于 2017-9-18 15:57
  [9 E* P; G) v做过类似的,顶一下楼主~
5 k$ _: p% `7 {3 \( e
谢谢
包子不 回答时间: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

( R5 C* ]3 e. [0 x- g' v1 U谢谢分享,支持一下!
网络孤客 回答时间: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 手机版