Skip to main content
Associate III
June 28, 2023
Question

HardFault exception when jumping from application to system bootloader

  • June 28, 2023
  • 4 replies
  • 2015 views

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

This topic has been closed for replies.

4 replies

TDK
Super User
June 28, 2023

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
June 28, 2023

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
June 29, 2023

@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.

DAUSILIAuthor
Associate III
June 29, 2023

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
June 29, 2023

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