加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

SD卡升级――SDIO_IAP实验

发布时间:2020-12-15 17:41:52 所属栏目:百科 来源:网络整理
导读:在嵌入式项目中,经常会用到SD卡升级这一方式来进行产品的软件升级。刚好最近做的项目也需要这一功能,由于之前未接触过IAP开发,刚好在这个时候可以学习一下,于是先到各大网站去搜索相关资料,两天下来,基本对于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.硬件:正点原子超级战舰开发板,由于购买时配套的3.5寸触摸屏,对于3.5以下的屏为测试过,但应该没问题,因为LCD驱动用的还是原子哥的驱动,是兼容2.4到3.5的。SanDisk 1G SD卡, MicroSD 2G。注意:要使用超级战舰开发板上的SDIO功能,必须将开发板上的P10跳线帽接到P11上,因为原子的SD卡驱动默认使用SPI接口的,所以这里必须要设置!
? ?2.软件:ST官方库V3.0的,比较老了。
? FatFs文件系统,注意:本人在ff.h配置中将宏_FS_READONLY配置为1,即只生成读操作的代码,不编译写操作的代码,目的是为了减小
? bootloader的代码量,包括原子哥的LCD.C中的代码也删减了很多。
? ?下面就将主要的源代码贴出,供大家参考。

  1. #include "stm32f10x.h"

  2. #include "delay.h"

  3. #include "LED.h"

  4. #include "diskio.h"

  5. #include "ff.h"

  6. #include "lcd.h"


  7. #define FLASH_APP_ADDR ? ? ? ? ? ? ? ?0x08010000 ? ? ? ? ?//第一个应用程序起始地址(存放在FLASH)

  8. #define STM_PAGE_SIZE ? ? ? ? ? ? ? ?2048 ? ? ? ? ? ? ? ? ? ? ? ?//注意:STM32F103ZET6的FLASH页大小为2K




  9. //****************************************************************************************************

  10. //全局变量声明

  11. FATFS Fs;

  12. FIL file; ? ?

  13. BYTE buffer[STM_PAGE_SIZE];

  14. FRESULT res; ? ? ? ?

  15. UINT br; ? ? ? ?


  16. typedef ?void (*fun)(void); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//定义一个函数类型的参数. ?

  17. fun AppStart;


  18. /*****************************************************************************************************

  19. 函数名 ?:Jump2App


  20. 功 ? ?能:从Bootloader跳转到用户APP程序地址空间


  21. 入口参数:Addr,用户APP的起始执行地址


  22. 出口参数:无


  23. 返回值 ?:无

  24. *****************************************************************************************************/

  25. void Jump2App(u32 Addr)

  26. {

  27. ? ? ? ?if(((*(vu32*)Addr)&0x2FFE0000) == 0x20000000) ? ? ? ?//检查栈顶地址是否合法.

  28. ? ? ? ?{

  29. ? ? ? ? ? ? ? ?AppStart = (fun)(*(vu32*)(Addr+4)); ? ? ? ? ? ? ? ? ? ? ? ?//用户代码区第二个字为程序开始地址(复位地址) ? ? ? ? ? ? ?

  30. ? ? ? ? ? ? ? ?AppStart(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//跳转到APP.

  31. ? ? ? ?}

  32. } ? ? ? ? ? ? ? ?



  33. /*****************************************************************************************************

  34. 函数名 ?:FirmwareUpdate


  35. 功 ? ?能:固件升级函数


  36. 入口参数:无


  37. 出口参数:无


  38. 返回值 ?:无

  39. *****************************************************************************************************/

  40. void FirmwareUpdate(void)

  41. {

  42. int PageOffest = 0; ? ? ? ? ? ? ? ?//页偏移,从APP的基地址到当前页起始位置的字节总数

  43. int ByteOffest; ? ? ? ? ? ? ? ? ? ? ? ?//当前页内的字节偏移,从当前操作页的起始位置到正在写入位置的字节偏移

  44. int a,b;

  45. u8 i = 0;


  46. ? ? ? ?/*首先初始化SD卡*/

  47. ? ? ? ?if(0 != disk_initialize(0)) ? ? ? ?return;


  48. ? ? ? ?/*接着挂载文件系统对象*/

  49. ? ? ? ?f_mount(0,&Fs);


  50. ? ? ? ?/*查找是否存在要升级的BIN文件*/

  51. ? ? ? ?res = f_open(&file,"RTC.bin",FA_OPEN_EXISTING | FA_READ);

  52. ? ? ? ?if(FR_OK != res) return;


  53. ? ? ? ?/*绘制进度条边框*/

  54. ? ? ? ?LCD_DrawRectangle(50,225,250,255);


  55. ? ? ? ?/*初始化临时变量*/

  56. ? ? ? ?a = file.fsize / 100; ?//100表示将进度条平均分成100份,由于进度条长度为200个像素,所以1份占用2个像素

  57. ? ? ? ?a &= 0xfffffffe; ? ? ? ? ? //将文件平均分成100份,所以a表示一份文件所占的字节数,为确保该字节数为偶数,故做此转换

  58. ? ? ? ?b = 0; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //b表示当前已经更新了多少字节


  59. ? ? ? ?/*执行主要的IAP功能*/

  60. ? ? ? ?while(1)

  61. ? ? ? ?{

  62. ? ? ? ? ? ? ? ?/*每次读取一个页的数据到内存缓冲区,注意:STM32F103ZE的页大小为2K*/

  63. ? ? ? ? ? ?res = f_read(&file,buffer,STM_PAGE_SIZE,&br);

  64. ? ? ? ? ? ?if (res || br == 0) break; ?


  65. ? ? ? ? ? ? ? ?/*然后就是永恒的4步骤:解锁、擦除、更新、上锁*/

  66. ? ? ? ? ? ? ? ?FLASH_Unlock();

  67. ? ? ? ? ? ? ? ?FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

  68. ? ? ? ? ? ? ? ?FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);

  69. ? ? ? ? ? ? ? ?for(ByteOffest = 0; ByteOffest < STM_PAGE_SIZE; ByteOffest += 2)

  70. ? ? ? ? ? ? ? ?{

  71. ? ? ? ? ? ? ? ? ? ? ? ?/*更新FLASH,注意当前操作的实际位置:APP基地址FLASH_APP_ADDR+页偏移字节PageOffest+当前页内的字节偏移ByteOffest*/

  72. ? ? ? ? ? ? ? ? ? ? ? ?FLASH_ProgramHalfWord(FLASH_APP_ADDR + PageOffest + ByteOffest,*(u16*)(buffer + ByteOffest));


  73. ? ? ? ? ? ? ? ? ? ? ? ?b += 2;


  74. ? ? ? ? ? ? ? ? ? ? ? ?/*更新显示进度条,(b % a == 0)的目的是确保当前正好写完1份文件*/

  75. ? ? ? ? ? ? ? ? ? ? ? ?if(b % a == 0)

  76. ? ? ? ? ? ? ? ? ? ? ? ?{

  77. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?LCD_Fill(50,50 + 2 * (b / a),255,0x7e0); //(b / a)表示已经写了几份文件

  78. ? ? ? ? ? ? ? ? ? ? ? ?}

  79. ? ? ? ? ? ? ? ?}

  80. ? ? ? ? ? ? ? ?FLASH_Lock();

  81. ? ? ? ? ? ? ? ?PageOffest += STM_PAGE_SIZE;


  82. ? ? ? ? ? ? ? ?/*每更新完1页,让LED状态翻转一次*/

  83. ? ? ? ? ? ? ? ?i = !i;

  84. ? ? ? ? ? ? ? ?if(i)

  85. ? ? ? ? ? ? ? ? ? ? ? ?GPIO_SetBits(GPIOB,GPIO_Pin_5);

  86. ? ? ? ? ? ? ? ?else

  87. ? ? ? ? ? ? ? ? ? ? ? ?GPIO_ResetBits(GPIOB,GPIO_Pin_5);

  88. ? ? ? ?}


  89. ? ? ? ?/*关闭文件,卸载文件系统*/

  90. ? ? ? ?f_close(&file);

  91. ? ? ? ?f_mount(0,0);

  92. }



  93. /*****************************************************************************************************

  94. 函数名 ?:main


  95. 功 ? ?能:主程序入口函数


  96. 入口参数:无


  97. 出口参数:无


  98. 返回值 ?:int

  99. *****************************************************************************************************/

  100. int main(void)

  101. {

  102. ? ? ? ?SystemInit();

  103. ? ? ? ?delay_init(72);

  104. ? ? ? ?LED_Init();

  105. ? ? ? ?LCD_Init();

  106. ? ? ? ?FirmwareUpdate();

  107. ? ? ? ?Jump2App(FLASH_APP_ADDR);

  108. ? ? ? ?while(1);

  109. }






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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读