搜索
查看: 6023|回复: 17

[原创] STM32F072使用SD卡进行IAP升级

  [复制链接]

该用户从未签到

20

主题

55

帖子

3

蝴蝶豆

高级会员

最后登录
2020-7-5
发表于 2017-9-15 17:31:55 | 显示全部楼层 |阅读模式
本帖最后由 黑色裂变 于 2017-9-18 09:22 编辑

之前做的一个小项目,因为刚开始没有考虑到以后会经常升级,而每次升级都要旋开4颗螺丝拆壳,然后烧程序,再装壳,如果只要更新几个倒没啥感觉,但是一下更新几百个,那工作量。。。。,正好板子上有SD卡,就想着写个Bootloader程序,通过读取SD卡中的Bin文件进行IAP升级,这样可以大大简化以后的升级。IAP升级原理就不多说了,网上相关的资料和帖子一大堆,这里简单介绍我做的IAP方案,欢迎大家批评指正!
Bootloader程序设计
bootloader程序的设计思路很简单,流程图如下:


初始化程序就不介绍了,比较简单。主要介绍下Bin文件检测以及IAP过程。我将IAP过程分为5个步骤,如下:
Step1:检查是否存在升级文件,若存在,打开后跳至Step2,若不存在或者打开失败,跳至Step5
Step2:擦除App程序对应的扇区,擦除成功后跳至Step3,若擦除失败,跳至Step5
Step3:使用f_read()函数读取Bin文件,每次读取2048个字节,并写入Flash。当文件全部被写入flash后跳至Step4,若中间出现写入错误,跳至Step5
Step4:检查栈顶地址,跳转至App程序。若栈顶地址非法,跳至Step5
Step5:此步表示本次升级失败,死循环,同时LED提示升级失败,等待重新上电
查找升级文件时我固定从Update文件夹查找,所以只要将Bin文件拷贝至Update文件夹就行了。
五个步骤的转换是通过switch函数实现的。代码如下:
  1.         while(1)
  2.         {
  3.             switch(iap_step)
  4.             {
  5.                 /* Step1:检查是否存在升级文件 */
  6.                 case 1:
  7.                 {
  8.                     /* 查找升级文件 */
  9.                     result = f_findfirst(&dj, &fno, "0:/Update", "FDR_update*.bin");
  10.                     
  11.                     /* 存在升级文件 */
  12.                     if(result==FR_OK && fno.fname[0])
  13.                     {
  14.                         /* 获取文件名字符串 */
  15.                     #if _USE_LFN
  16.                         fn_str = *fno.lfname ? fno.lfname : fno.fname;
  17.                     #else
  18.                         fn_str = fno.fname;
  19.                     #endif
  20.                         /* 得到完整的文件名路径 */
  21.                         sprintf(fname_path,"/Update/%s",fn_str);   
  22.                         
  23.                         /* 打开升级文件 */
  24.                         result = f_open(&file_fdr,fname_path,FA_OPEN_EXISTING|FA_READ);
  25.                        
  26.                         if(result==FR_OK)
  27.                         {
  28.                             /* 打开成功,准备升级 */
  29.                             iap_step = 2;
  30.                         }
  31.                         else
  32.                         {
  33.                             /* 打开失败 */
  34.                             f_close(&file_fdr);
  35.                             f_closedir(&dj);
  36.                             iap_step = 5;
  37.                         }
  38.                         
  39.                     }
  40.                     else
  41.                     {
  42.                         
  43.                         /* 不存在升级文件,直接跳转 */
  44.                         f_closedir(&dj);
  45.                         iap_step = 4;
  46.                         
  47.                     }
  48.                     break;
  49.                 }
  50.                
  51.                 /* Step2:存在升级文件,先擦除扇区 */
  52.                 case 2:
  53.                 {
  54.                     FLASH_Unlock();
  55.                     res = IAP_FLASH_Erase(APPLICATION_ADDRESS);
  56.                     FLASH_Lock();
  57.                     if( res )
  58.                     {
  59.                         iap_step = 3;
  60.                     }
  61.                     else
  62.                     {
  63.                         f_close(&file_fdr);
  64.                         f_closedir(&dj);
  65.                         iap_step = 5;
  66.                     }
  67.                     break;
  68.                 }
  69.                
  70.                 /* Step3:扇区擦除成功,准备依次读取并写入 */
  71.                 case 3:
  72.                 {
  73.                     memset(appbuf,0xFF,2052);
  74.                     f_read(&file_fdr,appbuf,2048,&br);
  75.                     
  76.                     FLASH_Unlock();
  77.                     
  78.                     res = IAP_FLASH_Write((u32*)appbuf,(u16)ceil(br/4.0f));
  79.                     
  80.                     FLASH_Lock();
  81.                     
  82.                     Toggle_LED_AP();
  83.                     
  84.                     if(res == 0)
  85.                     {
  86.                         f_close(&file_fdr);
  87.                         f_closedir(&dj);
  88.                         iap_step = 5;
  89.                         
  90.                     }
  91.                     else
  92.                     {
  93.                         /* 文件读完了 */
  94.                         if(br<2048)
  95.                         {
  96.                             f_close(&file_fdr);
  97.                             f_closedir(&dj);
  98.                             f_unlink(fname_path);
  99.                             iap_step = 4;   
  100.                            
  101.                         }
  102.                         
  103.                     }
  104.                     break;
  105.                 }
  106.                
  107.                 /* Step4:跳转至App程序 */
  108.                 case 4:
  109.                 {  
  110.                     /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
  111.                     if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
  112.                     {
  113.                         /* Jump to user application */
  114.                         JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
  115.                         Jump_To_Application = (pFunction) JumpAddress;
  116.                         
  117.                         /* Initialize user application's Stack Pointer */
  118.                         __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
  119.                         
  120.                         /* Jump to application */
  121.                         Jump_To_Application();
  122.                     }
  123.                     else
  124.                     {
  125.                         iap_step = 5;
  126.                     }
  127.                     
  128.                     break;
  129.                 }
  130.                
  131.                 /* Step5:升级失败,等待重新上电 */
  132.                 case 5:
  133.                 {
  134.                     if(GetFreqFlag(FREQ_0_5HZ))
  135.                     {
  136.                         Toggle_LED_AP();
  137.                     }
  138.                     break;
  139.                 }
  140.                
  141.                 default:
  142.                 {
  143.                     iap_step = 1;
  144.                     break;
  145.                 }
  146.                
  147.                
  148.             }//iap step switch
  149.             
  150.         }//end of bootloader while(1)
