接前一篇文章:PY32F系列MCU在OTA时App区概率性跑不起来的根因分析(1)
二、问题分析
2. 进一步分析和所采取措施
上一回初步分析了笔者所遇到的PY32F系列MCU OTA概率性失败的问题。经过初步筛查、处理和排除,将问题聚焦于:
(4)整个过程都没有问题,跳转出现了问题
上回书讲过,这里又分为几个怀疑点:
1)烧录后跳转到App出了问题;
2)不经过烧录过程,直接跳转到App就出问题;
3)Boot或App自身存在问题。
首先重点排查:1)烧录后跳转到App出了问题。
既然之前已经能够保证了通过串口接收数据的正确性以及烧录过程的正确性,并且已知不经过烧录过程,直接跳转App没有问题,那么就将怀疑重点聚焦于经过烧录过程后,MCU的某些状态(上下文)出现了某种问题,导致跳转到App区的过程中出现了问题,不能够正常跳转。
为此,笔者将代码逐步进行了以下逐步修改,不断提高跳转的可靠性。
(1)将烧录完成后由Boot区跳转到App区改为通过软件复位重启
之前是在接收完全部的升级文件(帧)并且均烧录完成后,在EEPROM写入特定标志,调用APP_Bootloader_Go函数实现由Boot区向App区的跳转。
APP_Bootloader_Go(APP_START_ADDR);
APP_Bootloader_Go函数的代码如下:
void APP_Bootloader_Go(uint32_t dwAddr)
{
uint32_t JumpAddress;
pFunction Jump_To_Application;
__disable_irq();
APP_DeInitInterface();
if (((*(__IO uint32_t*)dwAddr) & 0x2FFC0000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (dwAddr + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) dwAddr);
Jump_To_Application();
}
}
由于担心APP_Bootloader_Go函数存在问题,使用NVIC_SystemReset()替代。
NVIC_SystemReset()是Cortex‑M 内核(STM32、PY32 等)CMSIS的标准软系统复位函数。这样就免去了APP_Bootloader_Go函数可能存在的负面影响,让系统重新像每次正常启动一样,复位后先进入Boot区,再由Boot区跳转到App区。
(2)将软件系统复位改为看门狗硬件复位
进行了以上修改之后,出现问题的概率降低了,但仍然有跑飞的情况。于是又进行了加强 —— 使用开门狗复位代替系统复位。
由于担心NVIC_SystemReset()函数可能存在部分芯片 / 场景下会卡在死循环,复位不生效的问题,使用IWDG独立看门狗进行复位。两者的区别如下:
- NVIC_SystemReset:软件主动请求复位,可控;复位源标记为SFTRST。
- IWDG 复位:看门狗超时自动复位,用于程序跑飞卡死;复位源IWDGRST。
最主要的区别是前者是软件复位,而后者是硬件复位。这就排除了NVIC_SystemReset()可能存在问题的情况。
(3)在Boot区中也加入看门狗复位,保证Boot区不会跑飞
进行了手段加强之后,经过压力测试,问题依然存在。于是又再次进行了加强。
上一步的看门狗是在串口接收完全部的升级文件(帧)并且均烧录完成后,才初始化并且使能的(只使能不喂狗,超时时间一到硬件复位)。为了防止Boot区本身可能存在跑飞的情况,这一次把看门狗的初始化、使能以及喂狗代码前置,放在主函数和主循环中。正常情况下,在while中喂狗,当收到全部升级数据并烧录完成后,不再喂狗,超时时间一到产生硬件复位。
经过了“终极”手段之后,虽然概率很低了(约1/750),但实测还是会存在跑飞的情况。说明问题的根因还是没有找到,以上手段也只能够大幅降低概率,没有能够完全“cover”住、完全“work around”。
那么问题究竟出在了哪里?到底是什么原因导致的低概率程序跑飞?请看下回。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/phmatthaus/article/details/167128195




