cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4: jump to MCU bootloader

Werner Dähn
Associate II
Posted on June 01, 2018 at 07:54

I think I got the concept of how to jump to the MCU built-in bootloader but I never got it working. And often information is opposing each other.

My requirement is simple and very common, hence I hope somebody has code at hand. I am fed up with trying and trying.

I have a USB CDC connection, and enter commands there. One command should be 'boot to MCU bootloader' which would disconnect the USB and make the MCU appear in the DfuSeDemo tool. As if I manually disconnected the the board, pressed the Boot0 button and power it while button pressed.

Source Code can be found here: 

https://github.com/wernerdaehn/CC3D-CableCam-Controller

  

Nothing special, standard memory layout etc.

#stm32f4-dfu-usb-bootloader
16 REPLIES 16
...
    .text
    .thumb
 
    .align 2
    .thumb_func
    .globl   Reboot_Loader
    .type    Reboot_Loader, %function
Reboot_Loader:
    // Device specific, if in doubt RTFM, here F2/F4
 
    LDR     R0, =0x40023844 // RCC_APB2ENR
    LDR     R1, =0x00004000 // ENABLE SYSCFG CLOCK
    STR     R1, [R0, #0]
    LDR     R0, =0x40013800 // SYSCFG_MEMRMP
    LDR     R1, =0x00000001 // MAP ROM AT ZERO
    STR     R1, [R0, #0]
    LDR     R0, =0x1FFF0000 // ROM BASE
    LDR     SP,[R0, #0]     // SP @ +0
    LDR     R0,[R0, #4]     // PC @ +4
    BX      R0
     .pool // sourcer32@gmail.com
    .size Reboot_Loader, . - Reboot_Loader
 
    .align 2
    .thumb_func
    .globl    Reset_Handler
    .type    Reset_Handler, %function
Reset_Handler:
 
    LDR     R0, =0x2001FFF0 // End of SRAM for your CPU
    LDR     R1, =0xDEADBEEF
    LDR     R2, [R0, #0]
    STR     R0, [R0, #0] // Invalidate
    CMP     R2, R1
    BEQ     Reboot_Loader
 
/*     Loop to copy data from read only memory to RAM. The ranges
 *      of copy from/to are specified by following symbols evaluated in
 *      linker script.
 *      __etext: End of code section, i.e., begin of data sections to copy from.
 *      __data_start__/__data_end__: RAM address range that data should be
 *      copied to. Both must be aligned to 4 bytes boundary.  */
...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Werner Dähn
Associate II

Yes, that does work perfectly. Thank you so much!

I have seen your solution at multiple places but never understood what to do in detail. Now it is clear - afterwards.

I love micro controller programming. 😉

Tobi as
Associate II

Hi,

sorry it doesn't run in my project. I use the IDE from Atollic and haven't the file "startup_stm32f4xx.s.

If I used "__set_PRIMASK(0x20001000);" in the following code, then it runs when I don't initialize USB.

If I set "__set_PRIMASK(0x20001000);" in the following code as comment, then I get an error when I don't initialize USB.

If I initialize USB, then I becomme an error regardless of "__set_PRIMASK(0x20001000);".

void jumpToBootloader(void) {
   void (*SysMemBootJump)(void);
   volatile uint32_t addr = 0x1FFF0000;
 
   RCC_DeInit();
 
   SysTick->CTRL = 0;
   SysTick->LOAD = 0;
   SysTick->VAL = 0;
 
   SYSCFG->MEMRMP = 0x01;
 
   SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
 
   __disable_irq();
   __set_PRIMASK(1);      // Disable interrupts
// __set_PRIMASK(0x20001000);     // Set the main stack pointer to its default value
   __set_MSP(*(uint32_t *)addr);
 
   SysMemBootJump();
   while(1);
}

Have you a idea? Thanks for your help.

Stop disabling interrupts on the processor, as I've repeatedly said there's no magic on the otherside to enable them, the processor usually resets to get into the ROM based system loader, and interrupts are NOT disabled then.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Tobi as
Associate II

Hi Clive,

thanks for your answer. I have now set the following lines as comment:

//   __disable_irq();

//   __set_PRIMASK(1);

But I have the same effect as before...

Werner Dähn
Associate II

The provided code did work for 5 times, but after that Windows was not able to recognize the USB device after the system boot any longer. I had to again unplug the cable and reconnect.

As I guessed it was a timing issue, I added some code for disabling USB first and a short delay. Since then no more problems. So my C code is at the moment.

void JumpToBootloader(void) {
    *((unsigned long *)0x2001FFF0) = 0xDEADBEEF; // End of RAM
 
    USBD_Stop(&hUsbDeviceFS);
    USBD_DeInit(&hUsbDeviceFS);
    HAL_Delay(5000); // Wait for 5 seconds so that it looks to Windows as if the USB cable has been unplugged.
 
    NVIC_SystemReset();
}

Tobi as
Associate II

Hi Werner,

thanks for the very helpful information. My code run, when I unplug and reconnect the cable. 🙂

This is sufficient for my application.

But can you tell me what the function USBD_Stop(&hUsbDeviceFS); does in detail? This function isn't available in my code.