#include "stiap.h" #include "stapp.h" #include "crc32.h" #include "trigger.h" #include "shell.h" #include "delay.h" #if (0) // 临时措施,后续需做兼容 #include "can.h" #include "fmc.h" #endif //=================================================================== // IAP代码 // stfaddr: 应用程序的起始地址 // saveaddr: 应用程序存放在 NORFLASH 或 RAM 的起始地址. // size: 应用程序大小 (字节) int WriteAppBinData(u32 stfaddr, u32 saveaddr, u32 size) { int rslt = 0; u32 faddr = stfaddr; u32 saddr = saveaddr; u32 wrsize = size; u16 thissize; #ifdef STM32_FLASH_SEC_SIZE // 每扇区字节数 #define STM32_RW_BUFF_SIZE (STM32_FLASH_SEC_SIZE) #else #define STM32_RW_BUFF_SIZE (STM32_FLASH_RW_SIZE) #endif #if (APP_SAVE_TO == APP_SAVE_NORFLASH || APP_SAVE_TO == APP_SAVE_INFLASH) u8 iapbuf[STM32_RW_BUFF_SIZE]; #else u8 * iapbuf; #endif #if (NO_BUFF_WHEN_WT == 1) // 20230928 ljs 无缓写入时需提前擦除对应扇区,避免写入失败 u32 secIdx = GetFlashSectorIdx(faddr); u32 secnums = GetFlashSectorIdx(faddr+wrsize); secnums = secnums - secIdx + 1; STMFlashErase(secIdx, secnums); #endif printf("Write data to addr = 0x%x begin\r\n", (unsigned int)faddr); while (wrsize > 0) { if (wrsize < STM32_RW_BUFF_SIZE) { thissize = wrsize; } else { thissize = STM32_RW_BUFF_SIZE; } #if (APP_SAVE_TO == APP_SAVE_NORFLASH) DatFlashRdData(saddr, iapbuf, thissize); // 从 norflash 读数据 #elif (APP_SAVE_TO == APP_SAVE_EXRAM) iapbuf = (u8*)saddr; // 从 ram 读数据 #elif (APP_SAVE_TO == APP_SAVE_INFLASH) STMFlashRead(saddr, (u16*)iapbuf, thissize/2); // 从st flash 读数据 #else break; #endif STMFlashWrite(faddr, (u16*)iapbuf, thissize/2, 1); // 写数据到stm32的flash中 rslt = STMFlashCheck(faddr, (u16*)iapbuf, thissize/2); // 检查数据正确性 if (rslt != 0) { printf("\r\nWriteAppBinData error. addr=0x%x, size=%d\r\n", (unsigned int)faddr, thissize); break; } PutChar('.'); faddr += thissize; // 指针偏移 saddr += thissize; // 指针偏移 wrsize -= thissize; } printf("write data finish\r\n"); #if (APP_SAVE_TO == APP_SAVE_EXRAM) if (rslt == 0) { // 校验所有数据 printf("WriteAppBinData finish, check all data\r\n"); rslt = STMFlashCheck(stfaddr, (u16*)saveaddr, size/2); // 检查数据正确性 if (rslt == 0) { printf("WriteAppBinData ok\r\n"); } } #endif if (rslt != 0) { printf("WriteAppBinData failed\r\n"); } return rslt; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // 20230523 完善使用外部RAM进行升级 #if (APP_SAVE_TO == APP_SAVE_EXRAM) char g_appEnFlag[16] = {0xff}; void SetAppEnFlag(int flag) { if (flag == 0) { memset(g_appEnFlag, 0xff, 16); } else { strcpy(g_appEnFlag, APP_RIGHT); } } int IsAppRight(void) { if (strcmp((void*)APP_RIGHT, g_appEnFlag) != 0) { return -1; } else { return 0; } } #endif ////////////////////////////////////////////////////////////////////////////////////////////////////// // bootloader 接口函数 // 升级主控文件(从存储器到APP区域) int UpdateApp(void) { int rslt = 0; u32 saveaddr; // 数据读取地址 u32 stfaddr; // 数据写入地址 u32 appsize, wsize; u32 crc; IapHead iaphd; u32 resetaddr, stacktop; memset(&iaphd, 0, sizeof(IapHead)); #if (APP_SAVE_TO == APP_SAVE_NORFLASH) u32 taddr = (u32)(&iaphd); DatFlashRdData(APP_MARK_ADDR, (u8 *)(taddr), sizeof(IapHead)/sizeof(u8)); // 读数据 #elif (APP_SAVE_TO == APP_SAVE_EXRAM) memcpy((void*)(&iaphd), (void*)APP_MARK_ADDR, sizeof(IapHead)); // 读入iaphead 数据 SetAppEnFlag(1); #elif (APP_SAVE_TO == APP_SAVE_INFLASH) u32 taddr = (u32)(&iaphd); STMFlashRead(APP_MARK_ADDR, (u16*)(taddr), sizeof(IapHead)/sizeof(u16)); #endif crc = CalcCrc32((u8*)&(iaphd), sizeof(IapHead)-sizeof(iaphd.checkcrc)); // 校验之前所有字段 printf("UpdateApp begin\r\n"); #if (0) printf("iaphd.upmask=%s\r\n", iaphd.upmask); printf("iaphd.rdaddr=0x%x\r\n", iaphd.rdaddr); printf("iaphd.wraddr=0x%x\r\n", iaphd.wraddr); printf("iaphd.size=0x%x\r\n", iaphd.size); printf("iaphd.wsize=0x%x\r\n", iaphd.wsize); printf("iaphd.appcheck=0x%x\r\n", iaphd.appcheck); printf("calc iaphd crc = 0x%x, save iaphd.checkcrc = 0x%x\r\n", crc, iaphd.checkcrc); #endif // 校验数据 if (crc != iaphd.checkcrc) { printf("updatedata checkcrc err\r\n"); return -1; // 校验错 } if (strcmp((void*)STM32_MARK, iaphd.upmask) != 0) // 比较 { printf("updatedata upmask err\r\n"); return 0; // 不一致, 返回 } saveaddr = iaphd.rdaddr + APP_SAVE_BASE; // 读取地址 stfaddr = iaphd.wraddr + STM32_FLASH_BASE; // 写入地址 appsize = iaphd.size; wsize = iaphd.wsize; if ((stfaddr < STM32_APP_ADDR) || (stfaddr >= (STM32_FLASH_BASE + STM32_FLASH_SIZE)) || (saveaddr < APP_ADDR_BEG) || 0 ) // 地址不符合要求 { printf("flash addr error\r\n"); return -2; } crc = GetAppSaveDataCrc(saveaddr, appsize); if (crc != iaphd.appcheck) { printf("save data crc check error, crc=0x%x, appcheck=0x%x\r\n", crc, iaphd.appcheck); return -2; } // 从存储区中读取复位地址和栈顶地址 #if (APP_SAVE_TO == APP_SAVE_NORFLASH) { u8 buff[8]; DatFlashRdData(APP_ADDR_BEG, buff, 8); stacktop = *(__IO uint32_t*)(buff); // 栈顶地址 resetaddr = *(__IO uint32_t*)(buff+4); // 复位地址 } #elif (APP_SAVE_TO == APP_SAVE_EXRAM || APP_SAVE_TO == APP_SAVE_INFLASH) stacktop = *(__IO uint32_t*)(APP_ADDR_BEG); // 栈顶地址 resetaddr = *(__IO uint32_t*)(APP_ADDR_BEG+4); // 复位地址 #else return -2; #endif printf("save file stacktop = 0x%x, resetaddr=0x%x\r\n", (unsigned int)stacktop, (unsigned int)resetaddr); if ((resetaddr >= STM32_APP_ADDR) && ((resetaddr & 0xFF000000) == 0x08000000) && // 判断是否为0X08XXXXXX ((stacktop & 0x2FFC0000) == 0x20000000) && // 检查栈顶地址是否合法 1 ) { printf("save data ok\r\n"); } else { printf("save data not right\r\n"); return -2; } #if (APP_SAVE_TO == APP_SAVE_EXRAM) SetAppEnFlag(0); // 清除app正确标志.... #endif printf("UpdateApp: from add=0x%x to stadd=0x%x, size=%d, wsize=%d\r\n", saveaddr, stfaddr, appsize, wsize); rslt = WriteAppBinData(stfaddr, saveaddr, wsize); // 更新FLASH代码 #if (APP_SAVE_TO == APP_SAVE_NORFLASH) DatFlash4kErase(APP_MARK_ADDR, 1); // 更新完成, 擦除掉标志, 参数等 #elif (APP_SAVE_TO == APP_SAVE_EXRAM) memset((void*)APP_MARK_ADDR, 0xff, IAPHEAD_LEN); // 全部写为0xff #elif (APP_SAVE_TO == APP_SAVE_INFLASH) STMFlashErase(GetFlashSectorIdx(APP_MARK_ADDR), 1); #endif #if (APP_SAVE_TO == APP_SAVE_EXRAM) if (rslt == 0) { SetAppEnFlag(1); } #endif return rslt; } // 关闭所有 __WEAK void CloseAllPeripheral() { __disable_irq(); // 关闭中断 #if (0) // 临时措施,后续需做兼容 HAL_DeInit(); LL_GPIO_DeInit(GPIOA); LL_GPIO_DeInit(GPIOB); LL_GPIO_DeInit(GPIOC); LL_GPIO_DeInit(GPIOD); LL_GPIO_DeInit(GPIOE); LL_GPIO_DeInit(GPIOF); LL_GPIO_DeInit(GPIOG); LL_EXTI_DeInit(); HAL_ADC_DeInit(&hadc3); HAL_CAN_DeInit(&HCAN); HAL_SRAM_DeInit(&hsram1); HAL_SRAM_DeInit(&hsram2); HAL_SRAM_DeInit(&hsram3); HAL_SRAM_DeInit(&hsram4); LL_SPI_DeInit(SPI1); LL_SPI_DeInit(SPI2); LL_TIM_DeInit(TIM1); LL_TIM_DeInit(TIM2); LL_TIM_DeInit(TIM3); LL_TIM_DeInit(TIM4); LL_TIM_DeInit(TIM5); LL_TIM_DeInit(TIM6); LL_TIM_DeInit(TIM7); LL_TIM_DeInit(TIM8); LL_USART_DeInit(USART1); LL_USART_DeInit(USART2); LL_USART_DeInit(USART3); LL_USART_DeInit(UART4); LL_USART_DeInit(UART5); #else LL_EXTI_DeInit(); #endif __disable_irq(); // 关闭中断 } //=================================================================== // 跳转到应用程序段 int JumpToApp(void) { typedef void (*iapfun)(void); // 定义一个函数类型的参数. int rslt; u32 resetaddr, stacktop; printf("Begin run app\r\n"); // 从flash中读取复位地址和栈顶地址 stacktop = *(__IO uint32_t*)(STM32_APP_ADDR); // 栈顶地址 resetaddr = *(__IO uint32_t*)(STM32_APP_ADDR+4); // 复位地址 rslt = 0; #if (APP_SAVE_TO == APP_SAVE_EXRAM) rslt = IsAppRight(); #endif printf("stacktop = 0x%x, resetaddr=0x%x\r\n", (unsigned int)stacktop, (unsigned int)resetaddr); DelayMs(100); if ( (rslt == 0) && (resetaddr >= STM32_APP_ADDR) && ((resetaddr & 0xFF000000) == 0x08000000) && // 判断是否为0X08XXXXXX ((stacktop & 0x2FFC0000) == 0x20000000) && // 检查栈顶地址是否合法 1 ) { iapfun jump; printf("Jump to app address\r\n"); DelayMs(100); CloseAllPeripheral(); DelayMs(100); jump = (iapfun)(resetaddr); // 用户代码区第二个字为程序开始地址(复位地址) __set_MSP(stacktop); // 初始化 APP 堆栈指针 (用户代码区的第一个字用于存放栈顶地址) jump(); // 跳转到APP. } printf("run app failed\r\n"); return -1; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // app 调用iap模块功能接口函数 void IAPCleanUpdateArea(void) { #if (APP_SAVE_TO == APP_SAVE_NORFLASH) // 擦除升级区域 norflash 的块 u32 addr; int erflag; int count = 0; printf("IAPCleanUpdateArea, erase begin\r\n"); addr = NOR_SAVE_BASE; while(addr < NOR_SAVE_END) { erflag = IsDatFlashEmpty(addr, SNF_BYTES_PER_SEC); // 判断一个扇区是否为空 if (erflag != 0) { DatFlash4kErase(addr, 1); // 擦除一个扇区 PutChar('.'); count++; //erflag = IsDatFlashEmpty(addr, SNF_BYTES_PER_SEC); // 判断一个扇区是否为空 //printf("erase failed, addr=%d, idx=%d, flag=%d\r\n", addr, (addr-NOR_SAVE_BASE)/SNF_BYTES_PER_SEC, erflag); } addr += SNF_BYTES_PER_SEC; // 地址增加 } printf("IAPCleanUpdateArea finish, count=%d\r\n", count); #elif (APP_SAVE_TO == APP_SAVE_EXRAM) memset((void*)EXRAM_SAVE_BASE, 0xff, STM32_FLASH_SIZE); // 全部写为0xff #elif (APP_SAVE_TO == APP_SAVE_INFLASH) STMFlashErase(GetFlashSectorIdx(APP_SAVE_BASE), (STF_UPDATE_SIZE+MARK_SIZE)/STM32_FLASH_SEC_SIZE); #endif } // 写入升级起始地址, 长度和升级标志 void IapWritePara(u32 rdAddr, u32 wrAddr, u32 len, u32 wlen, u32 check) { // 数据长度必须为扇区(STM32_FLASH_SEC_SIZE)的整数倍 IapHead iaphd; memset(&iaphd, 0xff, sizeof(IapHead)); strcpy(iaphd.upmask, STM32_MARK); iaphd.rdaddr = rdAddr; iaphd.wraddr = wrAddr; iaphd.size = len; iaphd.wsize = wlen; iaphd.appcheck = check; iaphd.checkcrc = CalcCrc32((u8*)&(iaphd.upmask[0]), sizeof(IapHead)-sizeof(iaphd.checkcrc)); // 校验之前所有字段 printf("IapWritePara begin\r\n"); #if (0) printf("iaphd.upmask %s\r\n", iaphd.upmask); printf("iaphd.rdaddr=0x%x\r\n", iaphd.rdaddr); printf("iaphd.wraddr=0x%x\r\n", iaphd.wraddr); printf("iaphd.size=0x%x\r\n", iaphd.size); printf("iaphd.wsize=0x%x\r\n", iaphd.wsize); printf("iaphd.appcheck=0x%x\r\n", iaphd.appcheck); printf("iaphd.checkcrc = 0x%x\r\n", iaphd.checkcrc); #endif #if (APP_SAVE_TO == APP_SAVE_NORFLASH) DatFlash4kErase(NOR_MARK_ADDR, 1); // 4k擦除 u32 taddr = (u32)(&iaphd); DatFlashWrData(NOR_MARK_ADDR, (u8*)(taddr), sizeof(IapHead)/sizeof(u8)); // 写入 #elif (APP_SAVE_TO == APP_SAVE_EXRAM) memcpy((void*)EXRAM_MARK_ADDR, (void*)(&(iaphd)), sizeof(IapHead)); #elif (APP_SAVE_TO == APP_SAVE_INFLASH) STMFlashErase(GetFlashSectorIdx(APP_MARK_ADDR), 1); u32 taddr = (u32)(&iaphd); STMFlashWrite(APP_MARK_ADDR, (u16*)(taddr), sizeof(IapHead)/sizeof(u16), 3); // 写入 #endif printf("IapWritePara end\r\n"); DelayMs(100); } ////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////