Skip to main content
ERODR.1
Associate II
Nov 21, 2021 4:33 AM UTC
Question

STM32F072CBT6 - Entering bootloader from application

I need to enter into the bootloader from my application during runtime.

I found an example code to achieve this for another family series and followed the instructions to determine the specific memory region I should jump to based on my particular MCU.

Below is the resulting code.

typedef void jumpFunc(void);
 
void Bootloader_Start(uint32_t run)
{
 /* Set the address of the entry point to bootloader */
 volatile uint32_t BootAddr = 0x1FFFC800;
 
 /* Set up the jump to booloader address + 4 */
 jumpFunc* SysMemBoot = (jumpFunc*)0x1FFFC804;
 
 if (run == 1)
 {
 // Shut down any task running
 HAL_RCC_DeInit();
 SysTick->CTRL = 0; // reset the SysTick Timer
 SysTick->LOAD = 0;
 SysTick->VAL = 0;
 
 __disable_irq(); // Disable interrupts
 
 /* Set the main stack pointer to the bootloader stack */
 __set_MSP(*(uint32_t *)BootAddr);
 
 SysMemBoot();
 
 while (1);
 }
}

However, this code is not working for me. Executing it always results in a Hard fault interrupt.

What am I missing?

Thanks

This topic has been closed for replies.

6 replies

ERODR.1
ERODR.1Author
Associate II
Nov 21, 2021 1:57 PM UTC

Thank you very much. Very helpful. It looks like I was missing this:

SYSCFG->CFGR1 = 0x01;

So now it doesn't end up in a Hard Fault interrupt. However, I haven't been able to connect using the Flash Loader Demonstrator. I have tried all 3 options for Echo without luck.

0693W00000GYKviQAH.png0693W00000GYKwIQAX.png0693W00000GYKvYQAX.pngUsing the STM32CubeProgrammer UART, I get it to connect, but haven't been able to flash anything. It stays with the loading bar ping-ponging without ever increasing from 0%.

0693W00000GYKwWQAX.png 

What am I missing here?

MM..1
Super User
Nov 21, 2021 2:20 PM UTC

Try ommit the call to __disable_irq();

ERODR.1
ERODR.1Author
Associate II
Nov 21, 2021 2:41 PM UTC

Thanks for the follow up. I tried, but if the interrupts are not disabled, for some reason it resets after calling the SysMemBootJump.

MM..1
Super User
Nov 21, 2021 5:19 PM UTC

You need disable interrupts one by one before call Bootloader start.

ERODR.1
ERODR.1Author
Associate II
Nov 21, 2021 7:18 PM UTC

Thanks for your assistance. Based on your input I decided to call the DeInit functions for each and every peripheral currently used by my application as well as disabling all interrupts enabled by my application. I followed the reverse Initialization order while doing it.

Here's the final code tested to work using the Flash Demonstrator app:

void Bootloader_Start(uint32_t run) {
 void (*SysMemBootJump)(void);
 
 /**
 * Set system memory address.
 *
 * For STM32F072, system memory is on 0x1FFF C800
 * For other families, check AN2606 document table 155 with descriptions of memory addresses
 */
 volatile uint32_t addr = 0x1FFFC800;
 
 if (run == 1)
 {
 // De-initialize all peripherals configured for this Application
 HAL_TIM_Base_DeInit(&htim1);
 HAL_TIM_Base_DeInit(&htim6);
 HAL_TIM_Base_DeInit(&htim7);
 HAL_TIM_Base_DeInit(&htim14);
 
 HAL_TIM_PWM_DeInit(&htim15);
 HAL_TIM_Base_DeInit(&htim15);
 
 HAL_CRC_DeInit(&hcrc);
 
 HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
 HAL_NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);
 HAL_NVIC_DisableIRQ(DMA1_Channel4_5_6_7_IRQn);
 HAL_DMA_DeInit(&hdma_memtomem_dma1_channel2);
 
 HAL_PCD_DeInit(&hpcd_USB_FS);
 HAL_UART_DeInit(&huart2);
 HAL_UART_DeInit(&huart1);
 
 HAL_ADC_DeInit(&hadc);
 
 // Disable GPIO interrupts
 HAL_NVIC_DisableIRQ(EXTI0_1_IRQn);
 HAL_NVIC_DisableIRQ(EXTI2_3_IRQn);
 HAL_NVIC_DisableIRQ(EXTI4_15_IRQn);
 
 // Disable RCC, set it to default (after reset) settings
 // Internal clock, no PLL, etc.
 HAL_RCC_DeInit();
 
 // Disable systick timer and reset it to default values
 SysTick->CTRL = 0;
 SysTick->LOAD = 0;
 SysTick->VAL = 0;
 
 // Disable all interrupts
 __disable_irq();
 
 /**
 * Remap system memory to address 0x0000 0000 in address space
 * For each family registers may be different.
 * Check reference manual for each family.
 *
 * For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0])
 * For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0])
 * For others, check family reference manual
 */
 //Remap by hand... {
 #if defined(STM32F4)
 SYSCFG->MEMRMP = 0x01;
 #endif
 #if defined(STM32F0)
 SYSCFG->CFGR1 = 0x01;
 #endif
 //} ...or if you use HAL drivers
 //__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); //Call HAL macro to do this for you
 
 // Set jump memory location for system memory
 // Use address with 4 bytes offset which specifies jump location where program starts
 SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
 
 /**
 * Set main stack pointer.
 * This step must be done last otherwise local variables in this function
 * don't have proper value since stack pointer is located on different position
 *
 * Set direct address location which specifies stack pointer in SRAM location
 */
 __set_MSP(*(uint32_t *)addr);
 
 /**
 * Call our function to jump to set location
 * This will start system memory execution
 */
 SysMemBootJump();
 }
}