PY32F系列MCU在OTA时App区概率性跑不起来的根因分析(3)

接前一篇文章:PY32F系列MCU在OTA时App区概率性跑不起来的根因分析(2)

二、问题分析

3. 最终定位

上一回笔者沿着排查方向

(4)整个过程都没有问题,跳转出现了问题

1)烧录后跳转到App出了问题;

2)不经过烧录过程,直接跳转到App就出问题;

3)Boot或App自身存在问题。

不断改进方案、测试。

但即使笔者已经用了最强手段,问题依旧存在,只是概率上有所降低而已。这就说明也许之前的方向可能就错了,问题可能并不是烧录后跳转才出现,而是启动跳转就会出现。

碰巧在排查问题的过程中,有一天下午在天使用户家里复现了问题。那天并未进行OTA,而是直接一上电MCU程序直接跑飞了(通过指示灯和一般性功能判断)。这就辅证了问题确实不是OTA导致的,而是正常启动过程,由Boot区跳转到App区就存在问题。

还记得之前首先就排除了这种可能(参见PY32F系列MCU在OTA时App区概率性跑不起来的根因分析(1)-CSDN博客),

现在看来,之前的判断有误,正常启动时从Boot跳转到App就会存在问题。那么,问题究竟出在哪里呢?这次范围缩小了,锁定到了APP_Bootloader_Go这个函数。

APP_Bootloader_Go函数代码如下:

cpp 复制代码
typedef  void (*pFunction)(void);
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();
	}
}

而普冉官方给出的OTA例程的APP_Bootloader_Go函数代码如下:

cpp 复制代码
typedef  void (*pFunction)(void);
void APP_Bootloader_Go(uint32_t dwAddr)
{
  uint32_t JumpAddress;
  pFunction Jump_To_Application;
  
  CLEAR_BIT(RCC->CFGR, RCC_CFGR_SW);
  while (0 != READ_BIT(RCC->CFGR, RCC_CFGR_SWS));
  
  CLEAR_BIT(RCC->CR, RCC_CR_PLLON);

  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();
  }
}

看起来两个代码差不多,后半段代码完全一致,只是官方例程的代码中多了两段CLEAR_BIT相关代码,而笔者代码中多了APP_DeInitInterface函数。

但实际上笔者工程代码中的APP_DeInitInterface函数已经有了这两段代码。而官方例程将APP_DeInitInterface函数放到了APP_Bootloader_Go函数外边。

cpp 复制代码
/**
 * @brief  This function is used to jump to the user application.
 * @retval An ErrorStatus enumeration value:
 *          - SUCCESS: Go operation done
 *          - ERROR:   Go operation failed or the value of address is not ok
 */
ErrorStatus APP_Go(void)
{
  uint8_t ucMemArea;
  uint32_t dwAddr;

  ucMemArea = GetAddressArea(&dwAddr);
  if ((ucMemArea != FLASH_AREA) && (ucMemArea != RAM_AREA))
  {
    return ERROR;
  }
  
  APP_DeInitInterface();

  APP_Bootloader_Go(dwAddr);

  return SUCCESS;
}

因此,笔者工程代码和官方例程代码基本上一致了。而官方例程普冉的技术支持已经明确说了是非常成熟的方案,已经经过了N多公司的量产考验。

这样看来,问题是出在了细节的差异上。还需要仔细进行差异比对。具体细节请看下回。

相关推荐
Zwawa1 天前
编译器工具链:GCC、Clang、MSVC、ICC、armclang
c语言·嵌入式·编译器
用户8351414049491 天前
Makefile从零写起:每条规则在干什么
嵌入式
pipixia200331 天前
C++继承面试四连问:内存叠加、私有继承、sizeof、权限重映射
c++·面试·嵌入式·继承·面向对象·对象模型
极客 - L U1 天前
卡尔曼滤波从零到精通
c语言·数据结构·单片机·嵌入式硬件·mcu
橘色的喵2 天前
嵌入式Linux编程,如何把硬件中断交给用户态--UIO 的机制
linux·mcu·isr·中断·uio
shimly1234562 天前
(undone) 野火嵌入式 (1) 打开例程工程
嵌入式
Zwawa2 天前
一只按键不只“按下”:短按、长按和连按如何共存
c语言·单片机·嵌入式
Zevalin爱灰灰3 天前
Linux入门第一部分(Ubuntu入门篇) 第三章 shell脚本入门(一)
linux·ubuntu·嵌入式
笨笨饿3 天前
#143_屏幕画撕裂的问题及解决方法
linux·stm32·单片机·嵌入式硬件·mcu·lvgl·嵌入式实时数据库
李永奉3 天前
杰理可视化SDK开发-音频录制功能使用教程
笔记·单片机·嵌入式硬件·mcu·物联网·音视频