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区仍有效自动重搬
This commit is contained in:
+23
-1
@@ -206,7 +206,27 @@ typedef enum {
|
||||
#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 BOOT_PARA_SIZE (FLASH_SECTOR_SIZE)
|
||||
|
||||
/*外部SPI Flash(与App共用SPI1: PC0-NSS/PC1-MISO/PC2-SCK/PC3-MOSI, Mode3) - Cat1远程升级固件暂存区*/
|
||||
#define EXTFLASH_NSS_PORT (PortC)
|
||||
#define EXTFLASH_NSS_PIN (Pin00)
|
||||
#define EXTFLASH_NSS_SET() PORT_SetBits(EXTFLASH_NSS_PORT, EXTFLASH_NSS_PIN)
|
||||
#define EXTFLASH_NSS_CLR() PORT_ResetBits(EXTFLASH_NSS_PORT, EXTFLASH_NSS_PIN)
|
||||
#define EXTFLASH_SCK_PORT (PortC)
|
||||
#define EXTFLASH_SCK_PIN (Pin02)
|
||||
#define EXTFLASH_SCK_FUNC (Func_Spi1_Sck)
|
||||
#define EXTFLASH_MOSI_PORT (PortC)
|
||||
#define EXTFLASH_MOSI_PIN (Pin03)
|
||||
#define EXTFLASH_MOSI_FUNC (Func_Spi1_Mosi)
|
||||
#define EXTFLASH_MISO_PORT (PortC)
|
||||
#define EXTFLASH_MISO_PIN (Pin01)
|
||||
#define EXTFLASH_MISO_FUNC (Func_Spi1_Miso)
|
||||
#define EXTFLASH_UNIT (M4_SPI1)
|
||||
#define EXTFLASH_UNIT_CLOCK (PWC_FCG1_PERIPH_SPI1)
|
||||
#define EXTFLASH_CMD_READ 0x03
|
||||
#define SPIFLASH_SECTORSIZE 4096ul
|
||||
#define FLASH_FW_STASH_SECTOR 4038 //暂存区起始扇区(与App spiflash.h一致)
|
||||
|
||||
#define DEBUG 1
|
||||
#define USE_SD_CARD 0
|
||||
@@ -307,6 +327,8 @@ void Error_Handler(void);
|
||||
|
||||
/*Flash操作*/
|
||||
void FlashWrite(uint32_t Addr, uint32_t *wData, int wLen);
|
||||
void ExtFlashInit(void);
|
||||
void ExtFlashRead(uint32_t Addr, uint8_t *rData, uint16_t rLen);
|
||||
void ReadBootPara(BootPara rData);
|
||||
void WriteBootPara(BootPara wData);
|
||||
void EraseFlash(uint32_t BaseAddr, uint32_t SectorCnt);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define APP_START_FLAG 0x55AA5A5A
|
||||
#define APP_UPDATE_FLAG 0xA5A5AA55
|
||||
#define APP_BOOT_UPGRADE_FLAG 0x5A5A55A5 //升级完成标记:Boot升级成功后置位,App启动时据此擦除外部参数分区并恢复APP_START_FLAG(与App侧bsp.h定义保持一致)
|
||||
#define APP_UPDATE_SPI_FLAG 0xA5A55A5A //Cat1远程升级: 固件已存外部SPI Flash暂存区, Boot据此搬运(与App侧bsp.h定义保持一致)
|
||||
|
||||
typedef enum {
|
||||
UPDATE_CMD_NULL,
|
||||
@@ -53,6 +54,7 @@ typedef enum {
|
||||
BL_GET_DATA_TIMEOUT,
|
||||
BL_START_APP,
|
||||
BL_COPY_TO_A, //B区镜像搬运到A区阶段
|
||||
BL_STASH_TO_B, //外部SPI Flash暂存区搬运到B区阶段(Cat1远程升级)
|
||||
BL_RESET
|
||||
}BootStatus_m;
|
||||
|
||||
|
||||
@@ -393,6 +393,7 @@ void BSP_Init(void)
|
||||
SystemClockConfig();
|
||||
GPIO_Config();
|
||||
RS485Ch1_Config(500000);
|
||||
ExtFlashInit(); /*外部SPI Flash: Cat1远程升级暂存区读取用*/
|
||||
|
||||
FeedDog();
|
||||
SysTick_Init(1000);
|
||||
@@ -422,6 +423,93 @@ static void FlashRead(uint32_t u32Addr, uint32_t *rData, int rLen)
|
||||
}
|
||||
}
|
||||
|
||||
/*外部SPI Flash驱动: 供Cat1远程升级时读取暂存区固件(App负责写入暂存区)*/
|
||||
static uint16_t ExtSpiSendReceive(uint16_t sData)
|
||||
{
|
||||
uint16_t retry = 0;
|
||||
uint16_t rData;
|
||||
|
||||
while(Reset == SPI_GetFlag(EXTFLASH_UNIT, SpiFlagSendBufferEmpty)) {
|
||||
retry++;
|
||||
if(retry > 0x4000) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SPI_SendData8(EXTFLASH_UNIT, sData);
|
||||
retry = 0;
|
||||
while(Reset == SPI_GetFlag(EXTFLASH_UNIT, SpiFlagReceiveBufferFull)) {
|
||||
retry++;
|
||||
if(retry > 0x4000) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rData = SPI_ReceiveData8(EXTFLASH_UNIT);
|
||||
return rData;
|
||||
}
|
||||
|
||||
void ExtFlashInit(void)
|
||||
{
|
||||
stc_spi_init_t stcSpiInit;
|
||||
stc_port_init_t stcPortInit;
|
||||
|
||||
MEM_ZERO_STRUCT(stcPortInit);
|
||||
stcPortInit.enPinOType = Pin_OType_Cmos;
|
||||
PORT_Init(EXTFLASH_SCK_PORT, EXTFLASH_SCK_PIN, &stcPortInit);
|
||||
PORT_Init(EXTFLASH_MOSI_PORT, EXTFLASH_MOSI_PIN, &stcPortInit);
|
||||
PORT_Init(EXTFLASH_MISO_PORT, EXTFLASH_MISO_PIN, &stcPortInit);
|
||||
stcPortInit.enPinMode = Pin_Mode_Out;
|
||||
stcPortInit.enPinOType = Pin_OType_Cmos;
|
||||
stcPortInit.enPinDrv = Pin_Drv_H;
|
||||
stcPortInit.enPullUp = Disable;
|
||||
PORT_Init(EXTFLASH_NSS_PORT, EXTFLASH_NSS_PIN, &stcPortInit);
|
||||
EXTFLASH_NSS_SET();
|
||||
|
||||
MEM_ZERO_STRUCT(stcSpiInit);
|
||||
PWC_Fcg1PeriphClockCmd(EXTFLASH_UNIT_CLOCK, Enable);
|
||||
PORT_SetFunc(EXTFLASH_SCK_PORT, EXTFLASH_SCK_PIN, EXTFLASH_SCK_FUNC, Disable);
|
||||
PORT_SetFunc(EXTFLASH_MOSI_PORT, EXTFLASH_MOSI_PIN, EXTFLASH_MOSI_FUNC, Disable);
|
||||
PORT_SetFunc(EXTFLASH_MISO_PORT, EXTFLASH_MISO_PIN, EXTFLASH_MISO_FUNC, Disable);
|
||||
|
||||
stcSpiInit.enClkDiv = SpiClkDiv16;
|
||||
stcSpiInit.enFrameNumber = SpiFrameNumber1;
|
||||
stcSpiInit.enDataLength = SpiDataLengthBit8;
|
||||
stcSpiInit.enFirstBitPosition = SpiFirstBitPositionMSB;
|
||||
stcSpiInit.enSckPolarity = SpiSckIdleLevelHigh;
|
||||
stcSpiInit.enSckPhase = SpiSckOddChangeEvenSample;
|
||||
stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
|
||||
stcSpiInit.enWorkMode = SpiWorkMode4Line;
|
||||
stcSpiInit.enTransMode = SpiTransFullDuplex;
|
||||
stcSpiInit.enCommAutoSuspendEn = Disable;
|
||||
stcSpiInit.enModeFaultErrorDetectEn = Disable;
|
||||
stcSpiInit.enParitySelfDetectEn = Disable;
|
||||
stcSpiInit.enParityEn = Disable;
|
||||
stcSpiInit.enParity = SpiParityEven;
|
||||
stcSpiInit.enMasterSlaveMode = SpiModeMaster;
|
||||
stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
|
||||
stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
|
||||
stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
|
||||
stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
|
||||
stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
|
||||
stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
|
||||
stcSpiInit.stcSsConfig.enSsValidBit = SpiSsValidChannel0;
|
||||
stcSpiInit.stcSsConfig.enSs0Polarity = SpiSsLowValid;
|
||||
SPI_Init(EXTFLASH_UNIT, &stcSpiInit);
|
||||
SPI_Cmd(EXTFLASH_UNIT, Enable);
|
||||
}
|
||||
|
||||
void ExtFlashRead(uint32_t Addr, uint8_t *rData, uint16_t rLen)
|
||||
{
|
||||
EXTFLASH_NSS_CLR();
|
||||
ExtSpiSendReceive(0x03);
|
||||
ExtSpiSendReceive((Addr >> 16) & 0xFF);
|
||||
ExtSpiSendReceive((Addr >> 8) & 0xFF);
|
||||
ExtSpiSendReceive(Addr & 0xFF);
|
||||
for(uint16_t i = 0; i < rLen; i++) {
|
||||
rData[i] = ExtSpiSendReceive(0xFF);
|
||||
}
|
||||
EXTFLASH_NSS_SET();
|
||||
}
|
||||
|
||||
void ReadBootPara(BootPara rData)
|
||||
{
|
||||
FlashRead(BOOT_PARA_ADDRESS, (uint32_t *)rData, sizeof(BootPara_t));
|
||||
|
||||
@@ -164,6 +164,40 @@ static bool CopyAppBtoA(void)
|
||||
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)
|
||||
@@ -438,6 +472,33 @@ void BootLoaderLoopHandler(void)
|
||||
}
|
||||
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区未动)并复位*/
|
||||
@@ -564,6 +625,9 @@ int32_t main(void)
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user