optical/NxFuncs/stiap/stiap.c
2025-09-04 09:45:08 +08:00

454 lines
11 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 "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);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////