STM32F091 Saltar al gestor de arranque desde la aplicación

Estoy tratando de implementar un salto al gestor de arranque STM32F091 USART1 desde mi aplicación.

Estoy usando la siguiente función (basada en 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();
}

Desde la nota de la aplicación AN2606: dirección de la memoria del sistema como en la imagen: https://i.imgur.com/nVcgoBg.png

Desde SWD Utility, contenido de la memoria en System Memory: https://i.imgur.com/PeepkrX.png

Desde el depurador, SP y el controlador de reinicio como se muestra en la imagen: https://i.imgur.com/PagQng0.png

Ejecución del programa hasta el punto de interrupción en la dirección del cargador de arranque: https://i.imgur.com/koKfObe.png

Teniendo en cuenta: A - Usando un puente a VCC en el pin BOOT0, puedo acceder con éxito al cargador de arranque del sistema a través de la demostración del cargador flash STM32. No sucede lo mismo si salto al gestor de arranque desde mi aplicación. B - Estoy usando un puente FTDI FT230x USBxSerial.

Preguntas:

1 - Como estoy usando la dirección de memoria absoluta del sistema, no hay necesidad de usar __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(). ¿Correcto?

2 - ¿Me estoy perdiendo algo en esta función?

3 - ¿Hay un tiempo de espera entre el inicio del gestor de arranque y la recepción del byte "0x7F" en USART1?

4 - ¿Abrir/cerrar el puerto serie afectará al gestor de arranque? ¿Tengo que restablecer la MCU si cierro el puerto serie y lo abro de nuevo?

Respuestas (3)

El problema estaba en el estado periférico de USART1. Los valores del registro de configuración USART1 se llevaban a la ejecución del cargador de arranque, lo que posiblemente causaba problemas para el cargador de arranque propietario. La solución fue restablecer USART1 a través de RCC_APB2RSTR.

La función ahora es:

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();
}

Como estoy usando la dirección de memoria absoluta del sistema, no hay necesidad de usar __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH().

... si su programa definitivamente no accede a la memoria "baja". No olvide reasignar la tabla de interrupciones.

¿Abrir/cerrar el puerto serie afectará al gestor de arranque? ¿Tengo que restablecer la MCU si cierro el puerto serie y lo abro de nuevo?

Si realmente está utilizando los pines USART (no la emulación de serie USB): abrir/cerrar el puerto serie solo debería afectar las líneas de control, no las líneas de datos. En la mayoría de los casos, las líneas de control ni siquiera estarán conectadas a la CPU.

Parece algo relacionado con interrupciones u otras configuraciones. La función funciona si se llama justo al comienzo de main().

inserte "__enable_irq();" después de su "__ISB();". Debería funcionar bien.