STM32F4 IAP 跳转 APP问题

1. 概念

  IAP 的作用,网上其他资料已经有很多介绍了,这里放一个链接,不进行深入的介绍。本文的关注重点是Bootloader在跳转APP程序中出现的问题。
IAP的实现原理讲解以及中断向量表的偏移

2. 程序

  本人主要做应用层的开发,所有Bootloader和APP程序使用的是STM32CubeMX工具生成代码后,然后进行修改。

2.1 Bootloader 程序

  1. CubeMX 配置
  步骤1:使用的芯片为STM32F407ZGT6
在这里插入图片描述
  步骤2:选择时钟源(根据自己的板子进行选择)
在这里插入图片描述
  步骤3:时钟配置
在这里插入图片描述
  步骤4:项目配置
在这里插入图片描述
  2. 代码(只介绍跳转函数)

  完整代码

void IAP_ExecuteApp ( uint32_t ulAddr_App )
{
    
    
	int i = 0;
	pIapFun_TypeDef pJump2App; 

	
	if ( ( ( * ( __IO uint32_t * ) ulAddr_App ) & 0x2FFE0000 ) == 0x20000000 )	 //@1 //检查栈顶地址是否合法.
	{
    
     
		
		HAL_SPI_MspDeInit(&hspi1);	//@2
		__HAL_RCC_GPIOB_CLK_DISABLE();
		__HAL_RCC_GPIOG_CLK_DISABLE();
		
		
		 /* 设置所有时钟到默认状态,使用HSI时钟 */
		HAL_RCC_DeInit();		//@3
		
		__set_BASEPRI(0x20);		//@4
		__set_PRIMASK(1);
        __set_FAULTMASK(1);
		
		/* 关闭所有中断,清除所有中断挂起标志 */
		for (i = 0; i < 8; i++)		//@5
		{
    
    
			NVIC->ICER[i]=0xFFFFFFFF;
			NVIC->ICPR[i]=0xFFFFFFFF;
		}
		
		SysTick->CTRL = 0;		//@6
		SysTick->LOAD = 0;
		SysTick->VAL = 0;

		__set_BASEPRI(0);		//@7
		__set_PRIMASK(0);
		__set_FAULTMASK(0);
 		
 		//@8
        /*
        1)不使用OS时: 只用到MSP(中断和非中断都使用MSP);
        2)使用OS时(如UCOSII): main函数和中断使用MSP; 各个Task(线程)使用PSP(即任务栈);
        */
        __set_MSP(*(uint32_t*)ulAddr_App);//当带操作系统从APP区跳转到BOOT区的时候需要将SP设置为MSP,否则在BOOT区中使用中断将会引发硬件错误!
        __set_PSP(*(uint32_t*)ulAddr_App);
        __set_CONTROL(0);  /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
        __ISB();//指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
		//@9
		pJump2App = ( pIapFun_TypeDef ) * ( __IO uint32_t * ) ( ulAddr_App + 4 );	//用户代码区第二个字为程序开始地址(复位地址)		
		pJump2App ();								                                    	//跳转到APP.
	}
}	

  @1 代码作用:检查栈顶地址是否合法.0x20000000是sram的起始地址,也是程序的栈顶地址;

if ( ( ( * ( __IO uint32_t * ) ulAddr_App ) & 0x2FFE0000 ) == 0x20000000 )

  @2 代码作用:下面这几个关闭的是在Bootloader中初始化过的外设,如果没有初始化过其他外设,则不需要;

HAL_SPI_MspDeInit(&hspi1);	
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOG_CLK_DISABLE();

  @3 代码作用:PLL在Bootloader中已经配置启动了,在APP程序中如果想再进行配置启动的话会返回错误。
问题现象
  将Bootloader和APP程序分别下载到板子上,Bootlader程序可以正常运行,而APP程序会死在Error_Handler()的while(1)循环中。具体调试发现程序是在执行HAL_RCC_OscConfig()函数的PLL 配置部分检测到当前PLL已经被配置为了系统时钟而返回了HAL_ERROR的返回值导致进入了Error_Handler()。
