cancel
Showing results for 
Search instead for 
Did you mean: 

SOLVED: STM32H7 bootloader jumping to app compiled with TrueStudio, but not with STM32CubeIDE.

Jack3
Senior II

I used TrueStudio for a bootloader and two different applications for an STM32H7, and all worked fine.

Now, I imported the bootloader and applications into STM32CubeIDE.

The bootloader starts, jumps to the application and it runs fine when the bootloader was compiled with TrueStudio 9.3.0.

However, when the bootloader is compilerd with STM32CubeIDE 1.4.2, it also jumps to the application, but the application hangs when executing HAL_Delay, so the system Tick interrupt does not seem to work, and possibly more.

Both applications run with the bootloader compiled by TrueStudio, and standalone, without bootloader (slightly modified for that), from both IDE's

I suspect a problem in the handover function in the bootloader.

From the bootloader I also tried to jump first, without initializing anything, with the same results.

My jumping function in the bootloader looks like:

typedef void (*pFunction)(void);
pFunction JumpToApplication;
 
/* Jump to application */
void Bootloader_JumpToApplication(uint32_t AppAddress)
{
  JumpToApplication = (pFunction) (*(uint32_t *)(AppAddress + 4));
 
  HAL_RCC_DeInit();
 
  /* Disable all enabled interrupts and pending interrupt requests in NVIC */
  for(uint8_t i = 0; i < 8; i++)
  {
    /* Disable all enabled interrupts in NVIC */
    NVIC->ICER[i] = 0xFFFFFFFF;
    /* Clear all pending interrupt requests in NVIC */
    NVIC->ICPR[i] = 0xFFFFFFFF;
  }
 
  /*
   * Disable SysTick and clear its exception pending bit,
   * if it is used in the bootloader, e. g. by the RTX.
   */
  SysTick->CTRL = 0;
  SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;
 
  /* Disable individual fault handlers if the bootloader used them. */
  SCB->SHCSR &= ~(SCB_SHCSR_USGFAULTENA_Msk | \
      SCB_SHCSR_BUSFAULTENA_Msk | \
      SCB_SHCSR_MEMFAULTENA_Msk);
 
  /* Activate the MSP, if the core is found to currently run with the PSP. */
  if( CONTROL_SPSEL_Msk & __get_CONTROL( ) )
  {
    /* MSP is not active */
    __set_MSP(__get_PSP());
    __set_CONTROL( __get_CONTROL( ) & ~CONTROL_SPSEL_Msk ) ;
  }
 
  __HAL_RCC_SYSCFG_CLK_ENABLE();
 
  /** 
  * Set the VTOR register to point to the new start of the application.
  * Setting SCB->VTOR is handled in SystemInit function of the application.
  */
#if (SET_VECTOR_TABLE)
  SCB->VTOR = AppAddress;
#endif
 
  /* Configure the Main Stack Pointer. This function comes from CMSIS. */
  __set_MSP(*(__IO uint32_t*) AppAddress);
 
  JumpToApplication();
}

Managing SCB->VTOR is performed in the SystemInit() function of the application (thanks Clive):

system_stm32h7xx.c:

extern void *g_pfnVectors; // Keil forks use *__Vectors, check your startup_stm32h753xx.s
 
/**
  * @brief  Setup the microcontroller system
  *         Initialize the FPU setting, vector table location and External memory
  *         configuration.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
  #endif
 
  /* Configure the Vector Table ----------------------------------------------*/
  SCB->VTOR = (uint32_t)&g_pfnVectors;
  
...

The application can be compiled with either IDE, no problems.

I would really appreciate some help, as I am out of ideas on how to fix this.

UPDATE: I got it working. In the first code calling the function __set_MSP() seemed the culprit.

This also works fine:

__attribute__((naked, noreturn)) void BootJumpASM(uint32_t SP, uint32_t RH);
 
/* Jump to application */
void Bootloader_JumpToApplication(uint32_t AppAddress)
{
  uint32_t AppStack;
  uint32_t AppEntry;
 
  HAL_RCC_DeInit();
 
  /* Disable all enabled interrupts and pending interrupt requests in NVIC */
  for(uint8_t i = 0; i < 8; i++)
  {
    /* Disable all enabled interrupts in NVIC */
    NVIC->ICER[i] = 0xFFFFFFFF;
    /* Clear all pending interrupt requests in NVIC */
    NVIC->ICPR[i] = 0xFFFFFFFF;
  }
 
  /*
   * Disable SysTick and clear its exception pending bit,
   * if it is used in the bootloader, e. g. by the RTX.
   */
  SysTick->CTRL = 0;
  SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;
 
  /* Disable individual fault handlers if the bootloader used them. */
  SCB->SHCSR &= ~(SCB_SHCSR_USGFAULTENA_Msk | \
      SCB_SHCSR_BUSFAULTENA_Msk | \
      SCB_SHCSR_MEMFAULTENA_Msk);
 
  /* Activate the MSP, if the core is found to currently run with the PSP. */
  if (CONTROL_SPSEL_Msk & __get_CONTROL())
  {
    /* MSP is not active */
    __set_MSP(__get_PSP());
    __set_CONTROL(__get_CONTROL() & ~CONTROL_SPSEL_Msk);
  }
 
  __HAL_RCC_SYSCFG_CLK_ENABLE();
 
  /* Get the application stack pointer (1st entry in the app vector table) */
  AppStack = (uint32_t)*((__IO uint32_t*)AppAddress);
 
  /* Get the application entry point (2nd entry in the app vector table */
  AppEntry = (uint32_t)*(__IO uint32_t*)(AppAddress + 4);
 
  /*
   * The final part is to set the MSP to the value found in the user application vector table
   * and then load the PC with the reset vector value of the user application. This can't be
   * done in C, as it is always possible, that the compiler uses the current SP. But that
   * would be gone after setting the new MSP. So, a call to a small assembler function is done.
   */
  BootJumpASM(AppStack, AppEntry);
 
  while (1); /* Never reached */
}
 
__attribute__(( naked, noreturn )) void BootJumpASM(uint32_t SP, uint32_t RH)
{
  __asm("MSR      MSP,r0");
  __asm("BX       r1");
}

 Hope this helps somebody.

1 REPLY 1
Ahmet Yasin CİVAN
Associate III

Thank you for sharing.