历史上的今天
返回首页

历史上的今天

今天是:2024年11月10日(星期日)

正在发生

2020年11月10日 | SD卡升级——SDIO_IAP实验

2020-11-10 来源:eefocus

     在嵌入式项目中,经常会用到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. /*****************************************************************************************************

  2. 文件名  :main.c


  3. 文件描述:程序执行的主要文件,不用说也明白


  4. 创建人  :何小龙

  5.                   博客:http://blog.csdn.net/hexiaolong2009


  6. 创建时间:2012.05.16


  7. 更改历史:2012.05.29


  8. *****************************************************************************************************/

  9. #include "stm32f10x.h"

  10. #include "delay.h"

  11. #include "LED.h"

  12. #include "diskio.h"

  13. #include "ff.h"

  14. #include "lcd.h"


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

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




  17. //****************************************************************************************************

  18. //全局变量声明

  19. FATFS Fs;

  20. FIL file;     

  21. BYTE buffer[STM_PAGE_SIZE]; 

  22. FRESULT res;        

  23. UINT br;        


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

  25. fun AppStart; 


  26. /*****************************************************************************************************

  27. 函数名  :Jump2App


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


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


  30. 出口参数:无


  31. 返回值  :无

  32. *****************************************************************************************************/

  33. void Jump2App(u32 Addr)

  34. {

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

  36.         { 

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

  38.                 AppStart();                                                                        //跳转到APP.

  39.         }

  40. }                 



  41. /*****************************************************************************************************

  42. 函数名  :FirmwareUpdate


  43. 功    能:固件升级函数


  44. 入口参数:无


  45. 出口参数:无


  46. 返回值  :无

  47. *****************************************************************************************************/

  48. void FirmwareUpdate(void)

  49. {

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

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

  52. int a, b;

  53. u8 i = 0;


  54.         /*首先初始化SD卡*/

  55.         if(0 != disk_initialize(0))        return;


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

  57.         f_mount(0, &Fs);


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

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

  60.         if(FR_OK != res) return;


  61.         /*绘制进度条边框*/

  62.         LCD_DrawRectangle(50, 225, 250, 255);


  63.         /*初始化临时变量*/

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

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

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


  67.         /*执行主要的IAP功能*/

  68.         while(1)

  69.         {

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

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

  72.             if (res || br == 0) break;   


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

  74.                 FLASH_Unlock();

  75.                 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

  76.                 FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);

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

  78.                 {

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

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

  81.                         

  82.                         b += 2;


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

  84.                         if(b % a == 0)

  85.                         {

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

  87.                         }

  88.                 } 

  89.                 FLASH_Lock();

  90.                 PageOffest += STM_PAGE_SIZE;


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

  92.                 i = !i;

  93.                 if(i)

  94.                         GPIO_SetBits(GPIOB, GPIO_Pin_5);

  95.                 else

  96.                         GPIO_ResetBits(GPIOB, GPIO_Pin_5);

  97.         }


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

  99.         f_close(&file);

  100.         f_mount(0, 0);

  101. }



  102. /*****************************************************************************************************

  103. 函数名  :main


  104. 功    能:主程序入口函数


  105. 入口参数:无


  106. 出口参数:无


  107. 返回值  :int

  108. *****************************************************************************************************/

  109. int main(void)

  110. {

  111.         SystemInit();

  112.         delay_init(72);

  113.         LED_Init();

  114.         LCD_Init();

  115.         FirmwareUpdate();

  116.         Jump2App(FLASH_APP_ADDR);

  117.         while(1);

  118. }


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

    以下是运行效果:
      
      

希望对大家有帮助。

推荐阅读

史海拾趣

Heatron公司的发展小趣事

随着全球对环保和节能问题的日益关注,Heatron公司积极响应号召,致力于研发和生产环保节能的电加热产品。公司投入大量资源于新材料、新技术的研发中,成功推出了一系列低能耗、高效率的加热器产品。这些产品不仅满足了市场对环保节能的需求,还进一步巩固了Heatron在电子行业中的领先地位。

Denyo Europa Gmbh公司的发展小趣事

随着技术的成熟,Denyo Europa Gmbh公司开始将目光投向国际市场。公司利用自身的技术优势,结合对目标市场的深入调研,制定了一系列市场拓展策略。通过与当地合作伙伴的紧密合作,公司成功将产品打入多个国家和地区,实现了业务的全球化布局。这一过程中,公司不仅积累了宝贵的国际市场经验,也为公司的持续发展奠定了坚实基础。

Custom Components Inc公司的发展小趣事

在电子行业快速发展的背景下,客户对电子元件的定制化需求日益增长。CCI敏锐地捕捉到了这一市场趋势,迅速调整战略方向,将业务重心转向客户定制化服务。

