454 lines
11 KiB
C
454 lines
11 KiB
C
|
||
#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);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|