cancel
Showing results for 
Search instead for 
Did you mean: 

Help to Make Jump from Bootloader to Application Work

Chao
Senior

Hi,

I am trying to make the jump work with an F103RC, and have read many posts in this community, but the jump simply does not work for me. The jump code is mainly from DavidNaviaux in the following post:

https://community.st.com/t5/stm32-mcus-products/jump-to-application-from-bootloader-not-working/td-p/620734

The code in bootloader is downloaded to 0x08000000 via ST-Link:

 

/* USER CODE BEGIN PD */
#define APP_ADDR	0x08010000		// MCU app code base address
#define	MCU_IRQS	102u			// no. of NVIC IRQ inputs

struct app_vectable_
{
    uint32_t Initial_SP;
    void (*Reset_Handler)(void);
};

#define APPVTAB	((struct app_vectable_ *)APP_ADDR)
/* USER CODE END PD */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart5;

/* USER CODE BEGIN PV */
int printOnce = 1;
uint32_t startTick;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_UART5_Init(void);
/* USER CODE BEGIN PFP */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
/* USER CODE END PFP */

/**
  * Bootloader Code
  */
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_UART5_Init();

  /* USER CODE BEGIN 2 */
  startTick = HAL_GetTick();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if (printOnce == 1)
	  {
		  printf("This is in Bootloader\n");
		  printOnce = 0;
	  }
	  if ((HAL_GetTick() - startTick) > 1000)
	  {
			/* Set the clock to the default state */
		  	HAL_UART_DeInit(&huart5);
		    HAL_UART_MspDeInit(&huart5);
			HAL_RCC_DeInit();
			HAL_DeInit();

			/* Disable all interrupts */
			__disable_irq();
//			__disable_interrupt();

			/* Disable Systick timer */
			SysTick->CTRL = 0;

			/* Clear Interrupt Enable Registers & Interrupt Pending Registers */
			for (uint8_t i = 0; i < (MCU_IRQS + 31u) / 32; i++)
			{
				NVIC->ICER[i]=0xFFFFFFFF;
				NVIC->ICPR[i]=0xFFFFFFFF;
			}

			// set the vector table address to the application vector table
			SCB->VTOR = APP_ADDR;

			// Set the stack pointer
			__set_MSP(APPVTAB->Initial_SP);

			__DSB(); // Ensure the VTOR and SP operations are complete
			__ISB(); // Flush the pipeline because of SP change

			/* Re-enable all interrupts */
			__enable_irq();

			// and now jump to the application vector
			APPVTAB->Reset_Handler();
			while (1)
			{
			}
	  }
  }
  /* USER CODE END 3 */
}

 

and the code in the App to which the bootloader jumps to is downloaded to 0x08010000 via ST-Link:

 

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart5;

/* USER CODE BEGIN PV */
int tick = 0;
uint32_t startTick;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_UART5_Init(void);
/* USER CODE BEGIN PFP */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
/* USER CODE END PFP */

/**
  * App Code
  */
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_UART5_Init();

  /* USER CODE BEGIN 2 */
  startTick = HAL_GetTick();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if ((HAL_GetTick() - startTick) > 1000)
	  {
		  tick++;
		  startTick = HAL_GetTick();
		  printf("App tick = %ds\n", tick);
	  }
  }
  /* USER CODE END 3 */
}

 

Please help!

 

1 ACCEPTED SOLUTION

Accepted Solutions
STM_Thirty2
ST Employee

I tested this code and it works fine.

The only thing you did not mention is if you also adjusted the linker script in your application that you're jumping to. Otherwise that application thinks its at 0x08000000 and its not. 

 

 

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx)      : ORIGIN = 0x8010000, LENGTH = 128K
}

 

 

 

If you feel a post has answered your question, please click "Accept as Solution"

View solution in original post

5 REPLIES 5
Chao
Senior

In CubeIDE debugger, the bootloader can run upto the last function call APPVTAB->Reset_Handler() which is a jump into app, and I can't step into the app code. When run in standalone mode, it prints "This is in Bootloader", then nothing happens next.

The app code runs correctly in debugger of CubeIDE or in standalone mode without bootloader when programmed into address 0x08000000. It prints each second.

There must be somewhere wrong in the bootloader code or the app code.

Any comments would be highly appreciated.

 

Almost all looks reasonable, except:
What do you mean by:

APPVTAB->Reset_Handler();

Do you jump to the address (for execution starting there) where the ResetHandler ADDRESS (!!) stored, or do you read the 32bit as an ADDRESS from this location and then you jump to this ADDRESS read before?

You do almost all correctly:
You set the SP new, you relocate the Vector Table to the new one in the "second" code part.

But, maybe, you forget, that ResetHandler in the Vector Table is not instruction, it is just an ADDRESS:

0 : 32bit address for SP top   //ok, you seem to read properly and set it as new SP top
4 : 32bit ADDRESS for ResetHandler entry    //you have to read this value, not jump to this address, just after reading:
                                                                         //jump with the value read first as entry address

If you just jump to VECTOR_TABLE +4 address (which looks to me as you do): there is still vector table (not reasonable code).

STM_Thirty2
ST Employee

I tested this code and it works fine.

The only thing you did not mention is if you also adjusted the linker script in your application that you're jumping to. Otherwise that application thinks its at 0x08000000 and its not. 

 

 

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx)      : ORIGIN = 0x8010000, LENGTH = 128K
}

 

 

 

If you feel a post has answered your question, please click "Accept as Solution"

Thanks a lot for the reply. 

APP_ADDR + 4 contains the address of the main() in App code, so APPVTAB->Reset_Handler()  is actually calling the main() in App or jump to there.

 

struct app_vectable_
{
    uint32_t Initial_SP;
    void (*Reset_Handler)(void);
};

#define APPVTAB	((struct app_vectable_ *)APP_ADDR)

 

Thank you so much for the test, and what you pointed out is exactly the reason why the code didn't work for me. I really didn't know I need to change the linker script, after I have changed the ORIGIN to 0x8010000 and LENGTH to 192K (from 256K), it works:

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 48K
  FLASH    (rx)    : ORIGIN = 0x8010000,   LENGTH = 192K
}

Thank you again!