cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F042 - Issues entering bootloader from application

JCame.1
Associate III

The code below shows my current attempt to implement a jump to the bootloader:

#define ApplicationAddress 0x1FFFC400
 
void JumpBootloader(void)
{
    typedef void (*pFunction)(void); // defines function pointer for bootloader jump
 
    /* Set System memory address plus 4 bytes */
    uint32_t JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
 
    pFunction Jump_To_Boot = (pFunction) JumpAddress;
 
    //    /* Set main stack pointer
    //     * This must be done last otherwise all other variables might get mangled! */
    __set_MSP(*(__IO uint32_t*) ApplicationAddress);
 
    Jump_To_Boot();
}

When this function is called with the BOOT pin pulled high, the microcontroller correctly restarts into bootloader mode, although admittedly after a slight delay of about a second (Windows connect and disconnect sounds can be heard).

When called with the BOOT pin floating/pulled low (note I am using this pin to drive an LED during normal operation), the device disconnects after a small delay as before but then fails to connect, giving the error 'Device Descriptor Request Failed'.

I have looked around on other threads/forums and tried various different methods such as de-initialising all peripherals prior to calling the above function, remapping the system memory to 0x0 (__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();) with varying changes in behaviour. For example, the code below simply jumps back to the user application after being called:

void JumpBootloader(void)
{
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;
    uint32_t JumpAddress = 0x1FFFC400;
 
    Device_DeInit();
    HAL_RCC_DeInit();
 
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
 
    JumpToApplication = (void (*)(void)) (*((uint32_t *)(JumpAddress + 4)));
 
    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*) JumpAddress);
 
    JumpToApplication();
}
 
void Device_DeInit(void)
{
    USBD_Stop(&hUsbDeviceFS);
    USBD_DeInit(&hUsbDeviceFS);
    HAL_TIM_Base_Stop_IT(&htim16);
 
    HAL_SPI_DeInit(&hspi1);
    HAL_DMA_DeInit(&hdma_spi1_tx);
    HAL_DMA_DeInit(&hdma_spi1_rx);
    HAL_TIM_Base_MspDeInit(&htim16);
 
    HAL_GPIO_DeInit(LED_USB_GPIO_Port, LED_USB_Pin);
    HAL_GPIO_DeInit(LED_AXIOM_GPIO_Port, LED_AXIOM_Pin);
    HAL_DeInit();
}

Am I missing a vital point here? Are there any pre-requisites I have not met?

If it is of any concern, I am using USB DFU.

Best regards,

James

1 ACCEPTED SOLUTION

Accepted Solutions
JCame.1
Associate III

*************************************************************************

EDIT: Be careful when implementing this! Setting BOOT_SEL = 0 disables the physical boot pin from working. This has some pretty serious repercussions - if a firmware upgrade fails then there is no way to get the device into bootloader mode (as the code to enter bootloader doesn't exist). To recover the device you must connect and reprogram using the ST Link debugger.

*************************************************************************

For future reference/anyone searching for the same issue:

In the function that gets called when requesting the bootloader:

void StartBootloader(void)
{
    /* The STM32F042 has:
     * 6k SRAM in address: 0x2000 0000 - 0x2000 17FF
     */
    *((unsigned long *)0x200017F0) = 0xDEADBEEF;
 
    // Reset the processor
    NVIC_SystemReset();
 
    /* We then do a check in SystemInit() at startup to see if this 'magic number' has been set */
}

The we do a check at start-up in SystemInit():

void SystemInit(void)
{
    /* Check if we should go into bootloader mode.
     *
     * Set the main stack pointer __set_MSP() to its default value.  
     *
     * Note that 0x1FFFC400 is "System Memory" start address for STM32F042
     */
 
    if( *((unsigned long *)0x200017F0) == 0xDEADBEEF )
    {
        *((unsigned long *)0x200017F0) =  0xCAFEFEED; // Reset our magic trigger
        __set_MSP(0x20001800); // set main stack pointer to start of stack
 
                                                       // 0x1fffC400 is "System Memory" start address for STM32F042
        SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1fffC404)); // Point the PC to the System Memory reset vector (+4)
        SysMemBootJump();
    }
    ...
    //Normal SystemInit code here
    ...
}

For this to work correctly the BOOTMODE configuration register must be the following:

  • BOOT_SEL = 0
  • nBOOT0 = 1

NOTE: The register values and boot configuration is specific to the STM32F042. This should work on other chips but you will need to find the correct stack values, end of RAM addresses etc.

View solution in original post

5 REPLIES 5
Uwe Bonnes
Principal II

A mentioned many time before, best is to have some boot switch very early in the application code before any initialization is done and setup and jump to the bootloader is some magic is seen

Hi Uwe, thanks for answering so swiftly.

I did think that might be a better option rather than trying to messily pull myself out mid application. Just so I'm 100% sure I'm understanding correctly:

  • Set a bit in the user flash option bytes (as an example)
  • Reset the chip
  • Read from option bytes and check if bit is set - if it is then jump to bootloader otherwise carry on

Would that sort of logic succeed?

I use some magic word in RAM that the boot process does not initialize. If you have the swicth before ram initialization you can use almost any ram location.

JCame.1
Associate III

*************************************************************************

EDIT: Be careful when implementing this! Setting BOOT_SEL = 0 disables the physical boot pin from working. This has some pretty serious repercussions - if a firmware upgrade fails then there is no way to get the device into bootloader mode (as the code to enter bootloader doesn't exist). To recover the device you must connect and reprogram using the ST Link debugger.

*************************************************************************

For future reference/anyone searching for the same issue:

In the function that gets called when requesting the bootloader:

void StartBootloader(void)
{
    /* The STM32F042 has:
     * 6k SRAM in address: 0x2000 0000 - 0x2000 17FF
     */
    *((unsigned long *)0x200017F0) = 0xDEADBEEF;
 
    // Reset the processor
    NVIC_SystemReset();
 
    /* We then do a check in SystemInit() at startup to see if this 'magic number' has been set */
}

The we do a check at start-up in SystemInit():

void SystemInit(void)
{
    /* Check if we should go into bootloader mode.
     *
     * Set the main stack pointer __set_MSP() to its default value.  
     *
     * Note that 0x1FFFC400 is "System Memory" start address for STM32F042
     */
 
    if( *((unsigned long *)0x200017F0) == 0xDEADBEEF )
    {
        *((unsigned long *)0x200017F0) =  0xCAFEFEED; // Reset our magic trigger
        __set_MSP(0x20001800); // set main stack pointer to start of stack
 
                                                       // 0x1fffC400 is "System Memory" start address for STM32F042
        SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1fffC404)); // Point the PC to the System Memory reset vector (+4)
        SysMemBootJump();
    }
    ...
    //Normal SystemInit code here
    ...
}

For this to work correctly the BOOTMODE configuration register must be the following:

  • BOOT_SEL = 0
  • nBOOT0 = 1

NOTE: The register values and boot configuration is specific to the STM32F042. This should work on other chips but you will need to find the correct stack values, end of RAM addresses etc.

Thanks very much for your help Uwe, all works as intended now!