• 将STM32 内部Flash虚拟成优盘,进行IAP升级


            书接上回,上篇文章已经成功的将 STM32 内部FLASH虚拟成优盘进行文件存储了。

    【将 STM32 内部Flash虚拟成优盘】icon-default.png?t=M85Bhttps://blog.csdn.net/qq_44810226/article/details/127508789

            然后我们开始固件升级流程:

           

     从上图可以看出,固件存储的位置是不知道的,不确定的,但是一定在U盘存储的区域内。

            我们可以通过给bin文件加上一些标志,来在Flash中判断是否有固件存在。如下图所示,给bin文件开头添加 固件名称、软件版本、硬件版本、起始地址、校验位、长度等数据。

     

    因为FAT系统存储的特性,每个文件都会在扇区的开头存储,我们设置的扇区大小为0x200,所以我们可以在U盘开始的地址来遍历,搜索每个地址的前几个字符是否为我们想要固件的名称。

    1. /*************************************************************
    2. ** Function name: FindBinFileAddr
    3. ** Descriptions: 在指定地址查找是否有固件存在
    4. ** Input parameters: None
    5. ** Output parameters: None
    6. ** Returned value: 固件地址 或者 0(没有找到)
    7. ** Remarks: None
    8. *************************************************************/
    9. uint32_t FindBinFileAddr(void){
    10. unsigned char tempBuff[14] = {0};
    11. for(uint16_t i=40;i
    12. memcpy(tempBuff, (char *)(MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ)), sizeof(tempBuff)-1);
    13. if (strcmp(tempBuff, BIN_START_FLAG) == 0){
    14. SEGGER_RTT_printf(0,"Find Fw StartName in[%x] USB-Device Sector %d-> %s\r\n",(MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ)),i,tempBuff);
    15. return (MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ));
    16. }
    17. }
    18. SEGGER_RTT_printf(0,"Not Find Fw !!!\r\n");
    19. return 0;
    20. }

    这里还可以先判断一下固件的其他描述参数,判断固件是否有效,也可以在后面判断。

    找到固件之后就可以进行正常升级了。

    找到合适的固件之后,判断固件是否有效:通过名称、CRC、版本号等

    这里我将升级用到的参数都做到了一个 结构体中,方便后面写代码。PUpdateFw_Struct 是这个结构体的指针。

    1. UPDATE_Frameware_INIT(gFWUpdate,0x08050600,0x08019000,50,STMFLASH_ReadByte,STMFLASH_Write,2048);

    .c文件 

    1. /*************************************************************
    2. ** Function name: FWInit
    3. ** Descriptions: 固件升级 初始化
    4. ** Input parameters: None
    5. ** Output parameters: None
    6. ** Returned value: None
    7. ** Remarks: None
    8. *************************************************************/
    9. uint8_t FWUpdateInit(PUpdateFw_Struct fw){
    10. uint16_t checkCRC = 0;
    11. memcpy(fw->info_fwName,(uint8_t *)(fw->fwAddr),FW_NAME_LENGTH);
    12. memcpy(fw->info_fwVersion,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH),FW_VERSION_LENGTH);
    13. memcpy(&fw->info_fwLength,(uint32_t *)(fw->fwAddr+FW_NAME_LENGTH+FW_VERSION_LENGTH),4);
    14. memcpy(fw->info_boardVersion,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH+FW_VERSION_LENGTH+4),FW_VERSION_LENGTH);
    15. memcpy(&fw->info_crc,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH+2*FW_VERSION_LENGTH+4+4),sizeof(uint16_t));
    16. memcpy(fw->info_binEndFlag,(uint8_t *)(fw->fwAddr+48+fw->info_fwLength),BIN_END_FLAG_LENGTH);
    17. checkCRC = usMBCRC16((unsigned char *)(fw->fwAddr+48),fw->info_fwLength);
    18. if (strcmp(fw->info_fwName, BIN_START_FLAG) != 0){
    19. SEGGER_RTT_printf(0,"fw name is err ! not a effective firmware ... \r\n");
    20. return 0;
    21. }
    22. if (strcmp(fw->info_binEndFlag, BIN_END_FLAG) != 0){
    23. SEGGER_RTT_printf(0,"fw end name is err ! not a effective firmware ... \r\n");
    24. return 0;
    25. }
    26. if (checkCRC != fw->info_crc){
    27. SEGGER_RTT_printf(0,"crc check is err ! not a effective firmware ... \r\n");
    28. return 0;
    29. }
    30. SEGGER_RTT_printf(0," Firmware effective : name-> %s \r\n",fw->info_fwName);
    31. SEGGER_RTT_printf(0," Version-> %d.%d.%d.%d\r\n",fw->info_fwVersion[0],fw->info_fwVersion[2],fw->info_fwVersion[4],fw->info_fwVersion[6]);
    32. SEGGER_RTT_printf(0," FileLength-> %x\r\n",fw->info_fwLength);
    33. SEGGER_RTT_printf(0," BoardVersion-> %d.%d.%d.%d\r\n",fw->info_boardVersion[0],fw->info_boardVersion[2],fw->info_boardVersion[4],fw->info_boardVersion[6]);
    34. // crc 检测
    35. SEGGER_RTT_printf(0," FileCRC-> %x\r\n",fw->info_crc);
    36. SEGGER_RTT_printf(0," CheckCRC-> %x \r\n",checkCRC);
    37. SEGGER_RTT_printf(0," FileEndName-> [%p] %s\r\n",(uint8_t *)(fw->fwAddr+48+fw->info_fwLength),fw->info_binEndFlag);
    38. // 返回是否init成功 如果失败则代表不是一个正常的固件 不可以进行升级
    39. return 1;
    40. }
    41. void (*JumpToApplication)(void);
    42. uint32_t gJumpAddress;
    43. typedef void (*pFunction)(void);
    44. /*************************************************************
    45. ** Function name: FWStartUpdate
    46. ** Descriptions: 开始升级
    47. ** Input parameters: None
    48. ** Output parameters: None
    49. ** Returned value: None
    50. ** Remarks: None
    51. *************************************************************/
    52. void FWStartUpdate(PUpdateFw_Struct fw){
    53. fw->WriteByte(fw->appAddr,(uint32_t *)(fw->fwAddr+48),fw->info_fwLength/8);
    54. SEGGER_RTT_printf(0,"Write FW ok \r\n");
    55. uint32_t erase[2] = {0};
    56. // 破坏APP2 固件存储的地址
    57. fw->WriteByte(fw->fwAddr,erase,1);
    58. SEGGER_RTT_printf(0,"Eares app2 fw ok \r\n");
    59. // 破坏fat结构 上电重新初始化
    60. // fw->WriteByte(MASS_STORAGE_CLASS_START_ADDR,erase,1);
    61. // 跳转到APP
    62. /* Test if user code is programmed starting from address 0x0800C000 */
    63. // 检查栈顶是否合法,确保栈顶落在0x2000 0000 - 0x2001 0000 之间,刚好在stm32f1的RAM范围内
    64. if (((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000) == 0x20000000)
    65. {
    66. SEGGER_RTT_printf(0,"Check ok %x %x %x \r\n",fw->appAddr,(*(__IO uint32_t *)fw->appAddr),((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000));
    67. // 检查reset入口是否正确
    68. // if (((*(uint32_t*)(STM32_APP_BASE + 4)) & 0x0fff0000 ) == 0x08020000 )
    69. /* Jump to user application */
    70. gJumpAddress = *(__IO uint32_t *)(fw->appAddr + 4);
    71. JumpToApplication = (pFunction)gJumpAddress;
    72. /* Reset of all peripherals */
    73. HAL_DeInit();
    74. /* Set interrupt vector to app code */
    75. SCB->VTOR = fw->appAddr;
    76. /* Initialize user application's Stack Pointer */
    77. __set_MSP(*(__IO uint32_t *)fw->appAddr);
    78. __disable_irq();
    79. JumpToApplication();
    80. }else{
    81. SEGGER_RTT_printf(0,"Check err %x %x %x \r\n",fw->appAddr,(*(__IO uint32_t *)fw->appAddr),((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000));
    82. }
    83. }

     .h文件

    1. // 写入前先检查 是不是所有位置都可以写入:即是不是0xff 如果不是则擦除所在位置
    2. struct SUpdateFw_Struct {
    3. // 固件存放地址
    4. uint32_t fwAddr;
    5. // 写入地址:APP1地址
    6. uint32_t appAddr;
    7. // APP1所在区块
    8. uint16_t appSector;
    9. // 读取函数
    10. uint8_t (*ReadOneByte)(uint32_t addr);
    11. // 写入函数
    12. void (*WriteByte)(uint32_t addr,uint32_t *data, uint32_t num);
    13. // Flash Sector 大小
    14. uint16_t sectorSize;
    15. // 固件Info
    16. char info_fwName[FW_NAME_LENGTH+1];
    17. // 固件版本信息
    18. char info_fwVersion[FW_VERSION_LENGTH+1];
    19. // 固件长度
    20. uint32_t info_fwLength;
    21. char info_boardVersion[FW_VERSION_LENGTH+1];
    22. // info中的起始地址
    23. uint32_t info_startAddr;
    24. // 固件Info
    25. uint16_t info_crc;
    26. char info_binEndFlag[BIN_END_FLAG_LENGTH+1];
    27. };
    28. typedef struct SUpdateFw_Struct UpdateFw_Struct;
    29. typedef UpdateFw_Struct *PUpdateFw_Struct;
    30. // 固件存放地址、写入地址:APP1地址、 APP1所在区块、 读取函数、 写入函数、 Flash Sector 大小
    31. #define UPDATE_Frameware_INIT(xname,xfwAddr,xappAddr,xappSector,xReadOneByte,xWriteByte,xsectorSize) \
    32. UpdateFw_Struct xname = { \
    33. .fwAddr = xfwAddr, \
    34. .appAddr = xappAddr, \
    35. .appSector = xappSector, \
    36. .ReadOneByte = xReadOneByte, \
    37. .WriteByte = xWriteByte, \
    38. .sectorSize = xsectorSize, \
    39. .info_fwName = {0}, \
    40. .info_fwVersion = {0}, \
    41. .info_fwLength = 0, \
    42. .info_boardVersion = {0}, \
    43. .info_startAddr = 0, \
    44. .info_crc = 0, \
    45. .info_binEndFlag = {0}, \
    46. };

     

     这里程序参考意义不大,可能指针会有点难看。我将整个代码放在csdn中,需要的同学可以下载学习。

     

  • 相关阅读:
    消息队列三|Kafka 如何做到高可用?
    Vite 设置 build 之后项目的相对路径,而不是绝对路径 base
    MATLAB实战 | 粮食储仓的通风控制问题
    Kafka生产者之分区
    SSM+网上订餐系统 毕业设计-附源码221558
    20K+ SRE面试题分享
    Python数据分析与机器学习34-DBSCAN实例
    【爬虫进阶】猿人学任务六之回溯(难度3.0)
    如何通俗理解海涅定理
    Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)
  • 原文地址:https://blog.csdn.net/qq_44810226/article/details/127546606