复制代码
特别要注意形参uint16_t Datalength是指的字数,就是uint32_t类型变量的数量,而f_read读取的是字节数,要除以4进行转换,刚开始就是没有转换导致写的flash数据不正常,跳转后死机。
跳转程序也是参考的官方例程。我设置的App程序起始地址为:0x0800 A000

此外bootloader程序的IAR工程配置如图,flash地址范围:0x0800 0000 - 0x0800 9FFF,占用40K


App程序设计
1、App程序主要在原来的程序基础上修改flash起始和结束地址,以及中断向量偏移。Flash地址范围我设为:0x0800 A000 – 0x0801 FFFF,占用88K,IAR配置如下:






2、由于STM32F0没有像F1,F4那样的中断向量偏移寄存器,需要通过进行内存地址映射来实现,具体实现原理参见http://www.51hei.com/bbs/dpj-40938-1.html
所以在App程序main函数开始的地方加如下代码:(参考官方例程修改)

app设置

app设置

其实在官方例程中为 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);这并没有打开系统配置时钟,应该改为RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);我也是看到网上其他帖子才发现并改正过来的,在这里感谢网友们的分享!
以上就是我做的STM32F0的IAP升级方案,实际测试感觉速度很快,可能我的App程序不大,50K左右,升级过程基本在3秒以内。




评分

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

查看全部评分

回复

使用道具 举报

该用户从未签到

17

主题

672

帖子

0

蝴蝶豆

论坛元老

最后登录
2020-12-21
发表于 2017-9-16 07:58:09 | 显示全部楼层
支持一下
回复

使用道具 举报

该用户从未签到

3

主题

1002

帖子

363

蝴蝶豆

版主

最后登录
2021-4-15
发表于 2017-9-16 09:23:03 | 显示全部楼层
不过,支持一个!!!
回复 支持 反对

使用道具 举报

该用户从未签到

20

主题

55

帖子

3

蝴蝶豆

高级会员

最后登录
2020-7-5
 楼主| 发表于 2017-9-18 09:23:26 | 显示全部楼层
MrJiu 发表于 2017-9-16 09:23
不过,支持一个!!!

谢谢版主,发现少了一幅图,重新编辑上传了
回复 支持 反对

使用道具 举报

该用户从未签到

27

主题

1912

帖子

42

蝴蝶豆

论坛元老

最后登录
2022-7-11
发表于 2017-9-18 15:57:27 | 显示全部楼层
做过类似的,顶一下楼主~
回复 支持 反对

使用道具 举报

该用户从未签到

20

主题

55

帖子

3

蝴蝶豆

高级会员

最后登录
2020-7-5
 楼主| 发表于 2017-9-18 17:59:53 | 显示全部楼层
ts2000 发表于 2017-9-18 15:57
做过类似的,顶一下楼主~

谢谢
回复 支持 反对

使用道具 举报

该用户从未签到

0

主题

2290

帖子

3

蝴蝶豆

论坛元老

最后登录
2021-5-1
发表于 2017-9-18 20:40:54 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

该用户从未签到

14

主题

519

帖子

9

蝴蝶豆

金牌会员

最后登录
2022-7-6
发表于 2017-9-20 15:00:10 | 显示全部楼层
谢谢分享
回复

使用道具 举报

该用户从未签到

0

主题

4

帖子

0

蝴蝶豆

新手上路

最后登录
2018-3-21
发表于 2017-10-14 15:33:42 | 显示全部楼层

谢谢分享,支持一下!
回复 支持 反对

使用道具 举报

该用户从未签到

22

主题

1351

帖子

62

蝴蝶豆

论坛元老

最后登录
2021-9-26
发表于 2017-10-15 13:48:05 | 显示全部楼层
谢谢分享,很实用的教程。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-4-24 18:58 , Processed in 0.246216 second(s), 47 queries .

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表