方案一: 网上有人的建议是不使用PLL,使用HSI作为系统的时钟源,经过测试可以正常运行;但是这样会有个问题是,使用STM32F4的HSI是16M,这显然和通过PLL倍频之后使用的168M不在一个数量级上。
方案二: 通过查找资料发现,可以在Bootloader启动的时候配置PLL倍频到168M,然后在跳转程序之前将RCC的配置反初始化为默认设置(使用HSI时钟)。

HAL_RCC_DeInit();	

  @4 代码作用:关闭所有的中断;此处的特殊寄存器设置值,可以看如下链接: 嵌入式–Keil5–调试状态下Registers界面解析(nrf52832–Cortex-M4内核)

__set_BASEPRI(0x20);
__set_PRIMASK(1);
 __set_FAULTMASK(1);

  @5 代码作用:清除所有中断挂起标志,防止在APP中触发该中断,导致运行错误;

	/* 关闭所有中断,清除所有中断挂起标志 */
		for (i = 0; i < 8; i++)		//@5
		{
    
    
			NVIC->ICER[i]=0xFFFFFFFF;
			NVIC->ICPR[i]=0xFFFFFFFF;
		}

  @6 代码作用:关闭掉系统滴答定时器,该定时器会在APP的程序中重新启动,调用HAL_Init();函数会启动;
注意:@6 的代码一定要放到@3 之后,因为HAL_RCC_DeInit();函数会再次开启滴答定时器。

SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;

  @7 代码作用:重新启动中断开关;

	__set_BASEPRI(0);
	__set_PRIMASK(0);
	__set_FAULTMASK(0);

注意:必须重新启动中断的开关,本人调试过程中没有开启__set_FAULTMASK(0) ;的中断,导致滴答定时器(SysTick)无法正常运行,执行HAL_Delay();,死循环在了延时中,耽误了一天的时间查找问题。

  @8 和@9 代码都有详细的注释;

注意: __set_PSP((uint32_t)ulAddr_App); 和 __set_CONTROL(0); 函数是使用RTOS(实时操作系统的读者必须要添加的)

2.2. APP程序

  CubeMX 配置基本和Bootloader 基本相同,不赘述。本人使用的FreeRTOS的实时操作系统。

  1. Keil 配置
    步骤1:配置程序的起始位置(根据自己的需要修改),配置的时候发现只配置这块没用,需要配置步骤2才行
在这里插入图片描述
    步骤2:Linker 中修改ScatterFile 文件;

在这里插入图片描述
  这是本人的配置,每个人的可能都不一样,本人是需要用ccmram,所以使用自己的ScatterFile 文件,修改的内容如下图。
在这里插入图片描述
    步骤2:设置APP的中断向量表的位置;
  首先找到 startup_stm32f407xx.s 文件中调用 SystemInit 函数的地方,找到SystemInit 函数的实现,然后 找到 USER_VECT_TAB_ADDRESS 的宏定义的地方,取消注释。先修改下图 1的位置,然后修改 2的位置,2的位置根据自己的APP偏移位置来修改。
在这里插入图片描述
  2. 代码
   在main 函数的一开始添加如下代码。

  /* USER CODE BEGIN 1 */
	HAL_DeInit();
	HAL_RCC_DeInit();
  /* USER CODE END 1 */

在这里插入图片描述
HAL_DeInit(); HAL库反初始化;
HAL_RCC_DeInit(); RCC配置反初始化;

  注意: 如果直接查找HAL_RCC_DeInit() 的实现,发现是个空函数,实际这是HAL库的一个机制,实际编译使用的另外一个文件中的,如下图1和2

在这里插入图片描述
在这里插入图片描述

4. 其他问题

4.1 可能导致APP死机的原因

  1. Bootloader启动的外设比APP的多,导致死机,需要在跳转到APP时清理不需要的外设配置;
  2. Bootloader开启了某个终端,在APP中没有配置相应的处理函数,导致死机;该问题可通过Bootloader程序的@4 @5 @7来解决;

猜你喜欢

转载自blog.csdn.net/qinbo1234567890/article/details/128318895