Page 1 of 1

Calling stm32 internal bootloader from application

Posted: Tue Jan 19, 2016 9:46 am
by geoffroy
Hi Giovanni,

We are trying to calling the STM32 SystemMemory Bootloader from our application,
but we encountered some problems.

In order to make bootloader working, it's necessary to do some stuff before : (from ST documentation)

Disable all peripheral clocks
• Disable used PLL
• Disable interrupts
• Clear pending interrupts

Here is my function which enters in bootloader mode :

Code: Select all

void enter_bootloader_mode()
{
   chSysDisable();

   //shut down any tasks here ...

   uint32_t application_address = 0x1FF01FFE; //corresponding to stm32l152RE <=== code crash here
   __set_MSP( * (__IO uint32_t*) application_address);
   bootJump = *(__IO uint32_t*) (application_address + 4);
   bootJump();
   
   while(1);
}


But, every time, debugger stop at :
__set_MSP( * (__IO uint32_t*) application_address)
and I get a : _unhandled_exception(void) { ... }
in vectors.c

apparently, reading address 0x1FF01FFE is not permitted ..
Have you any ideas about what is occurring ?

Thanks in advance for any help ..
Geoffroy

Re: Calling stm32 internal bootloader from application

Posted: Tue Jan 19, 2016 10:21 am
by vambwodonk
Hi, Geoffroy

Maybe you need more than ChSysDisable(). You need to stop entire OS like this
http://wiki.chibios.org/dokuwiki/doku.php?id=chibios:howtos:stop_os

Tell us if you successful with this project, :D

Re: Calling stm32 internal bootloader from application

Posted: Wed Jan 20, 2016 12:32 am
by flabbergast
The way I do it is that I patch the ResetHandler supplied with chibios, so that it reads a word at the end of the memory, and if it matches a predefined value, it jumps to the bootloader. This jump is "safe" because nothing has been initialised yet, it is just after a reset. Now when I want to jump to bootloader from the application, I just write the predefined word to the end of the memory and request reset.

To see the code, see here.
Here are the important bits: The actual patch to crt0 chibios code is here; the correct bootloader address is passed in the Makefile like this; and finally the jump in the application is implemented here.

EDIT: This approach may work without patching chibios by performing the bootloader-jump-check in the __early_init() function, which can be redefined in the board definition files. I have not tried this yet.

Re: Calling stm32 internal bootloader from application

Posted: Wed Jan 20, 2016 9:15 am
by Giovanni
Editing __early_init() is legit, it is like creating new board files.

Giovanni

Re: Calling stm32 internal bootloader from application

Posted: Thu Jan 21, 2016 12:19 pm
by geoffroy
@flabbergast

We tested the solution about patching chibios. It's working great ;-)

Thanks ! :D

Re: Calling stm32 internal bootloader from application

Posted: Thu Jan 21, 2016 6:24 pm
by flabbergast
Good to know! Just to give credit where it is due, my approach is based on this forum thread.

Also, I have now moved the required code to board definition files, so patching core chibios code is no longer needed: the modifications to the board files are like this to the header and this to the __early_init function; calling from the main application is still the same (but it uses now the BOOTLOADER_MAGIC define instead of the straight value) and BOOTLOADER_ADDRESS should be now passed in the Makefile in UDEFS (not UADEFS) and as a string constant (not a number constant), like this.

I'm sure the inline assembly bit can be replaced by some C magic one-liner with lots of brackets and stars, but I'm not good enough to know how ;)

Re: Calling stm32 internal bootloader from application

Posted: Mon Apr 11, 2016 8:01 pm
by trainman419
I'm trying to do the same thing with ChibiOS 3.0.5 on an STM32F407, and it doesn't seem to be working. Is there something that has changed in the Reset_Handler on newer versions of ChibiOS?

I can enter the bootloader by pulling BOOT0 high, but the jump into the bootloader from __early_init() doesn't work:

Code: Select all

#define BOOTLOADER_ADDRESS 0x1FFF0000

    /* Remap the system memory onto address 0 */
    asm("LDR r0, =0x40023844;" /* RCC_APB2ENR */\
        "LDR r1, =0x00004000;" /* enable SYSCFG clock */\
        "STR r1, [r0, #0];"\
        "LDR r0, =0x40013800;" /* SYSCFG_MEMRMP */\
        "LDR r1, =0x00000001;" /* remap ROM at zero */\
        "STR r1, [r0, #0];");

    /* Jump into the bootloader
     * Page 70 of the reference manual (RM0090) describes how to set up the
     * stack pointer and jump to the bootloader
     *
     * Load the initial stack pointer value from the first location in memory
     * then Jump to the next address */
    asm("LDR r0, =%[Is];"\
        "LDR r1, [r0, #0];"\
        "MOV sp, r1;"\
        "LDR r0, [r0, #4];"\
        "BX  r0;"\
        : : [Is] "i" (BOOTLOADER_ADDRESS));


I've also added the remap of address 0 as suggested by https://my.st.com/public/STe2ecommuniti ... views=1164 , but it doesn't seem to be helping.

Re: Calling stm32 internal bootloader from application

Posted: Tue Apr 12, 2016 12:44 am
by flabbergast
I have actually discovered that the approach I described does not quite work (on F042) because F042's bootloader *always* checks the BOOT0 pin (and the only other possibility is setting the option byte) - so the only reliable way I found to not just jump to the bootloader code but also stay there is to devise a hardware way to keep BOOT0 high during that check (e.g. a RC circuit).

I don't think the ResetHandler code has changed recently, and my understanding is that actually not much happens before the __early_init() function is called.

Re: Calling stm32 internal bootloader from application

Posted: Thu Apr 14, 2016 9:08 am
by LHelge
What is the benefit of doing this in __early_init() instead of in the beginning of main() I can the that the former is called first by the bootup code but will it make any difference?`

I would rather have the bootloader check in main() for two reasons, the __early_init() will be overwritten each time I generate new board-files from the config XML. And I think it would be cleaner to keep as much application code as possible out of the board-files.

Re: Calling stm32 internal bootloader from application

Posted: Thu Apr 14, 2016 12:20 pm
by Giovanni
Hi,

__early_init() comes before memory initialization and static constructors which can be slow, so it is the right place for clock-up and urgent initializations.

Said that, it could be moved elsewhere, it does not have to be in board files.

Giovanni