SD卡升级——SDIO_IAP实验

在嵌入式项目中,经常会用到SD卡升级这一方式来进行产品的软件升级。刚好最近做的项目也需要这一功能,由于之前未接触过IAP开发,刚好在这个时候可以学习一下,于是先到各大网站去搜索相关资料,两天下来,基本对于IAP的概念和编程步骤有了大致的了解。本人手里有块开发板,前期的实验都是在这块开发板上实现的。在实现了SD卡IAP功能以后,立马将工程移植到项目中去,很快就把这个功能添加进去了,甚是高兴,对于以前的SD卡升级功能也不再那么神秘了。

本人是先看FLASH模拟EEPROM实验,了解了STM32片内FLASH编程的步骤,然后再看的串口IAP实验,学习IAP编程的思想,最后搜索相关的资料,最终完成了SD卡IAP编程的学习,并解决了实际问题。

学习总结:

1.STM32片内FLASH编程步骤4步曲:解锁、擦除、编程、上锁;

2.设置IAP程序在FLASH的起始地址,设置用户程序的起始地址为IAP后面的地址,并修改ROM空间大小;

3.在用户程序中,设置中断向量偏移地址为用户程序的起始地址;

4.STM32大容量存储器的页大小为2K,起初总以为是512字节;

5.页擦除的时候,所有的页地址都是实际的字节地址,而并非常说的“第几页第几页”中的页编号;

6.页擦除的时候,如果指定的页地址没有和页边界对齐的话,擦除操作仍然有效,只是擦除的范围是指定地址所在的整页大小;

IAP实验是基于串口的,由于串口的数据发送是不可调的,只能一次性将整个用户程序的BIN文件发送给bootloader,而且bootloader是将接收到的用户文件暂存在片内SRAM的,这就限值了用户程序的大小,不能大于SRAM的大小64K。而SD卡设计则不受用户程序大小限值,只要FLASH装得下就行。由于原子哥的代码很多都是寄存器版本的,而文件系统又是他自己独门的FAT32驱动,再加上他的开发板SD卡例程都基于SPI驱动的(只有一个扩展例程是SDIO的),而我的项目时间比较急,要求用最高的效率完成这项功能,于是就产生了以ST官方库函数为主导,以网上开源文件系统Fatfs作为SD卡文件系统驱动,以SDIO4位总线的DMA访问模式为SD卡驱动这样一个方案,一切都只为了开发的效率,同时,也将源代码与大家分享,相信也有很多人使用这样一种方案的。

本工程试验平台:

1.硬件:LCD驱,是兼容2.4到3.5的。SanDisk 1G SD卡, MicroSD 2G。

2.软件:ST官方库V3.0的,比较老了。

FatFs文件系统,注意:本人在ff.h配置中将宏_FS_READONLY配置为1,即只生成读操作的代码,不编译写操作的代码,目的是为了减小bootloader的代码量。

