2021-11-20 08:33 PM
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
2021-11-21 02:08 AM
2021-11-21 05:57 AM
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.
Using 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%.
What am I missing here?
2021-11-21 06:20 AM
Try ommit the call to __disable_irq();
2021-11-21 06:41 AM
Thanks for the follow up. I tried, but if the interrupts are not disabled, for some reason it resets after calling the SysMemBootJump.
2021-11-21 09:19 AM
You need disable interrupts one by one before call Bootloader start.
2021-11-21 11:18 AM
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();
}
}