为了满足客户多样化的需求,CCI加强了与客户的沟通与合作,深入了解客户的具体需求和应用场景。公司不仅提供标准产品,还能根据客户的特殊需求进行定制化设计和生产。这种服务模式赢得了客户的广泛认可,CCI的市场份额也随之稳步提升。

BB公司的发展小趣事

2000年,BB公司迎来了发展史上的一个重要时刻——被美国德州仪器公司收购。这一收购对于BB公司来说,既是挑战也是机遇。德州仪器作为全球领先的半导体公司,为BB公司提供了更广阔的平台和更丰富的资源。在德州仪器的支持下,BB公司得以继续深化技术创新和市场拓展,进一步提升了其在电子行业的地位。

亿晶源(ekinglux)公司的发展小趣事

在不断提升产品质量和创新能力的同时,亿晶源还积极拓展市场。公司先后在华南、华东等地区设立生产基地和销售中心,形成了覆盖全国的销售网络。同时,公司还注重品牌建设,通过参加国内外知名展会、举办技术交流会等活动,提升品牌知名度和影响力。

Aristo-Craft/ L M P Inc公司的发展小趣事

随着公司产品的不断升级和优化,Aristo-Craft/L M P Inc开始积极寻求市场拓展的机会。他们不仅在国内市场建立了稳定的销售渠道,还通过参加国际展会、与海外企业建立合作关系等方式,成功打入国际市场。同时,公司还积极寻求与其他行业领导者的战略合作,共同推动电子行业的发展。

问答坊 | AI 解惑

(转)dsp学习 要点

年初到现在,接触DSP已经半年了,由于公司没有人指导,做了这么久都没出什么大的成果,也走了不少的弯路。以前做单片机用C编过一些程序,个人觉得还可以。现在看来也只是在吃以前在学校里面一些C语言皮毛的老本,加上一些网上说的所谓的技巧什么的结合以 ...…

查看全部问答>

用什么也别用害人的红外一体机!(转)

转自:http://www.1000bbs.com/dispbbs.asp?boardid=51&Id=261604 首先声明一下身份:辽宁锦州安防器材经销商、工程商。 我开始选择红外一体机,是因为甲方点着名要这玩意。 选了哪些厂家的哪些型号的红外机,恕我不一一列举了。总之,深圳的、 ...…

查看全部问答>

航模电机

用51怎样驱动航模直升机的电机,需要电流太大2-3A,一般驱动板太大了,而且电流达不到,请问有什么好办法,能否用MOS管或晶闸管,做开关管?先谢谢了…

查看全部问答>

准备开NO.3方案

准备开第三种方案,做一个便携式的温度湿度检测计 大家可以看看我的方案,我主要想做一个便携式的,袖珍型的,可以挂在钥匙圈上的,所以尽量的简单,C8051F系列中选一款单片机,特点就是简单方便性能强大,再加上湿度传感器芯片和LCD液晶即可 &nb ...…

查看全部问答>

如何确认PPP链接已经建立成功?请高手指点!谢谢!

各位大虾,我采用了sim300d gprs模块,北京的神州行wap gprs 卡,通过ppp协议来连接cmwap,现在通过了pap验证,可以拿到ISP server的ip address和分配的本地ip address。有几个问题:   1,如何自动获取dns。如果在ipcp请求中请求分配dn ...…

查看全部问答>

verilog中的task 可以在定义的模块之外调用么?

例如 taskA 在moduleA中定义, 而moduleB与moduleA有可能是嵌套关系,也可能是并列的被高层模块调用,那么moduleB能调用taskA么?…

查看全部问答>

救急。。。。救急。。。 谢谢大家。。。。急急。。。

我是新手  刚开始做 windows CE 的程序。再部署的时候报了个 这样的错误 。。请教各位 errmessage : 指定的文件不是有效的 CE 引导映像 。。。 内部签名丢失 或者 节长度或校验和 不正确。。。 请教各位  这是怎么回事& ...…

查看全部问答>

msp430f149栈溢出的问题

大家好,我在编译一个代码出现了栈溢出警告, 理论上讲我的数据段为: map文件 6 152 bytes of CODE  memory 1 268 bytes of DATA  memory (+ 56 absolute )   463 bytes of CONST memory   而栈的使用情况 ...…

查看全部问答>

MSP430PWM脉冲占空比调节LED光亮

/*实验板 MSP430 LaunchPad * 利用定时器编写PWM电路,驱动LED,并可以通过按键调节亮度 * MCLK=SMCLK=DCOCLK=32×ACLK=1.048576MHz, */ #include void main(void) { P1DIR |= BIT6+BIT0; P1DIR &=~BIT3;     &nb ...…

查看全部问答>