Jump to Bootloader in STM32 through application i.e using Boot 0 and Boot 1 Pins in Boot mode from User flash

Boot0/1 pins are sampled only when the processor starts, in order to check if it should load the user code from memory or if it should load the bootloader. The state of these pins has no effect of the bootloader afterwards.

I've been faced to a similar request, and found 2 ways to load the bootloader on-demand.

First, you can "JUMP" from user-code to the bootloader. For example, you could jump to the bootloader when a button is pressed.

But... this is far more complicated than a simple JUMP instruction : some registers and devices must be reconfigured correctly to work with the bootloader, you have to ensure that no IRQ will be triggered during the JUMP,... In fact, you have to reconfigure the processor as if it was just started after reset. You can find some information about this technic : on this video from ST.

I managed to do this kind of things on STM32F1xx project. However, on a more complex project based on STM32F4, this would become really difficult... I would have to stop all devices (timers, communication interface, ADC, DAC,...), ensure that no IRQ would be triggered, reconfigure all the clocks,...

Instead, I decided to implement this second solution: When I want to jump to the bootloader, I write a byte in one of the backup register and then issue a soft-reset. Then, when the processor will restart, at the very beginning of the program, it will read this register. This register contains the value indicating that it should reboot in bootloader mode. Then, the jump to the bootloader is much easier, as presented in the youtube video.


You can simulate the bootloader condition. Connect capacitor and paralel resistor from BOOT pin to ground. Connect another free pin to BOOT pin. Capacitor can be charged by external pin and is discharged by resistor. I don't remember exact values you can calculate/experiment them (important is time constant of RC circuit).

Charge this capatitor by setting external pin to 1, perform software reset by NVIC_SystemReset. After reset, it will run bootloader. Resistor connected to Capacitor will perform discharging. After firmware update, you can reset the device and it will run to your application.

We are using this in some applications and it works well. Drawback of this solution is that you need external circuitry, but it is very easy to implement and it is universal for all STM32 devices.


In MicroPython there is a pyb.bootloader() function which is used to enter into DFU mode.

The C code which implements that can be found in their source repository.

I've used the STM32F4 version extensively (the #else block), and the F7 variant a few times (although its been a while).

I'll put the body of the function here since the above links could become stale if that file changes:

// Activate the bootloader without BOOT* pins.
STATIC NORETURN mp_obj_t machine_bootloader(void) {
    pyb_usb_dev_deinit();
    storage_flush();

    HAL_RCC_DeInit();
    HAL_DeInit();

#if defined(MCU_SERIES_F7)
    // arm-none-eabi-gcc 4.9.0 does not correctly inline this
    // MSP function, so we write it out explicitly here.
    //__set_MSP(*((uint32_t*) 0x1FF00000));
    __ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");

    ((void (*)(void)) *((uint32_t*) 0x1FF00004))();
#else
    __HAL_REMAPMEMORY_SYSTEMFLASH();

    // arm-none-eabi-gcc 4.9.0 does not correctly inline this
    // MSP function, so we write it out explicitly here.
    //__set_MSP(*((uint32_t*) 0x00000000));
    __ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");

    ((void (*)(void)) *((uint32_t*) 0x00000004))();
#endif

    while (1);
}

The pyb_usb_dev_deinit() function shuts down USB, and storage_flush writes out any cached filesystem data. The HAL functions come from the STM32Cube HAL files.

If you use a newer version of dfu-util (IIRC 0.8 or newer) then you can specify the -s :leave command line option to have your newly flashed program executed at the end of flashing. Combining with the above I go through flash/test cycles without having to touch the board, and only use BOOT0/RESET when the firmware hard-crashes.

There is also a python DFU flasher called pydfu.py: https://github.com/micropython/micropython/blob/master/tools/pydfu.py which is a little faster than dfu-util.

Tags:

C

Usb

Stm32

Dfu