Electronic – EXTI stops working after jumping to the new firmware STM32L4

microcontrollerstm32

I am working on an application on the STM32L4 microcontroller. The idea is when I press the user button, the bootloader jumps from the main application (0x08000000) to the second one (0x08080000).

The second firmware is just a blinking LED application. The jumping is fine and the LED starts blinking, but my problem is that when I want to go back from the second application to the first one (0x08000000) the exti won't work!

Here's my code:

First firmware:

if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
{
    /* Jump to user application */
    JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
    JumpToApplication = (pFunction) JumpAddress;

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

    __disable_irq;
    SCB->VTOR = FLASH_BASE | 0x80000;

    HAL_RCC_DeInit();
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
    __set_PRIMASK(1);

    printf("Starting Firmware 2 . . .  \r\n");
    HAL_DeInit();
    JumpToApplication();
}

The beginning of the second firmware:

  SCB->VTOR = FLASH_BASE | 0x80000;
  __set_PRIMASK(0);
  HAL_Init();

  SystemClock_Config();

  HAL_InitTick(1);

This is the exti callback from the second firmware:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    HAL_NVIC_ClearPendingIRQ(EXTI15_10_IRQn);
    HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);

    if (GPIO_Pin == GPIO_PIN_13)
    {
        if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
        {
            JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
            JumpToApplication = (pFunction) JumpAddress;

            __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);

             HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);
            __disable_irq;
             SCB->VTOR = FLASH_BASE;
            JumpToApplication();
        }
    }
}

Why is this not working?

Best Answer

You are starting the other application from within the interrupt serice routine, never returning from the interrupt handler. The system won't execute the same interrupt handler (or any other handler with the same or lower priority) until a proper exception return sequence is executed. You should somehow exit all active handlers before jumping to the other firmware.

Simplest method is to set a global volatile flag in the interrupt handler, and check it periodically in your main applocation loop.

You can also reset the system using NVIC_SystemReset(). You'd need a way to check and communicate where did the reset request come from, as it always goes to the first application.

Also note that __disable_irq; does nothing, you'd need () to actually call a function. It's always a good idea to enable and check compiler warnings.