Files
HC32F460BootLoader/source/User/Src/main.c
T
YuanHongbin 48b789c0c4 feat(ota): Boot支持外部Flash暂存搬运(BL_STASH_TO_B状态)
- bsp.c/h: 外部SPI Flash只读驱动(SPI1, 与App同总线Mode3)
- main.c/h: BL_STASH_TO_B状态: AppSize门禁 -> 外部Flash逐8KB搬运B区 -> CRC校验 -> 进BL_COPY_TO_A复用现有搬运链
- 搬运幂等: 搬运中断电重启后B区仍有效自动重搬
2026-09-24 17:14:09 +08:00

645 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdlib.h>
#include <string.h>
#include "main.h"
/*设备唯一编码 - 固定在Flash 0x4000位置(协议规定: Mac[0]=VerInfo, Mac[1:3]=PrjNum, Mac[4:5]=GwNum)
参照hc32l170_boot方式用宏构造6字节MAC, 网关APP从该地址读取本机MAC编码*/
const uint8_t GwMacConst[6] __attribute__((section(".ARM.__at_0x00004000"))) = {
(0x80 | GATEWAY_VER_INFO), // Mac[0] = VerInfo: Bit7固定1, Bit6:0版本
(GATEWAY_PRJ_NUM >> 16) & 0xFF, // Mac[1]
(GATEWAY_PRJ_NUM >> 8) & 0xFF, // Mac[2]
GATEWAY_PRJ_NUM & 0xFF, // Mac[3]
(GATEWAY_GW_NUM >> 8) & 0xFF, // Mac[4]
GATEWAY_GW_NUM & 0xFF // Mac[5]
};
/*运行用MAC, 首次从0x4000读入, 之后从参数区同步*/
static uint8_t s_DevMac[6] = {0};
uint32_t pdwCrc32Tbl[256];
BootLoader_t BL;
/*****************************************************************************************
* 函数名称: InitCrc32Table
* 功能描述: CRC32查表初始化
*****************************************************************************************/
void InitCrc32Table(uint32_t* Crc32Tbl)
{
for(int wCnt = 0; wCnt < 256; wCnt++) {
uint32_t dwCrc = wCnt;
for(int ucCnt = 0; ucCnt < 8; ucCnt++) {
if(dwCrc & 1) {
dwCrc = (dwCrc >> 1) ^ 0xEDB88320;
}
else {
dwCrc >>= 1;
}
}
Crc32Tbl[wCnt] = dwCrc;
}
}
/*****************************************************************************************
* 函数名称: GetCrc32
* 功能描述: 计算指定区域CRC32校验值
*****************************************************************************************/
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*)(BaseAddr + dwCnt));
uint32_t dwTbl = (dwCrc32Data ^ Data) & 0xFF;
dwCrc32Data = ((dwCrc32Data >> 8) & 0xFFFFFF) ^ pdwCrc32Tbl[dwTbl];
}
return ~dwCrc32Data;
}
/*****************************************************************************************
* 函数名称: CRC_Modbus
* 功能描述: Modbus CRC16校验
*****************************************************************************************/
uint16_t CRC_Modbus(uint16_t wBase, __IO uint8_t *para, uint16_t length)
{
uint16_t crc = 0xFFFF;
uint16_t index, i;
for(index = 0; index < length; index++) {
crc ^= para[index];
for(i = 0; i < 8; i++) {
if(crc & 1) {
crc >>= 1;
crc ^= wBase;
}
else {
crc >>= 1;
}
}
}
return crc;
}
/*****************************************************************************************
* 函数名称: JumpToApp
* 功能描述: 跳转APP
*****************************************************************************************/
static bool JumpToApp(uint32_t AppAddr)
{
uint32_t u32StackTop = *((__IO uint32_t *)AppAddr);
uint32_t JumpAddress;
func_ptr_t JumpToApplication;
if((u32StackTop > SRAM_BASE) && (u32StackTop <= (SRAM_BASE + SRAM_SIZE))) {
JumpAddress = *(__IO uint32_t *)(AppAddr + 4);
JumpToApplication = (func_ptr_t)JumpAddress;
/*关闭全局中断, 停SysTick, 禁用Boot用过的NVIC中断, 避免跳转后残留中断干扰APP启动*/
__disable_irq();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
NVIC_DisableIRQ(RS485CH1_UART_IRQn);
NVIC_DisableIRQ(RS485CH1_UART_EI_IRQn);
NVIC_ClearPendingIRQ(RS485CH1_UART_IRQn);
NVIC_ClearPendingIRQ(RS485CH1_UART_EI_IRQn);
__set_MSP(*((__IO uint32_t *)AppAddr));
JumpToApplication();
return true;
}
return false;
}
/*****************************************************************************************
* 函数名称: AppWriteFlash
* 功能描述: 写升级数据到Flash指定分区 (每包200字节, 尾部不足4字节按0xFF补齐)
* 参 数: BaseAddr 分区基址(B区), AddrOffset 分区内偏移, wData 数据, wLen 字节数
* 返 回 值: 无
*****************************************************************************************/
void AppWriteFlash(uint32_t BaseAddr, uint32_t AddrOffset, uint8_t *wData, int wLen)
{
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);
}
static uint32_t s_StashBuf[FLASH_SECTOR_SIZE / 4]; /*外部Flash读缓冲(8KB)*/
/*****************************************************************************************
* 函数名称: StashToB
* 功能描述: Cat1远程升级: 将外部SPI Flash暂存区固件搬运到B区(逐8KB: 读外部2×4KB→擦写B区1×8KB)
* 参 数: 无
* 返 回 值: 无(搬运后由调用方CRC32校验B区)
*****************************************************************************************/
static void StashToB(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, SrcAddr;
for(Sec = 0; Sec < FullSectors; Sec++) {
Base = APP_B_ADDRESS + Sec * FLASH_SECTOR_SIZE;
SrcAddr = FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + Sec * FLASH_SECTOR_SIZE;
FeedDog();
ExtFlashRead(SrcAddr, (uint8_t *)s_StashBuf, FLASH_SECTOR_SIZE);
EraseFlash(Base, 1);
FlashWrite(Base, s_StashBuf, SecPerBank);
}
if(RemainWords > 0) {
Base = APP_B_ADDRESS + FullSectors * FLASH_SECTOR_SIZE;
SrcAddr = FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + FullSectors * FLASH_SECTOR_SIZE;
FeedDog();
ExtFlashRead(SrcAddr, (uint8_t *)s_StashBuf, RemainWords * 4);
EraseFlash(Base, 1);
FlashWrite(Base, s_StashBuf, RemainWords);
}
}
/*****************************************************************************************
* 函数名称: SendResponseCmd
* 功能描述: 发送响应帧 (0x7D + DevMac)
*****************************************************************************************/
static void SendResponseCmd(uint8_t Cmd, uint16_t PayLoad)
{
uint8_t sData[24];
uint16_t sLen;
uint16_t crc16;
FrameH Frame = (FrameH)sData;
Frame->Header = 0x7D;
memcpy(Frame->DevMac, s_DevMac, 6);
Frame->Cmd = Cmd;
if(Cmd == UPDATE_CMD_SLAVE_RES) {
Frame->PayloadLen = 1;
sData[sizeof(FrameHeader_t)] = (uint8_t)PayLoad;
}
else if(Cmd == UPDATE_CMD_SLAVE_REQ_DATA) {
Frame->PayloadLen = 4;
GDReq GDData = (GDReq)&sData[sizeof(FrameHeader_t)];
GDData->PackageIndex = PayLoad;
GDData->PackageNum = BL.AppPackageCnt;
}
sLen = sizeof(FrameHeader_t) + Frame->PayloadLen;
crc16 = CRC_Modbus(CRC16_BASE, sData, sLen);
sData[sLen++] = crc16 & 0xFF;
sData[sLen++] = (crc16 >> 8) & 0xFF;
RS485Ch1UartSend(sData, sLen);
}
/*****************************************************************************************
* 函数名称: AnalyzeData
* 功能描述: 解析接收帧 (0x81升级请求 / 0x82数据包)
*****************************************************************************************/
bool AnalyzeData(uint8_t *rData, uint16_t rLen)
{
uint16_t crc16, check;
check = CRC_Modbus(CRC16_BASE, rData, rLen - 2);
crc16 = (rData[rLen - 1] << 8) | rData[rLen - 2];
if(check != crc16) {
return false;
}
FrameH Frame = (FrameH)rData;
/*校验MAC地址是否匹配(支持广播全0xFF)*/
int ret = memcmp(Frame->DevMac, s_DevMac, 6);
if(ret != 0) {
bool isBroadcast = true;
for(int i = 0; i < 6; i++) {
if(Frame->DevMac[i] != 0xFF) {
isBroadcast = false;
break;
}
}
if(!isBroadcast) {
return false;
}
}
/*命令处理*/
if(Frame->Cmd == UPDATE_CMD_MASTER_REQ) {
if(BL.Status != BL_IDLE) {
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;
BL.Para.PackageCnt = UpData->PackageNum;
BL.Para.AppSize = UpData->AppSize;
WriteBootPara(&BL.Para);
/*回0x01 ACK应答, 确认收到升级请求, 载荷=0x20*/
SendResponseCmd(UPDATE_CMD_SLAVE_RES, 0x20);
BL.BootLoader1mSDlyCnt = 20;
BL.Status = BL_RESET;
return true;
}
else if(Frame->Cmd == UPDATE_CMD_MASTRE_RES_DATA) {
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(APP_B_ADDRESS, BL.AppPackageIdx * 200, &rData[sizeof(FrameHeader_t) + sizeof(DownResponse_t)], DownData->DataLen);
BL.AppPackageIdx++;
BL.RevErrCnt = 0;
if(BL.AppPackageIdx < BL.AppPackageCnt) {
BL.Status = BL_GET_DATA;
BL.BootLoader1mSDlyCnt = 5;
}
else {
/*全部数据处理完成: 整包校验B区CRC32(此时尚未触碰A区, 原App完好)*/
uint32_t crc32 = GetCrc32(APP_B_ADDRESS, BL.Para.AppSize);
if(crc32 == BL.Para.Crc32Check) {
/*B区校验通过: 关闭接收, 进入搬运阶段(B→A), 搬运并校验A区后才置升级完成标记*/
BL.UpDateFlag = false;
BL.CopyRetryCnt = 0;
BL.Status = BL_COPY_TO_A;
}
else {
/*B区校验失败: A区未动, 恢复老App启动标志并复位, 主机可重新发起升级*/
BL.Para.AppFlag = APP_START_FLAG;
BL.Para.UpdateFlag = 0;
WriteBootPara(&BL.Para);
BL.UpDateFlag = false;
BL.BootLoader1mSDlyCnt = 100;
BL.Status = BL_RESET;
}
}
return true;
}
return false;
}
/*****************************************************************************************
* 函数名称: BootLoader1mSRoutine
* 功能描述: BootLoader 1ms定时(由SysTick中断调用)
*****************************************************************************************/
static void BootLoader1mSRoutine(void)
{
if(BL.BootLoader1mSDlyCnt) {
BL.BootLoader1mSDlyCnt--;
}
if(BL.UartRevTimeOutCnt > 0) {
BL.UartRevTimeOutCnt--;
}
BL.FeedDogDlyCnt++;
}
/*****************************************************************************************
* 函数名称: SysTick_IrqHandler
* 功能描述: SysTick中断
*****************************************************************************************/
void SysTick_IrqHandler(void)
{
BootLoader1mSRoutine();
}
/*****************************************************************************************
* 函数名称: FeedDogHandler
* 功能描述: 看门狗喂狗
*****************************************************************************************/
void FeedDogHandler(void)
{
if(BL.FeedDogDlyCnt >= 200) {
FeedDog();
BL.FeedDogDlyCnt = 0;
}
}
/*****************************************************************************************
* 函数名称: RS485Ch1RxIrqCallback
* 功能描述: RS485通道1接收中断回调(每字节), 组帧(0x7D)
*****************************************************************************************/
static uint16_t rLen;
static uint8_t rBuff[300];
static bool Header;
static uint16_t PayLen;
void RS485Ch1RxIrqCallback(uint8_t RxData)
{
if(BL.UartRevTimeOutCnt == 0) {
Header = false;
rLen = 0;
PayLen = 0;
}
BL.UartRevTimeOutCnt = 3;
if(Header == false && (RxData == 0x7D)) {
Header = true;
rLen = 0;
PayLen = 0;
rBuff[rLen++] = RxData;
}
else if(Header == true) {
if(rLen >= sizeof(rBuff)) {
Header = false;
rLen = 0;
return;
}
rBuff[rLen++] = RxData;
if(rLen == 9) {
PayLen = RxData;
if(PayLen > 256) {
Header = false;
rLen = 0;
return;
}
}
else if(rLen == sizeof(FrameHeader_t) + PayLen + 2) {
BL.RxLen = rLen;
memcpy(BL.RxBuff, rBuff, BL.RxLen);
BL.RxFlag = true;
Header = false;
rLen = 0;
}
}
}
/*****************************************************************************************
* 函数名称: BootLoaderLoopHandler
* 功能描述: BootLoader主循环
*****************************************************************************************/
void BootLoaderLoopHandler(void)
{
/*帧解析 - BL_RESET状态下不处理新帧, 避免复位等待期被0x81打断*/
if(BL.RxFlag && BL.Status != BL_RESET) {
BL.RxFlag = false;
AnalyzeData(BL.RxBuff, BL.RxLen);
}
switch(BL.Status) {
case BL_IDLE:
break;
case BL_RESET:
if(BL.BootLoader1mSDlyCnt > 0) {
break;
}
NVIC_SystemReset();
break;
case BL_START_APP:
if(JumpToApp(APP_ADDRESS) == false) {
BL.Status = BL_IDLE;
}
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_STASH_TO_B:
FeedDog();
/*固件大小非法: 无法搬运, 恢复老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;
}
/*外部SPI Flash暂存区→B区(逐8KB), StashToB幂等: 搬运中断电重启后自动重做*/
StashToB();
/*B区整包校验: 通过进搬运, 失败清标志回老App*/
if(GetCrc32(APP_B_ADDRESS, BL.Para.AppSize) == BL.Para.Crc32Check) {
BL.CopyRetryCnt = 0;
BL.Status = BL_COPY_TO_A;
}
else {
BL.Para.AppFlag = APP_START_FLAG;
BL.Para.UpdateFlag = 0;
WriteBootPara(&BL.Para);
BL.BootLoader1mSDlyCnt = 100;
BL.Status = BL_RESET;
}
break;
case BL_ERASE_FLASH:
FeedDog();
/*固件大小非法: 无法下载, 恢复老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;
BL.AppPackageCnt = BL.Para.PackageCnt;
BL.RevErrCnt = 0;
BL.UpDateFlag = true;
break;
case BL_GET_DATA:
if(BL.BootLoader1mSDlyCnt > 0) {
break;
}
/*请求下一包数据 - 通过RS485应答*/
SendResponseCmd(UPDATE_CMD_SLAVE_REQ_DATA, BL.AppPackageIdx);
BL.Status = BL_WAIT_REV;
BL.BootLoader1mSDlyCnt = 500;
break;
case BL_WAIT_REV:
if(BL.BootLoader1mSDlyCnt == 0) {
BL.Status = BL_GET_DATA_TIMEOUT;
}
break;
case BL_GET_DATA_TIMEOUT:
BL.RevErrCnt++;
if(BL.RevErrCnt < 3) {
BL.Status = BL_GET_DATA;
}
else {
/*下载超时: 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;
}
}
/*****************************************************************************************
* 函数名称: SetDefaultBootPara
* 功能描述: 填充BootPara_t中所有默认配置(服务器/Lora/通道/RS485), 由Boot直接配置
*****************************************************************************************/
static void SetDefaultBootPara(BootPara_t *Para)
{
Para->SvrAddr[0] = GATEWAY_SVR_ADDR0;
Para->SvrAddr[1] = GATEWAY_SVR_ADDR1;
Para->SvrAddr[2] = GATEWAY_SVR_ADDR2;
Para->SvrAddr[3] = GATEWAY_SVR_ADDR3;
Para->SvrPort = GATEWAY_SVR_PORT;
Para->LoraFreq = GATEWAY_LORA_FREQ;
Para->Much = GATEWAY_MUCH;
Para->Auch = GATEWAY_AUCH;
Para->Duch = GATEWAY_DUCH;
Para->CuchMask = GATEWAY_CUCH_MASK;
}
/*****************************************************************************************
* 函数名称: main
* 功能描述: 主函数
*****************************************************************************************/
int32_t main(void)
{
BSP_Init();
InitCrc32Table(pdwCrc32Tbl);
/*从固定地址0x4000读入网关MAC编码*/
memcpy(&s_DevMac[0], &GwMacConst[0], 6);
/*读取boot参数*/
ReadBootPara(&BL.Para);
/*设备判断*/
if(BL.Para.GwMac[0] == 0xFF && BL.Para.GwMac[1] == 0xFF) {
/*首次运行GwMac无效*/
if(BL.Para.FirstRunFlag == 0xFFFFFFFF) {
BL.Status = BL_START_APP;
}
else {
BL.Status = BL_IDLE;
}
BL.Para.AppFlag = 0;
BL.Para.UpdateFlag = 0;
BL.Para.FirstRunFlag = 0;
memcpy(&BL.Para.GwMac[0], &s_DevMac[0], 6);
SetDefaultBootPara(&BL.Para);
WriteBootPara(&BL.Para);
}
else {
/*更新MAC地址*/
memcpy(&s_DevMac[0], &BL.Para.GwMac[0], 6);
/*兼容旧参数区: 默认配置未写入(0xFF)时补默认值*/
if(BL.Para.SvrAddr[0] == 0xFF && BL.Para.SvrAddr[1] == 0xFF) {
SetDefaultBootPara(&BL.Para);
WriteBootPara(&BL.Para);
}
/*APP_BOOT_UPGRADE_FLAG也需直接启动App:升级完成后由App擦除外部参数分区,
若此处不放行,设备升级完会停留在BL_IDLE等待升级命令而无法启动*/
if(BL.Para.AppFlag == APP_START_FLAG || BL.Para.AppFlag == APP_BOOT_UPGRADE_FLAG) {
BL.Status = BL_START_APP;
}
else if(BL.Para.UpdateFlag == APP_UPDATE_SPI_FLAG) {
BL.Status = BL_STASH_TO_B; /*Cat1远程升级: 外部Flash暂存区→B区→A区*/
}
else if(BL.Para.UpdateFlag == APP_UPDATE_FLAG) {
BL.Status = BL_ERASE_FLASH;
}
else {
BL.Status = BL_IDLE;
}
}
while(1) {
FeedDogHandler();
BootLoaderLoopHandler();
}
}