cancel
Showing results for 
Search instead for 
Did you mean: 

HardFault exception when jumping from application to system bootloader

DAUSILI
Associate II

Hello,
when trying to jump from my application to system bootloader, I get an HardFault exception.

This is the jumping routine that I am using, based on the following ST tutorial:
https://community.st.com/t5/stm32-mcus/how-to-jump-to-system-bootloader-from-application-code-on-stm32/ta-p/49424

 

 

#define SYSTEM_MEMORY_ADDR                0x1FFF0000
#define BOOTLOADER_ENTRY_ADDR            (SYSTEM_MEMORY_ADDR + 4)

void JumpToBootloader(void)
{
  ADC_HandleTypeDef hadc;
  UART_HandleTypeDef huart;
  SPI_HandleTypeDef hspi;
  TIM_HandleTypeDef htim;
  void        (*f)(void);
  uint8_t i;

  /* Disable all interrupts */
  __disable_irq();

  /* Disable Systick timer */
  SysTick->CTRL = 0;

  /* Set the clock to the default state */
  HAL_RCC_DeInit();

  /* Disable all other peripherls */
  hadc.Instance = ADC1;
  HAL_ADC_DeInit(&hadc);

  huart.Instance = USART2;
  HAL_UART_DeInit(&huart);

  hspi.Instance = SPI1;
  HAL_SPI_DeInit(&hspi);

  htim.Instance = TIM2;
  HAL_TIM_Base_DeInit(&htim);

  /* Clear Interrupt Enable Register & Interrupt Pending Register */
  for (i = 0; i < 5; i++)
  {
    NVIC->ICER[i]=0xFFFFFFFF;
    NVIC->ICPR[i]=0xFFFFFFFF;
  }

  /* Re-enable all interrupts */
  __enable_irq();

  /* Set the main stack pointer to the boot loader stack */
  __set_MSP(*(uint32_t *) SYSTEM_MEMORY_ADDR);

  /* jump to bootloader */
  f = (void (*)(void)) BOOTLOADER_ENTRY_ADDR;
  f();
}

 

Thank you,
Daniele

5 REPLIES 5
TDK
Guru

What does information within the SCB registers tell you about the reason for the hard fault? Use a fault analyzer if needed.

The calls to HAL_*_DeInit aren't as intended. These should be called using the same global handles that were used in the HAL_*_Init calls. Unclear if this is the source.

If you feel a post has answered your question, please click "Accept as Solution".
Jeff Tenney
Senior

You probably need to map system memory to 0x00000000 via SYSCFG->CFGR1.  And you probably need to set the VTOR back to 0 as well (SCB->VTOR).

Jeff Tenney
Senior

@DAUSILI wrote:

 

  /* Clear Interrupt Enable Register & Interrupt Pending Register */
  for (i = 0; i < 5; i++)
  {
    NVIC->ICER[i]=0xFFFFFFFF;
    NVIC->ICPR[i]=0xFFFFFFFF;
  }

 

The M0+ has only 1 ICER and ICPR register, not 5.  So this code is writing to registers that don't exist.  That's probably the cause of the hardfault.

Hello Jeff,
the cause of the malfunction was due to a wrong VTOR alignment.
The main memory was mapped at 0x00000000, so before jumping to system memory I correct the VTOR value in this way:

#define SYSTEM_MEMORY_ADDR 0x1FFF0000

__ISB();
SCB->VTOR = SYSTEM_MEMORY_ADDR;
__DSB();

Thank you,

Daniele

gbm
Lead III

This is incorrect and quite different from the original code:

f = (void (*)(void)) BOOTLOADER_ENTRY_ADDR;

See my post in the bootloader thread for a correct and simpler version

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice