STM32 BootLoader升级固件

嵌入式设计应用

132人已加入

描述

  Bootloader应该是每个成熟产品都必须具备的功能,有了它,我们不用担心产品销售出去后发现产品固件有问题而无法解决的问题,有了Bootloader功能,我们可以非常方便的升级更新我们产品的固件!

  该方案主要是基于USB HID协议实现的Bootloader,其升级操作流程如下动画所示:

  bootloader

  功能简介:

  1,通过USB HID实现数据的传输,该方案也同时集成了USB键盘的功能;

  2,App固件传输是经过AES加密的,可以防止非法人员窃取固件;

  3,在开始升级固件之前,对固件文件进行严格检测,防止客户选择错误文件;

  4,升级操作非常简单,无需在设备上做任何其他的操作,连接USB之后,只需要在软件上选择固件,再点击升级固件按钮即可;

  5,固件烧写完成后使用MD5算法对固件进行校验,防止数据出错而导致升级失败;

  6,固件升级完成之后,无需断电重启;

  实际上,在STM32系列的单片机中,Flash本身就是分扇区的,一个扇区16KB的样子,具体可以查看手册。那么就可以用从第一个扇区的首地址开始下载BootLoader的程序,而从第二个扇区的起始地址开始下载APP程序。如下为STM32F4系列芯片的Flash模块。

  单片机上电之后开始执行BootLoader程序,这是单片机会检测用户是否有升级应用程序(APP)的请求,具体表现有很多种,例如检测内存卡,Nand Flash中是否包含升级文件,串口/I2C/SPI等外设接口是否传来升级文件。据说还有使用GSM来升级的。

  所谓的升级,就是将ROM/Flash中存储APP程序的扇区内容擦除并写入新文件。例如一次固件升级的过程可以是:1、单片机上电执行BootLoader,2、BootLoader查找升级文件,3、若找到文件,擦除Flash中的部分扇区(存APP的),4、在擦除的扇区写入升级的文件,5、写入完成,读取数据检验是否出错,6、若数据一致,升级成功,删除升级文件,7、BootLoader程序跳转到APP程序执行。删除升级文件是为了下次上电后不再进行升级。

  所谓的跳转,可以理解程序指针的改变,变为指向APP程序扇区的起始地址

  部分代码

  1、主函数

  int main(void) { HAL_Init();//STM32初始化 SystemClock_Config();//时钟配置 System_GPIOInit();//IO口配置 #ifdef BOOTLOAD_DISPLAY_ENABLE SystemColorInit();//显示屏配置 #endif System_LoadUpdateFile();//升级函数 while (1) { } }

  2、升级函数

  void System_LoadUpdateFile(void) { uint8_t res; if(bNandFlash_Error)//如果NandFlash错误,串口打印错误信息,跳转到用户程序 { d_printf(“NandFlash_Error jump\n”); BootLoad_Jump();//跳转函数 return; } if(bNo_FileSystem)//如果没有文件系统,串口打印错误信息,跳转到用户程序 { d_printf(“no file system jump\n”); BootLoad_Jump();//跳转函数 return; } if(f_open(&File, (char *)UPDATE_FILE_PATH, FA_READ)==FR_OK)//如果存在升级文件,开始执行升级 { d_printf(“update\n”); if(BootLoad_Program())//是否写入成功 { f_close(&File);//关闭升级文件 res=f_unlink((char *)UPDATE_FILE_PATH);//删除升级文件 d_printfhex(res);d_printf(“\n”); res=f_unlink((char *)UPDATE_DIR_PATH);//删除升级目录 d_printfhex(res);d_printf(“\n”); BootLoad_Jump();//跳转函数 } else { HAL_FLASH_Lock();//锁定Flash d_printf(“update fail\n”); f_close(&File);//关闭升级文件 BootLoad_Jump();//跳转函数 } } else { d_printf(“jump\n”); f_close(&File); BootLoad_Jump(); } }

  3、重写Flash函数

  uint8_t BootLoad_Program(void) { uint32_t BaseAddress=APPLICATION_ADDRESS;//APP地址 uint32_t i,br,datacnt=0; uint8_t data8; GlobalPtr32=(uint32_t *)BootBuff; HAL_FLASH_Unlock();//解锁Flash if(BootLoad_Erase()==false)//擦除Flash { return false; } d_printf(“size:”);d_printfhex32(File.fsize);d_printf(“\n”); while(1) { f_read(&File,BootBuff,8192,(void *)&br);//读取升级文件 for (i=0;i《(br》》2);i++) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, BaseAddress, GlobalPtr32[i]) == HAL_OK)//写入升级文件 { BaseAddress = BaseAddress +4; } else { d_printf(“program err\n”); return false; } } datacnt+=br; if(datacnt》=File.fsize)//写入完成 { break; } } d_printf(“verify\n”); //验证Flash中的内容与升级文件是否一致 f_lseek(&File,0); //若一致代表升级成功 datacnt=0; //若不一致代表升级失败 BaseAddress=APPLICATION_ADDRESS; while(1) { f_read(&File,BootBuff,8192,(void *)&br); for (i=0;i《br;i++) { data8 = *(__IO uint8_t*)BaseAddress; if (data8 != BootBuff[i]) { d_printf(“error!\n”); return false; } BaseAddress ++; } datacnt+=br; if(datacnt》=File.fsize) { break; } } HAL_FLASH_Lock();//锁定Flash return true; }

  4、跳转函数(从BootLoader中跳转到APP的main函数)

  void BootLoad_Jump(void) { /* Check Vector Table: Test if user code is programmed starting from address “APPLICATION_ADDRESS” */ d_printfhex32((*(__IO uint32_t*)APPLICATION_ADDRESS));d_printf(“\n”); if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS +4); d_printfhex32(JumpAddress);d_printf(“\n”); HAL_Delay(100); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application‘s Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); Jump_To_Application(); } }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分