diff --git a/source/User/Inc/bsp.h b/source/User/Inc/bsp.h index 3bfacce..89cfdc4 100644 --- a/source/User/Inc/bsp.h +++ b/source/User/Inc/bsp.h @@ -172,16 +172,16 @@ typedef enum { /*当前设备版本/项目选择*/ #define GATEWAY_VER_INFO GATEWAY_VER1_0 //版本信息 #define GATEWAY_PRJ_NUM GATEWAY_PRJ_YAXIA //项目编号 -#define GATEWAY_GW_NUM 0x0008 //网关编号(2字节, 1~65535) +#define GATEWAY_GW_NUM 0x0000 //网关编号(2字节, 1~65535) /*CAT1服务器/Lora配置 - 替代原MAC_ADDR_TYPE编译宏, 在Boot中直接配置*/ #define GATEWAY_SVR_ADDR0 39 //服务器IP[0] #define GATEWAY_SVR_ADDR1 106 //服务器IP[1] #define GATEWAY_SVR_ADDR2 103 //服务器IP[2] #define GATEWAY_SVR_ADDR3 147 //服务器IP[3] -#define GATEWAY_SVR_PORT 8088 //服务器端口 +#define GATEWAY_SVR_PORT 8080 //服务器端口 -#define GATEWAY_LORA_FREQ CH8 //Lora中心频率(可配置为CH0~CH119) +#define GATEWAY_LORA_FREQ CH0 //Lora中心频率(可配置为CH0~CH119) /*默认通道配置 - 在Boot中直接配置, 替代原APP硬编码默认值*/ #define GATEWAY_MUCH CH_ETH //主上传通道 @@ -191,7 +191,7 @@ typedef enum { /*********************************下载前必须检查配置项************************************/ /*****************************************************************************************/ -/*Flash分区 - 32KB Boot + APP(0x8000起) + 参数区(0x7C000)*/ +/*Flash分区 - 32KB Boot + APP_A区(0x8000,232KB,运行) + APP_B区(0x42000,232KB,升级暂存) + 参数区(0x7C000)*/ #define FLASH_SECTOR_SIZE 0x2000ul //8KB #define FLASH_BASE ((uint32_t)0x00000000) #define FLASH_SIZE (64u * FLASH_SECTOR_SIZE) //512KB @@ -199,10 +199,13 @@ typedef enum { #define SRAM_BASE ((uint32_t)0x1FFF8000) #define SRAM_SIZE 0x2F000ul //192KB -#define BOOT_SIZE (4 * FLASH_SECTOR_SIZE) //32KB -#define APP_ADDRESS (FLASH_BASE + BOOT_SIZE) //0x8000 -#define APP_SIZE (58 * FLASH_SECTOR_SIZE) //464KB -#define BOOT_PARA_ADDRESS (APP_ADDRESS + APP_SIZE) //0x7C000 +#define BOOT_SIZE (4 * FLASH_SECTOR_SIZE) //32KB +#define APP_A_ADDRESS (FLASH_BASE + BOOT_SIZE) //0x8000 A区: 当前运行App +#define APP_BANK_SECTORS (29u) //A/B区各29扇区(232KB) +#define APP_BANK_SIZE (APP_BANK_SECTORS * FLASH_SECTOR_SIZE) //232KB +#define APP_B_ADDRESS (APP_A_ADDRESS + APP_BANK_SIZE) //0x42000 B区: 升级暂存 +#define APP_ADDRESS APP_A_ADDRESS //兼容旧名, 指向A区 +#define BOOT_PARA_ADDRESS (APP_B_ADDRESS + APP_BANK_SIZE) //0x7C000 #define BOOT_PARA_SIZE (FLASH_SECTOR_SIZE) #define DEBUG 1 @@ -303,10 +306,10 @@ void FeedDog(void); void Error_Handler(void); /*Flash操作*/ -void FlashWrite(uint32_t Addr, uint32_t *wData, uint8_t wLen); +void FlashWrite(uint32_t Addr, uint32_t *wData, int wLen); void ReadBootPara(BootPara rData); void WriteBootPara(BootPara wData); -void EraseFlash(void); +void EraseFlash(uint32_t BaseAddr, uint32_t SectorCnt); #endif diff --git a/source/User/Inc/main.h b/source/User/Inc/main.h index 0a05498..550e074 100644 --- a/source/User/Inc/main.h +++ b/source/User/Inc/main.h @@ -52,6 +52,7 @@ typedef enum { BL_WAIT_REV, BL_GET_DATA_TIMEOUT, BL_START_APP, + BL_COPY_TO_A, //B区镜像搬运到A区阶段 BL_RESET }BootStatus_m; @@ -62,6 +63,7 @@ typedef struct { uint32_t AppPackageCnt; uint32_t AppPackageIdx; uint32_t RevErrCnt; + uint32_t CopyRetryCnt; //搬运重试计数 uint32_t FeedDogDlyCnt; uint32_t BootLoader1mSDlyCnt; diff --git a/source/User/Src/bsp.c b/source/User/Src/bsp.c index 346557a..aa9d081 100644 --- a/source/User/Src/bsp.c +++ b/source/User/Src/bsp.c @@ -402,7 +402,7 @@ void BSP_Init(void) /***************************************************************************************** * Flash操作 ****************************************************************************************/ -void FlashWrite(uint32_t Addr, uint32_t *wData, uint8_t wLen) +void FlashWrite(uint32_t Addr, uint32_t *wData, int wLen) { EFM_Unlock(); EFM_FlashCmd(Enable); @@ -415,7 +415,7 @@ void FlashWrite(uint32_t Addr, uint32_t *wData, uint8_t wLen) EFM_Lock(); } -static void FlashRead(uint32_t u32Addr, uint32_t *rData, uint8_t rLen) +static void FlashRead(uint32_t u32Addr, uint32_t *rData, int rLen) { for(int i = 0; i < rLen / 4; i++) { rData[i] = *((volatile uint32_t*)(u32Addr + i * 4)); @@ -449,15 +449,15 @@ void WriteBootPara(BootPara wData) EFM_Lock(); } -void EraseFlash(void) +void EraseFlash(uint32_t BaseAddr, uint32_t SectorCnt) { EFM_Unlock(); EFM_FlashCmd(Enable); while(Set != EFM_GetFlagStatus(EFM_FLAG_RDY)) { ; } - /* 只擦APP区, 不擦参数区(BOOT_PARA_ADDRESS) */ - for(int Addr = APP_ADDRESS; Addr < BOOT_PARA_ADDRESS; Addr += FLASH_SECTOR_SIZE) { - EFM_SectorErase(Addr); + /*从BaseAddr起连续擦除SectorCnt个扇区(A/B区通用), 不碰参数区*/ + for(uint32_t i = 0; i < SectorCnt; i++) { + EFM_SectorErase(BaseAddr + i * FLASH_SECTOR_SIZE); FeedDog(); } EFM_Lock(); diff --git a/source/User/Src/main.c b/source/User/Src/main.c index fe5e54f..c038720 100644 --- a/source/User/Src/main.c +++ b/source/User/Src/main.c @@ -40,14 +40,14 @@ void InitCrc32Table(uint32_t* Crc32Tbl) /***************************************************************************************** * 函数名称: GetCrc32 -* 功能描述: 计算APP区CRC32校验值 +* 功能描述: 计算指定区域CRC32校验值 *****************************************************************************************/ -uint32_t GetCrc32(int dwLen) +uint32_t GetCrc32(uint32_t BaseAddr, int dwLen) { uint32_t Data; uint32_t dwCrc32Data = 0xFFFFFFFF; for(int dwCnt = 0; dwCnt < dwLen; dwCnt++) { - Data = *((volatile uint8_t*)(APP_ADDRESS + dwCnt)); + Data = *((volatile uint8_t*)(BaseAddr + dwCnt)); uint32_t dwTbl = (dwCrc32Data ^ Data) & 0xFF; dwCrc32Data = ((dwCrc32Data >> 8) & 0xFFFFFF) ^ pdwCrc32Tbl[dwTbl]; } @@ -110,11 +110,58 @@ static bool JumpToApp(uint32_t AppAddr) /***************************************************************************************** * 函数名称: AppWriteFlash -* 功能描述: 写APP数据到Flash (每包200字节) +* 功能描述: 写升级数据到Flash指定分区 (每包200字节, 尾部不足4字节按0xFF补齐) +* 参 数: BaseAddr 分区基址(B区), AddrOffset 分区内偏移, wData 数据, wLen 字节数 +* 返 回 值: 无 *****************************************************************************************/ -void AppWriteFlash(uint32_t AddrOffset, uint8_t *wData, int wLen) +void AppWriteFlash(uint32_t BaseAddr, uint32_t AddrOffset, uint8_t *wData, int wLen) { - FlashWrite(APP_ADDRESS + AddrOffset, (uint32_t *)wData, wLen / 4); + int FullWords = wLen / 4; + int Remain = wLen % 4; + uint32_t Word; + + FlashWrite(BaseAddr + AddrOffset, (uint32_t *)wData, FullWords); + if(Remain > 0) { /*末包尾字节补0xFF组字写入, 保证与AppSize逐字节CRC一致*/ + Word = 0xFFFFFFFF; + memcpy(&Word, &wData[FullWords * 4], Remain); + FlashWrite(BaseAddr + AddrOffset + FullWords * 4, &Word, 1); + } +} + +static uint32_t s_CopyBuf[FLASH_SECTOR_SIZE / 4]; /*搬运缓冲(8KB)*/ + +/***************************************************************************************** +* 函数名称: CopyAppBtoA +* 功能描述: 将B区已校验固件搬运到A区(逐扇区: 擦A→读B→写A), 完成后整包校验A区 +* 参 数: 无 +* 返 回 值: true=搬运并校验通过 +*****************************************************************************************/ +static bool CopyAppBtoA(void) +{ + uint32_t TotalWords = (BL.Para.AppSize + 3) / 4; /*实际固件字数*/ + uint32_t SecPerBank = FLASH_SECTOR_SIZE / 4; + uint32_t FullSectors = TotalWords / SecPerBank; + uint32_t RemainWords = TotalWords % SecPerBank; + uint32_t Sec, Base; + + for(Sec = 0; Sec < FullSectors; Sec++) { + Base = APP_A_ADDRESS + Sec * FLASH_SECTOR_SIZE; + EraseFlash(Base, 1); + for(uint32_t i = 0; i < SecPerBank; i++) { + s_CopyBuf[i] = *((volatile uint32_t *)(APP_B_ADDRESS + Sec * FLASH_SECTOR_SIZE + i * 4)); + } + FlashWrite(Base, s_CopyBuf, SecPerBank); + } + if(RemainWords > 0) { + Base = APP_A_ADDRESS + FullSectors * FLASH_SECTOR_SIZE; + EraseFlash(Base, 1); + for(uint32_t i = 0; i < RemainWords; i++) { + s_CopyBuf[i] = *((volatile uint32_t *)(APP_B_ADDRESS + FullSectors * FLASH_SECTOR_SIZE + i * 4)); + } + FlashWrite(Base, s_CopyBuf, RemainWords); + } + /*整包校验A区*/ + return (GetCrc32(APP_A_ADDRESS, BL.Para.AppSize) == BL.Para.Crc32Check); } /***************************************************************************************** @@ -188,6 +235,10 @@ bool AnalyzeData(uint8_t *rData, uint16_t rLen) return false; } UDReq UpData = (UDReq)&rData[sizeof(FrameHeader_t)]; + /*固件大小合法性检查: 为0或超出B区容量时拒绝升级*/ + if(UpData->AppSize == 0 || UpData->AppSize > APP_BANK_SIZE) { + return false; + } BL.Para.AppFlag = 0; BL.Para.UpdateFlag = APP_UPDATE_FLAG; BL.Para.Crc32Check = UpData->AppCrc32; @@ -204,12 +255,16 @@ bool AnalyzeData(uint8_t *rData, uint16_t rLen) if(BL.UpDateFlag == false) { return false; } + /*状态守卫: 仅下载状态接收数据, 防止搬运/复位阶段迟到包破坏B区*/ + if(BL.Status != BL_GET_DATA && BL.Status != BL_WAIT_REV) { + return false; + } DownRes DownData = (DownRes)&rData[sizeof(FrameHeader_t)]; if(BL.AppPackageIdx != DownData->PackageIndex) { return false; } /*写数据到Flash*/ - AppWriteFlash(BL.AppPackageIdx * 200, &rData[sizeof(FrameHeader_t) + sizeof(DownResponse_t)], DownData->DataLen); + AppWriteFlash(APP_B_ADDRESS, BL.AppPackageIdx * 200, &rData[sizeof(FrameHeader_t) + sizeof(DownResponse_t)], DownData->DataLen); BL.AppPackageIdx++; BL.RevErrCnt = 0; @@ -218,23 +273,22 @@ bool AnalyzeData(uint8_t *rData, uint16_t rLen) BL.BootLoader1mSDlyCnt = 5; } else { - /*全部数据处理完成, 校验CRC32*/ - uint32_t crc32 = GetCrc32(BL.Para.AppSize); + /*全部数据处理完成: 整包校验B区CRC32(此时尚未触碰A区, 原App完好)*/ + uint32_t crc32 = GetCrc32(APP_B_ADDRESS, BL.Para.AppSize); if(crc32 == BL.Para.Crc32Check) { - /*置升级完成标记(每次升级均置位):Boot本身不擦除外部Flash, - App启动时检测到此标记后擦除外部参数分区并恢复APP_START_FLAG*/ - BL.Para.AppFlag = APP_BOOT_UPGRADE_FLAG; - BL.Para.UpdateFlag = 0; - WriteBootPara(&BL.Para); - BL.BootLoader1mSDlyCnt = 100; - BL.Status = BL_RESET; + /*B区校验通过: 关闭接收, 进入搬运阶段(B→A), 搬运并校验A区后才置升级完成标记*/ + BL.UpDateFlag = false; + BL.CopyRetryCnt = 0; + BL.Status = BL_COPY_TO_A; } else { - BL.Para.AppFlag = 0; + /*B区校验失败: A区未动, 恢复老App启动标志并复位, 主机可重新发起升级*/ + BL.Para.AppFlag = APP_START_FLAG; BL.Para.UpdateFlag = 0; WriteBootPara(&BL.Para); BL.UpDateFlag = false; - BL.Status = BL_IDLE; + BL.BootLoader1mSDlyCnt = 100; + BL.Status = BL_RESET; } } return true; @@ -359,9 +413,50 @@ void BootLoaderLoopHandler(void) } break; + case BL_COPY_TO_A: + /*搬运B区已校验镜像到A区, 完成后整包校验A区*/ + if(CopyAppBtoA()) { + /*搬运校验通过: 立即擦除B区作废镜像, 防止下次升级时B区残留被误判为断电续传而跳过下载*/ + EraseFlash(APP_B_ADDRESS, APP_BANK_SECTORS); + /*置升级完成标记(每次升级均置位), App启动时擦除外部参数分区并恢复APP_START_FLAG*/ + BL.Para.AppFlag = APP_BOOT_UPGRADE_FLAG; + BL.Para.UpdateFlag = 0; + WriteBootPara(&BL.Para); + BL.BootLoader1mSDlyCnt = 100; + BL.Status = BL_RESET; + } + else { + /*搬运后A区校验失败(B区仍有效): 重试一次搬运*/ + if(BL.CopyRetryCnt++ < 1) { + break; + } + /*重试仍失败: 清标志停留等待主机重新升级*/ + BL.Para.AppFlag = 0; + BL.Para.UpdateFlag = 0; + WriteBootPara(&BL.Para); + BL.Status = BL_IDLE; + } + break; + case BL_ERASE_FLASH: FeedDog(); - EraseFlash(); + /*固件大小非法: 无法下载, 恢复老App(A区未动)并复位*/ + if(BL.Para.AppSize == 0 || BL.Para.AppSize > APP_BANK_SIZE) { + BL.Para.AppFlag = APP_START_FLAG; + BL.Para.UpdateFlag = 0; + WriteBootPara(&BL.Para); + BL.BootLoader1mSDlyCnt = 100; + BL.Status = BL_RESET; + break; + } + /*先校验B区: 已有完整有效镜像则直接搬运(断电续传: 下载完未搬运/搬运中断电)*/ + if(GetCrc32(APP_B_ADDRESS, BL.Para.AppSize) == BL.Para.Crc32Check) { + BL.CopyRetryCnt = 0; + BL.Status = BL_COPY_TO_A; + break; + } + /*B区无效: 仅擦除B区(A区保留原App), 逐包下载到B区*/ + EraseFlash(APP_B_ADDRESS, APP_BANK_SECTORS); FeedDog(); BL.Status = BL_GET_DATA; BL.BootLoader1mSDlyCnt = 200; @@ -392,12 +487,14 @@ void BootLoaderLoopHandler(void) BL.Status = BL_GET_DATA; } else { - BL.Status = BL_IDLE; - BL.Para.AppFlag = 0; - BL.RevErrCnt = 0; + /*下载超时: A区未动, 恢复老App启动标志并复位(设备回到可运行状态)*/ + BL.Para.AppFlag = APP_START_FLAG; BL.Para.UpdateFlag = 0; WriteBootPara(&BL.Para); + BL.RevErrCnt = 0; BL.UpDateFlag = false; + BL.BootLoader1mSDlyCnt = 100; + BL.Status = BL_RESET; } break; }