STM32F091 Von der Anwendung zum Bootloader springen

Ich versuche, von meiner Anwendung aus einen Sprung zum STM32F091 USART1-Bootloader zu implementieren.

Ich verwende die folgende Funktion (basierend auf https://community.st.com/thread/40238-stm32l476rg-jump-to-bootloader-from-software ):

void SB_SystemBootloaderJump()
{
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;

    HAL_RCC_DeInit();

    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    /**
     * Step: Disable all interrupts
     */
    __disable_irq();

    /* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
    __DSB();

//  __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()
//  ;

//  /* Remap is bot visible at once. Execute some unrelated command! */
//  __DSB();
//  __ISB();

    JumpToApplication = (void (*)(void)) (*((uint32_t *) ((0x1FFFD800 + 4))));

    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*) 0x1FFFD800);

    JumpToApplication();
}

Von APP Note AN2606: Systemspeicheradresse wie im Bild: https://i.imgur.com/nVcgoBg.png

Vom SWD-Dienstprogramm Speicherinhalte im Systemspeicher: https://i.imgur.com/PeepkrX.png

Von Debugger, SP und Reset-Handler als Bild: https://i.imgur.com/PagQng0.png

Programmausführung bis zum Haltepunkt an der Bootloader-Adresse: https://i.imgur.com/koKfObe.png

In Anbetracht: A - Mit einem Jumper zu VCC am BOOT0-Pin kann ich über die STM32 Flash Loader-Demo erfolgreich auf den System-Bootloader zugreifen. Das Gleiche gilt nicht, wenn ich von meiner App zum Bootloader springe. B - Ich verwende eine FTDI FT230x USBxSerial Bridge.

Fragen:

1 - Da ich die absolute Systemspeicheradresse verwende, muss __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(). Richtig?

2 - Übersehe ich etwas bei dieser Funktion?

3 - Gibt es eine Zeitüberschreitung zwischen dem Start des Bootloaders und dem Empfang des "0x7F"-Bytes auf USART1?

4 - Wirkt sich das Öffnen/Schließen der seriellen Schnittstelle auf den Bootloader aus? Muss ich die MCU zurücksetzen, wenn ich die serielle Schnittstelle schließe und wieder öffne?

Antworten (3)

Das Problem war mit dem USART1-Peripheriestatus. Die USART1-Konfigurationsregisterwerte wurden zur Bootloader-Ausführung übertragen, was möglicherweise Probleme für den proprietären Bootloader verursachte. Die Lösung war, USART1 über RCC_APB2RSTR zurückzusetzen.

Die Funktion lautet nun:

void SB_SystemBootloaderJump()
{
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;

    __HAL_RCC_USART1_FORCE_RESET();
    HAL_Delay(5);
    __HAL_RCC_USART1_RELEASE_RESET();
    HAL_Delay(5);

    HAL_RCC_DeInit();

    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    /**
     * Step: Disable all interrupts
     */
    __disable_irq();

    /* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
    __DSB();

    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()
    ;

    /* Remap is bot visible at once. Execute some unrelated command! */
    __DSB();
    __ISB();

    JumpToApplication = (void (*)(void)) (*((uint32_t *) ((0x1FFFD800 + 4))));

    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*) 0x1FFFD800);

    JumpToApplication();
}

Da ich die absolute Systemspeicheradresse verwende, muss __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH() nicht verwendet werden.

... wenn Ihr Programm definitiv nicht auf den "low" Speicher zugreift. Vergessen Sie nicht, die Interrupt-Tabelle neu zuzuordnen.

Wirkt sich das Öffnen/Schließen der seriellen Schnittstelle auf den Bootloader aus? Muss ich die MCU zurücksetzen, wenn ich die serielle Schnittstelle schließe und wieder öffne?

Wenn Sie wirklich die USART-Pins verwenden (nicht die serielle USB-Emulation): Das Öffnen/Schließen des seriellen Ports sollte nur die Steuerleitungen betreffen, nicht die Datenleitungen. In den meisten Fällen werden die Steuerleitungen nicht einmal mit der CPU verbunden.

Es sieht tatsächlich so aus, als hätte es etwas mit Interrupts oder anderen Konfigurationen zu tun. Die Funktion funktioniert, wenn sie gleich zu Beginn von main() aufgerufen wird.

"__enable_irq();" einfügen nach Ihrem "__ISB();". Es sollte gut funktionieren.