Skip to main content
Explorer II
July 10, 2024
Solved

Problem to Jump from bootloader to application on STM32F412

  • July 10, 2024
  • 1 reply
  • 1638 views

Good morning everyone,
I am trying to modify a bootloader that is already in production and working.
My problem is that if I call the JumpToApplication() function right after peripheral initialization (as the production bootloader does), everything works perfectly.
However, if I call it from within the infinite loop or even after exiting the loop, as you can see from the attached code, the jump does not work.
I can't explain why.
Additionally, I wanted to ask two more things:

  1. Is it necessary to define the array volatile uint32_t stack_arr[30]? I have never seen it in any bootloader.

  2. In the statement pmain_app = (void (*)(void)) * (APPLICATION_START_ADDRESS + 1); I see that there is a +1 at the end, but in various examples, I always see +4. Yet it still works!!!

Can you give me some advice?
Thank you.

 

 

 

 

#include "main.h"
#include "dma.h"
#include "fatfs.h"
#include "spi.h"
#include "usb_host.h"
#include "gpio.h"
#include "crc.h"

extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
extern TIM_HandleTypeDef htim11;

static uint16_t tim_boot_x1ms = 0;
volatile static uint8_t timRefreshDisplay_x1ms = 0;

void SystemClock_Config(void);
void MX_USB_HOST_Process(void);

void JumpToApplication(void);

int main(void)
{
 volatile uint32_t stack_arr[30] = {0}; // Allocate some stack
 // just to show that
 // the SP should be reset
 // before the jump - or the
 // stack won't be configured
 // correctly.

 HAL_Init();
 SystemClock_Config();

 static void JumpToApplication(void)
 MX_GPIO_Init();
 __enable_irq();
 MX_DMA_Init();
 MX_SPI1_Init();
	MX_USB_HOST_Init();
 MX_FATFS_Init();
	MX_CRC_Init();

 //JumpToApplication(); //JumpToApplication called here works fine

 static bool endLoop = false;

 while(!endLoop)
 {
 MX_USB_HOST_Process();

		retStatus_t ret = USB_FW_Update_Process();
 
		switch(ret)
		{
			case retNothing:
			break;

			case retJump:
				__disable_irq();
				endLoop = true;
			break;

			case retReset:
				NVIC_SystemReset();
			break;
		}
 }

	JumpToApplication();
}


void JumpToApplication(void)
{
 //Deinit all peripherals
	HAL_SPI_MspDeInit(&hspi1);
 HAL_TIM_Base_DeInit(&htim11);
	HAL_CRC_MspDeInit(&hcrc);
	__HAL_RCC_USB_OTG_FS_CLK_DISABLE();
	__HAL_RCC_DMA2_CLK_DISABLE();
 __HAL_RCC_SPI1_CLK_DISABLE();
 __HAL_RCC_TIM1_CLK_DISABLE();
 __HAL_RCC_GPIOA_CLK_DISABLE();
	__HAL_RCC_GPIOB_CLK_DISABLE();
	__HAL_RCC_GPIOC_CLK_DISABLE();
	__HAL_RCC_GPIOD_CLK_DISABLE();

 void (*pmain_app)(void);

 __disable_irq();

 SCB->VTOR = (uint32_t)APPLICATION_START_ADDRESS;
 __set_MSP((uint32_t)*APPLICATION_START_ADDRESS);
 pmain_app = (void (*)(void)) * (APPLICATION_START_ADDRESS + 1);

 // JUMP TO APP!
 pmain_app();
}

 

 

 

 

 

    This topic has been closed for replies.
    Best answer by SDall.11

    Hi, I rearranged the function as you can see below and it works fine:

    void jumpToApplication(void)
    {
     void (*pmain_app)(void);
    
     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_All);
     HAL_GPIO_DeInit(GPIOB, GPIO_PIN_All);
     HAL_GPIO_DeInit(GPIOC, GPIO_PIN_All);
     HAL_GPIO_DeInit(GPIOD, GPIO_PIN_All);
    
     HAL_SPI_MspDeInit(&hspi1);
     HAL_CRC_MspDeInit(&hcrc);
    
     HAL_TIM_Base_DeInit(&htim11);
     HAL_DeInit(); 
    
     __disable_irq();
    
     __DSB();
     __ISB();
    
     SCB->VTOR = (uint32_t)APPLICATION_START_ADDRESS;
     __set_MSP((uint32_t)*APPLICATION_START_ADDRESS);
    
     pmain_app = (void (*)(void)) * (APPLICATION_START_ADDRESS + 1);
     pmain_app();
    }

     

    1 reply

    Graduate II
    July 10, 2024

    Hi,

    Can you please elaborate more? How it is not working? Does it show hard fault? 

    What does this function do USB_FW_Update_Process?

     

     

     

    Super User
    July 10, 2024
    pmain_app = (void (*)(void)) * (APPLICATION_START_ADDRESS + 1);

    That line works only if APPLICATION_START_ADDRESS is defined something like this:

    #define APPLICATION_START_ADDRESS ((void *)(0x08010000))

    Since it is defined as a "pointer to void", pointers are 32-bit values (aka 4 bytes).  So incrementing a pointer increments the actual value by 4.

    The stack_arr[] variable is not used anywhere, not sure why it is there.

    As to why your application fails when you call JumpToApplication() in or after that loop - just a wild guess but you do not de-initialize the USB interface, you only turn off the clock.  Presuming your application uses the USB interface, as soon as it enables the clock it MAY get an interrupt, and the USB data structures have not yet been fully enabled and the registers have not be reset - so who knows what the interrupt handler will do.  Most likely hit a memory fault.

    SDall.11Author
    Explorer II
    July 11, 2024

    Good morning everyone and thank you for your responses.
    First of all, I apologize for omitting in the previous post the define concerning the assignment of  APPLICATION_START_ADDRESS.
    I have conducted further tests to understand more and to provide you with a more complete picture.
    As already mentioned previously, I confirm that if I place JumpToApplication() right before the while(true) loop, everything works correctly.
    I have also noticed that if I do not initialize any peripherals, the JumpToApplication() also works within the while loop.
    So, I started to perform selective initializations, but even with the first initialization, MX_GPIO_Init(), the JumpToApplication() works outside the while loop but not inside.
    And yet, I think I am deinitializing everything correctly, what am I doing wrong?
    Thank you.

    #include "main.h"
    #include "dma.h"
    #include "fatfs.h"
    #include "spi.h"
    #include "usb_host.h"
    #include "gpio.h"
    #include "crc.h"
    
    extern TIM_HandleTypeDef htim11;
    extern const uint32_t app_vector; 
    
    #define APPLICATION_START_ADDRESS (uint32_t *)&app_vector
    
    
    void SystemClock_Config(void);
    void MX_USB_HOST_Process(void);
    void JumpToApplication(void);
    
    
    int main(void)
    {
     HAL_Init();
     SystemClock_Config();
     MX_GPIO_Init();
     __enable_irq();
    
     volatile static int xxx;
    
     //JumpToApplication() //Here works
    
     while(true)
     {
    		retStatus_t ret = retNothing;
    
     if(xxx++ >= 10000) ret = retJump;
    
    		switch(ret)
    		{
    			case retNothing:
    			break;
    
    			case retJump:
    				__disable_irq();
    				JumpToApplication();
    			break;
    
    			case retReset:
    				NVIC_SystemReset();
    			break;
    		}
     }
    }
    
    void JumpToApplication(void)
    {
     __HAL_RCC_GPIOA_CLK_DISABLE();
    	__HAL_RCC_GPIOB_CLK_DISABLE();
    	__HAL_RCC_GPIOC_CLK_DISABLE();
    	__HAL_RCC_GPIOD_CLK_DISABLE();
    
     HAL_TIM_Base_DeInit(&htim11);
    
     void (*pmain_app)(void);
    
     __disable_irq();
    
     __HAL_RCC_CRC_CLK_DISABLE();
    
     SCB->VTOR = (uint32_t)APPLICATION_START_ADDRESS;
     __set_MSP((uint32_t)*APPLICATION_START_ADDRESS);
     pmain_app = (void (*)(void)) * (APPLICATION_START_ADDRESS + 4);
    
     __DSB();
     __ISB();
    
     pmain_app();
    }