Accessing the STM32 System Bootloader

The STM32 range of Microcontrollers have a built in bootloader that may be used to update the firmware running on the MCU. Depending upon the STM32 variant being used this update may be done using a USART, USB, or SPI interface. The usual way of triggering the bootloader is by using the BOOT1 and BOOT0 pins of the MCU:

Typically the BOOT1 pin is held high on the hardware and bootloader mode is controlled by a hardware jumper on BOOT0. These pins are sampled upon restart of the MCU and require access to a reset button (or power-cycle) and the BOOT0 jumper.

For devices that are deeply embedded in a system accessing the a hardware jumper for the BOOT0 control may not be practical. Indeed, on some systems where General Purpose Input/Output pins are at a premium, the designer may require the BOOT0 pin for GPIO.

What is required in the above situations is a means of forcing the MCU into system bootloader mode from the resident firmware. The following code snippet enables the system bootloader to be accessed from the main firmware and possibly triggered by a USB or USART command.

void platform_request_boot(void)
{
    typedef void (*pFunction)(void);
    const uint32_t ApplicationAddress = 0x1FFF0000;
    register uint32_t JumpAddress = 0;
    register uint32_t addr = 0x20018000;
    static pFunction Jump_To_Application;
    /* We start here */
    cm_disable_interrupts ();
    uint32_t value = 0 - 1;
    NVIC_ICER (0) = value;
    NVIC_ICER (1) = value;
    NVIC_ICER (2) = value;
    NVIC_ICPR (0) = value;
    NVIC_ICPR (1) = value;
    NVIC_ICPR (2) = value;STK_CSR = 0;
    /* Reset the RCC clock configuration to the default reset state ------------*/
    /* Reset value of 0x83 includes Set HSION bit */
    RCC_CR |= (uint32_t) 0x00000082;
    /* Reset CFGR register */
    RCC_CFGR = 0x00000000;
    /* Disable all interrupts */
    RCC_CIR = 0x00000000;
    FLASH_ACR = 0;
    __asm volatile ("isb");
    __asm volatile ("dsb");
    cm_enable_interrupts ();
    JumpAddress = *((uint32_t *) (ApplicationAddress + 4));
    Jump_To_Application = (pFunction) JumpAddress;
    /*
         set up the stack for the bootloader
     */
    __asm__ ("mov sp,%[v]" : : [v]"r"(addr));
    Jump_To_Application ();
}

Noted that above code is for the GCC ARM compiler and also uses the libOpenCM3 library.

Sid.