下面就将主要的源代码贴出,供大家参考。

  1. /**************************************************************************************
  2. 文件名  :main.c
  3. 文件描述:程序执行的主要文件,不用说也明白
  4. ***************************************************************************************/
  5. #include "stm32f10x.h"
  6. #include "delay.h"
  7. #include "LED.h"
  8. #include "diskio.h"
  9. #include "ff.h"
  10. #include "lcd.h"
  11. #define FLASH_APP_ADDR                0x08010000          //第一个应用程序起始地址(存放在FLASH)
  12. #define STM_PAGE_SIZE                2048                        //注意:STM32F103ZET6的FLASH页大小为2K
  13. //************************************************************************************
  14. //全局变量声明
  15. FATFS Fs;
  16. FIL file;     
  17. BYTE buffer[STM_PAGE_SIZE]; 
  18. FRESULT res;        
  19. UINT br;        
  20. typedef  void (*fun)(void);                                //定义一个函数类型的参数.   
  21. fun AppStart; 
  22. /*************************************************************************************
  23. 函数名  :Jump2App
  24. 功    能:从Bootloader跳转到用户APP程序地址空间
  25. 入口参数:Addr,用户APP的起始执行地址
  26. 出口参数:无
  27. 返回值  :无
  28. *************************************************************************************/
  29. void Jump2App(u32 Addr)
  30. {
  31.         if(((*(vu32*)Addr)&0x2FFE0000) == 0x20000000)        //检查栈顶地址是否合法.
  32.         { 
  33.                 AppStart = (fun)(*(vu32*)(Addr+4));                        //用户代码区第二个字为程序开始地址(复位地址)                
  34.                 AppStart();                                                                        //跳转到APP.
  35.         }
  36. }                 
  37. /*************************************************************************************
  38. 函数名  :FirmwareUpdate
  39. 功    能:固件升级函数
  40. 入口参数:无
  41. 出口参数:无
  42. 返回值  :无
  43. ***************************************************************************************/
  44. void FirmwareUpdate(void)
  45. {
  46. int PageOffest = 0;                //页偏移,从APP的基地址到当前页起始位置的字节总数
  47. int ByteOffest;                        //当前页内的字节偏移,从当前操作页的起始位置到正在写入位置的字节偏移
  48. int a, b;
  49. u8 i = 0;
  50.         /*首先初始化SD卡*/
  51.         if(0 != disk_initialize(0))        return;
  52.         /*接着挂载文件系统对象*/
  53.         f_mount(0, &Fs);
  54.         /*查找是否存在要升级的BIN文件*/
  55.         res = f_open(&file, "RTC.bin", FA_OPEN_EXISTING | FA_READ);
  56.         if(FR_OK != res) return;
  57.         /*绘制进度条边框*/
  58.         LCD_DrawRectangle(50, 225, 250, 255);
  59.         /*初始化临时变量*/
  60.         a = file.fsize / 100;  //100表示将进度条平均分成100份,由于进度条长度为200个像素,所以1份占用2个像素
  61.         a &= 0xfffffffe;           //将文件平均分成100份,所以a表示一份文件所占的字节数,为确保该字节数为偶数,故做此转换
  62.         b = 0;                                   //b表示当前已经更新了多少字节
  63.         /*执行主要的IAP功能*/
  64.         while(1)
  65.         {
  66.                 /*每次读取一个页的数据到内存缓冲区,注意:STM32F103ZE的页大小为2K*/
  67.             res = f_read(&file, buffer, STM_PAGE_SIZE, &br);
  68.             if (res || br == 0) break;   
  69.                 /*然后就是永恒的4步骤:解锁、擦除、更新、上锁*/
  70.                 FLASH_Unlock();
  71.                 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
  72.                 FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);
  73.                 for(ByteOffest = 0; ByteOffest < STM_PAGE_SIZE; ByteOffest += 2)
  74.                 {
  75.                         /*更新FLASH,注意当前操作的实际位置:APP基地址FLASH_APP_ADDR+页偏移字节PageOffest+当前页内的字节偏移ByteOffest*/
  76.                         FLASH_ProgramHalfWord(FLASH_APP_ADDR + PageOffest + ByteOffest, *(u16*)(buffer + ByteOffest));
  77.                         
  78.                         b += 2;
  79.                         /*更新显示进度条,(b % a == 0)的目的是确保当前正好写完1份文件*/
  80.                         if(b % a == 0)
  81.                         {
  82.                                 LCD_Fill(50, 225, 50 + 2 * (b / a), 255, 0x7e0); //(b / a)表示已经写了几份文件
  83.                         }
  84.                 } 
  85.                 FLASH_Lock();
  86.                 PageOffest += STM_PAGE_SIZE;
  87.                 /*每更新完1页,让LED状态翻转一次*/
  88.                 i = !i;
  89.                 if(i)
  90.                         GPIO_SetBits(GPIOB, GPIO_Pin_5);
  91.                 else
  92.                         GPIO_ResetBits(GPIOB, GPIO_Pin_5);
  93.         }
  94.         /*关闭文件,卸载文件系统*/
  95.         f_close(&file);
  96.         f_mount(0, 0);
  97. }
  98. /************************************************************************************
  99. 函数名  :main
  100. 功    能:主程序入口函数
  101. 入口参数:无
  102. 出口参数:无
  103. 返回值  :int
  104. *************************************************************************************/
  105. int main(void)
  106. {
  107.         SystemInit();
  108.         delay_init(72);
  109.         LED_Init();
  110.         LCD_Init();
  111.         FirmwareUpdate();
  112.         Jump2App(FLASH_APP_ADDR);
  113.         while(1);
  114. }

 

还要注意的地方:用户程序是放在FLASH地址0x08010000的位置的,而且该代码只识别SD卡根目录下的RTC.bin文件,如果要更改文件名,则只需将FirmwareUpdate函数中的“RTC.bin”文件改成你要升级的文件即可。

永不止步步 发表于11-03 09:57 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:308117个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号