新疆网站建设/百度上怎么做推广
书接上回,上篇文章已经成功的将 STM32 内部FLASH虚拟成优盘进行文件存储了。
【将 STM32 内部Flash虚拟成优盘】https://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<BLOCKNUM;i++){memcpy(tempBuff, (char *)(MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ)), sizeof(tempBuff)-1);if (strcmp(tempBuff, BIN_START_FLAG) == 0){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);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中,需要的同学可以下载学习。