I'm developing a custom a bootloader on STM32F411VE MCU which must download a .bin file from USB key and flash it into the application sectors of flash memory. Following the examples provided with cube libraries i managed to open correctly the file with the FAT FS system, but I'm having hard times understanding how to exit from the bootloader and jump to my app.

These are the scenarios: 1) Power on the board with no USB Key inserted; the code has no usb stop/deinit/disconnect call -->boot ends its function and jumps correctly to the application. If I plug the USB key during application-life the system reboots. Note that in my application I have no USB driver running 2) Power on with USB key inserted; the code has no usb stop/deinit/disconnect call --> boot fails when setting the MSP of the application:

__set_MSP((uint32_t)*APPLICATION_START_ADDRESS);


3) Power on with no USB Key inserted and USBH_Stop call before jumping to app --> boot fails when setting the MSP of the application

This is my Jump to app implementation. It worked optimally before inserting the USB Host driver

static void JumpToApplication(void)
{
void (*pmain_app)(void);
/* First, disable all IRQs */
__disable_irq();

pmain_app = (void (*)(void))*(APPLICATION_START_ADDRESS + 1);

pmain_app();
}


Thanks a lot for supporting me

• How do you know that it fails when setting the MSP? Can you step through the statement in instruction debug mode (in the disassembly window)? What is the value of the sp register before and after? Can you show the disassembled function? What optimization settings do you use? Jul 13, 2019 at 20:57
• I can say that I'm using medium optimization, while I'm sorry but I'm not able to give you the other answers. Would you be so kind to guide me someway? I'd like to undersand better the cons and dangers related to code optimization Jul 15, 2019 at 8:02

Your overall issue is in trying to branch to an application after a bootloader has heavily operated the system. This is strongly dis-recommended on the STM32, as to get it to work you have to get every aspect of the chip back to a state the application code assumes. Likely more obvious failures include things like having the clock PLL on and selected (as required for USB) and then the application code expected the PLL is not selected when it starts configuring it. But chasing down everything will be extremely frustrating, and you can be left with 90% functionality but 10% seemingly inexplicable weirdness in some peripheral.

Instead, the usual recommendation is to set a flag in memory or the RCC backup registers, reboot the system, and then detect the flag and branch early in startup before doing any configuration. When I needed to implement this I did it in assembly before even the C startup had run; that was probably unnecessary though if you chose to use a memory flag beware of the likelihood of startup code initializing RAM. If entering the bootloader requires explicit action, you wouldn't even need the flag, but only to check that the "stay in bootloader" GPIO or whatever condition is not met, and that there is an application present matching whatever validity check you use.

boot fails when setting the MSP of the application

This is more easily explained. Your code attempts to utilize a local stack variable that was allocated before it changed the stack pointer, which is essentially a recipe for disaster. If you are going to do that, you don't want to make any use of the stack after you change it.

• using a flag in memory to detect the need to init peripherals in bootloader would be for sure a great technique to bypass my problem. On the other hand I might need to implement a bootloader that is able to detect if a USB key is inserted and, eventually, start with FW upgrade by itself. Please note that before initalizing USB I used some timer and clocks and PLL in my bootloader without having any issue. More in detail, I've tested that the function that breaks everything is "USBH_Start". If I don't start USB but just init it, no problem happens Jul 15, 2019 at 6:48
• Your automatic upgrade is not incompatible with doing a self reset to clear state. You are welcome to try to identify and fix the specific issue but the best practice on this platform is to reset - it's where every other version of this question that has been asked ended up Jul 15, 2019 at 10:38