ARMmbed / mbed-os

Arm Mbed OS is a platform operating system designed for the internet of things
https://mbed.com
Other
4.68k stars 2.98k forks source link

Hook before SystemInit to jump to USB DFU bootloader (STM32) #7853

Closed martinjaeger closed 5 years ago

martinjaeger commented 6 years ago

Description

I want to use the built-in DFU bootloader of the STM32F072. It can be initialized using the BOOT0 pin or by software.

To start it via software, a magic code has to be written to a defined address and a reset is initiated. The presence of the magic code has to be checked before or at the beginning of SystemInit. If it is present, the device jumps to the bootloader instead of starting up.

Example function to activate bootloader:

void dfu_run_bootloader()
{
    // set magic code 0xDEADBEEF
    // STM32 F072 has 16k SRAM in address 0x2000 0000 - 0x2000 3FFF
    *((unsigned long *)0x20003FF0) = 0xDEADBEEF;

    NVIC_SystemReset();
}

Example function to be called before SystemInit():

void __bootloader_manager(void)
{
    // function pointer
    void (*SysMemBootJump)(void);

    // Add this to SystemInit() in system_clocks.c
    if ( *((unsigned long *)0x20003FF0) == 0xDEADBEEF) {

        // reset the trigger
        *((unsigned long *)0x20003FF0) =  0xCAFEFEED; 

        // set stack pointer
        __set_MSP(0x20002250);  // bootloader stack pointer

        // point the PC to the System Memory reset vector (+4)
        // 0x1fffC800 is "System Memory" start address for STM32 F0xx
        SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1fffC804)); 
        SysMemBootJump();

        while (42);
    } else {
        SystemInit();
    }
}

I suggest to define a weak function in the target startup code which is called at the very beginning of SystemInit(). So it can be overwritten in order to define own "bootloader jump" code.

Or is there a different (more elegant way) to implement this feature?

Issue request type

[ ] Question
[X] Enhancement
[ ] Bug

martinjaeger commented 6 years ago

This comment on stackoverflow states that CubeMX HAL actually defines a weak function for this purpose:

void __attribute__((weak)) __initialize_hardware_early(void);

But I can't find this definition in the mbed sources anywhere. [Mirrored to Jira]

0xc0170 commented 6 years ago

Look at mbed boot code file (contains information there in comments). I cant locate the document that would describe it (cc @AnotherButler ).

Looking at your requirements: SystemInit is the first function to be run (invoked from startupfile, even before __main invoked, where other hooks are present later).

We provide bootloader, see https://os.mbed.com/docs/latest/tutorials/bootloader.html - isn't this what you are looking for?

@ARMmbed/team-st-mcd Please review [Mirrored to Jira]

martinjaeger commented 6 years ago

The referenced mbed bootloader is stored in the flash before the actual application code. So it reduces the amount of available flash memory.

Many STM32 MCUs have a built-in bootloader in system memory which does even work if the flash got corrupted. I would like to use that one instead. [Mirrored to Jira]

AnotherButler commented 6 years ago

@0xc0170 Are you looking for this? https://os.mbed.com/docs/v5.9/reference/runtime.html [Mirrored to Jira]

martinjaeger commented 6 years ago

I guess the mbed_main is also too late, as all clocks are already initialized. The jump to the bootloader should happen right after reset, i.e. at the beginning of SystemInit(). [Mirrored to Jira]

screamerbg commented 6 years ago

@0xc0170 Can we remove the devices:st tag from issue? Seems like this is rather about Mbed OS than ST. [Mirrored to Jira]

0xc0170 commented 6 years ago

@ARMmbed/team-st-mcd Please review

Can you review this use case? [Mirrored to Jira]

adustm commented 6 years ago

Hi @martinjaeger STM32s have a way to jump to a boot-code. This is not used within mbed-os, that already has a feature for bootloader. Providing a weak implementation for system_init sounds too risky.

I would suggest that you have your own patch for startup function, calling your function before the call to system init. Such a solution has been implemented some time ago for STM32F4 family (https://github.com/ARMmbed/mbed-os/blob/f5fb3c19113f662d5dbc3d565e2160f6cf532ad9/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F429xI/device/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.S#L111)

You would need to patch this https://github.com/ARMmbed/mbed-os/blob/83fc2e2d201ce2e95963b9fe6ac3199f80cc2650/targets/TARGET_STM/TARGET_STM32F0/TARGET_NUCLEO_F072RB/device/TOOLCHAIN_GCC_ARM/startup_stm32f072xb.S#L100

       bcc FillZerobss  
/* start patch */
ldr r0, =your_boot_function 
blx r0
/* end of patch */
    /* Call the clock system intitialization function.*/    
    bl SystemInit   

[Mirrored to Jira]

adbridge commented 6 years ago

Internal Jira reference: https://jira.arm.com/browse/IOTPART-6211

martinjaeger commented 6 years ago

@adustm thanks for your suggestion.

Problem with patching the mbed repository is that I am working on open source hardware and I want to make it as easy as possible for users to get started (i.e. not spend days of setting up toolchains etc.). So I am using mbed with PlatformIO. But PlatformIO automatically integrates the mbed environment from the official repositories.

Unfortunately, it doesn't seem to be easy to define a custom board (even for known MCU) without pushing it to the main repository. This would be the ideal solution as I could also adjust other settings (like the timer for the us_ticker) which are not compatible with my custom board design.

Do you see any chance to have something in the official mbed repository to execute own code at the beginning of SystemInit() without the need to patch the official repository? Could also be a define:

#ifdef MBED_SYSTEM_INIT_HOOK_PRESENT
mbed_pre_startup()
#endif

Or similar way as mbed_die(), which I am also overloading to get flashing LEDs if something goes wrong in my custom board.

0xc0170 commented 6 years ago

@c1728p9 @SenRamakri Please review this enhancement request

c1728p9 commented 6 years ago

Hi @martinjaeger as a possible alternative, what about hooking the weak function mbed_main and then using mbed_start_application() to powerdown the system and jump to STs ROM bootloader? This is the mechanism the mbed-os bootloader uses to start an application.

martinjaeger commented 6 years ago

@c1728p9 Thanks, that sounds like a good approach. Will try it next week (no access to HW now) and give feedback.

martinjaeger commented 6 years ago

Tried to use the mbed_start_application(), but it is not enabled for STM32L0 and STM32F0, which I am using. MBED_APPLICATION_SUPPORT is only enabled for larger MCUs >= Cortex M3. Any reason for that?

jeromecoutant commented 5 years ago

@martinjaeger Should we close this ST issue ? Thx

martinjaeger commented 5 years ago

Yes, jumping to the embedded bootloader via software doesn't work anyway with the STM32L072 micros I am using because of their dual memory bank layout.