将STM32 内部Flash虚拟成优盘,进行IAP升级
创始人
2024-04-01 00:08:06
0

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

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

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

       

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

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

 

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

/*************************************************************
** Function name:       FindBinFileAddr
** Descriptions:        在指定地址查找是否有固件存在
** Input parameters:    None
** Output parameters:   None
** Returned value:      固件地址 或者 0(没有找到)
** Remarks:             None
*************************************************************/
uint32_t FindBinFileAddr(void){unsigned char tempBuff[14] = {0};for(uint16_t i=40;i   %s\r\n",(MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ)),i,tempBuff);return (MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ));} }SEGGER_RTT_printf(0,"Not Find Fw !!!\r\n");return 0;
}

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

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

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

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


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

.c文件 

/*************************************************************
** Function name:       FWInit
** Descriptions:        固件升级 初始化
** Input parameters:    None
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
uint8_t FWUpdateInit(PUpdateFw_Struct fw){uint16_t checkCRC = 0;memcpy(fw->info_fwName,(uint8_t *)(fw->fwAddr),FW_NAME_LENGTH);memcpy(fw->info_fwVersion,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH),FW_VERSION_LENGTH);memcpy(&fw->info_fwLength,(uint32_t *)(fw->fwAddr+FW_NAME_LENGTH+FW_VERSION_LENGTH),4);memcpy(fw->info_boardVersion,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH+FW_VERSION_LENGTH+4),FW_VERSION_LENGTH);memcpy(&fw->info_crc,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH+2*FW_VERSION_LENGTH+4+4),sizeof(uint16_t));memcpy(fw->info_binEndFlag,(uint8_t *)(fw->fwAddr+48+fw->info_fwLength),BIN_END_FLAG_LENGTH);checkCRC = usMBCRC16((unsigned char *)(fw->fwAddr+48),fw->info_fwLength);if (strcmp(fw->info_fwName, BIN_START_FLAG) != 0){SEGGER_RTT_printf(0,"fw name is err ! not a effective firmware ... \r\n");return 0;}if (strcmp(fw->info_binEndFlag, BIN_END_FLAG) != 0){SEGGER_RTT_printf(0,"fw end name is err ! not a effective firmware ... \r\n");return 0;}if (checkCRC != fw->info_crc){SEGGER_RTT_printf(0,"crc check is err ! not a effective firmware ... \r\n");return 0;}SEGGER_RTT_printf(0,"   Firmware effective  : name-> %s  \r\n",fw->info_fwName);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]);SEGGER_RTT_printf(0,"   FileLength-> %x\r\n",fw->info_fwLength);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]);// crc 检测SEGGER_RTT_printf(0,"   FileCRC-> %x\r\n",fw->info_crc);SEGGER_RTT_printf(0,"   CheckCRC-> %x \r\n",checkCRC);SEGGER_RTT_printf(0,"   FileEndName-> [%p] %s\r\n",(uint8_t *)(fw->fwAddr+48+fw->info_fwLength),fw->info_binEndFlag);// 返回是否init成功 如果失败则代表不是一个正常的固件 不可以进行升级return 1;
}void (*JumpToApplication)(void);
uint32_t gJumpAddress;
typedef  void (*pFunction)(void);/*************************************************************
** Function name:       FWStartUpdate
** Descriptions:        开始升级
** Input parameters:    None
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
void FWStartUpdate(PUpdateFw_Struct fw){fw->WriteByte(fw->appAddr,(uint32_t *)(fw->fwAddr+48),fw->info_fwLength/8);SEGGER_RTT_printf(0,"Write FW ok \r\n");uint32_t erase[2] = {0};// 破坏APP2 固件存储的地址 fw->WriteByte(fw->fwAddr,erase,1);SEGGER_RTT_printf(0,"Eares app2 fw ok \r\n");// 破坏fat结构 上电重新初始化// fw->WriteByte(MASS_STORAGE_CLASS_START_ADDR,erase,1);// 跳转到APP/* Test if user code is programmed starting from address 0x0800C000 */// 检查栈顶是否合法,确保栈顶落在0x2000 0000 - 0x2001 0000 之间,刚好在stm32f1的RAM范围内if (((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000) == 0x20000000){SEGGER_RTT_printf(0,"Check ok %x  %x  %x \r\n",fw->appAddr,(*(__IO uint32_t *)fw->appAddr),((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000));// 检查reset入口是否正确// if (((*(uint32_t*)(STM32_APP_BASE + 4)) & 0x0fff0000 ) == 0x08020000 ) /* Jump to user application */gJumpAddress = *(__IO uint32_t *)(fw->appAddr + 4);JumpToApplication = (pFunction)gJumpAddress;/* Reset of all peripherals */HAL_DeInit();/* Set interrupt vector to app code */SCB->VTOR = fw->appAddr;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t *)fw->appAddr);__disable_irq();JumpToApplication();}else{SEGGER_RTT_printf(0,"Check err %x  %x  %x \r\n",fw->appAddr,(*(__IO uint32_t *)fw->appAddr),((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000));}}

 .h文件

// 写入前先检查 是不是所有位置都可以写入:即是不是0xff  如果不是则擦除所在位置struct SUpdateFw_Struct {// 固件存放地址uint32_t fwAddr;// 写入地址:APP1地址uint32_t appAddr;// APP1所在区块uint16_t appSector;// 读取函数uint8_t (*ReadOneByte)(uint32_t addr);// 写入函数void (*WriteByte)(uint32_t addr,uint32_t *data, uint32_t num);// Flash Sector 大小uint16_t sectorSize;// 固件Infochar info_fwName[FW_NAME_LENGTH+1];// 固件版本信息char info_fwVersion[FW_VERSION_LENGTH+1];// 固件长度uint32_t info_fwLength;char info_boardVersion[FW_VERSION_LENGTH+1];// info中的起始地址uint32_t info_startAddr;// 固件Infouint16_t info_crc;char info_binEndFlag[BIN_END_FLAG_LENGTH+1];
};
typedef struct SUpdateFw_Struct UpdateFw_Struct;
typedef UpdateFw_Struct *PUpdateFw_Struct;//                              固件存放地址、写入地址:APP1地址、 APP1所在区块、 读取函数、 写入函数、  Flash Sector 大小
#define UPDATE_Frameware_INIT(xname,xfwAddr,xappAddr,xappSector,xReadOneByte,xWriteByte,xsectorSize)     \
UpdateFw_Struct xname = {                                                 \.fwAddr = xfwAddr,                                  \.appAddr = xappAddr,                                \.appSector = xappSector,                            \.ReadOneByte = xReadOneByte,                        \.WriteByte = xWriteByte,                            \.sectorSize = xsectorSize,                          \.info_fwName = {0},                                 \.info_fwVersion = {0},                              \.info_fwLength = 0,                                 \.info_boardVersion = {0},                           \.info_startAddr = 0,                                \.info_crc = 0,                                      \.info_binEndFlag = {0},                             \
};

 

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

 

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...