cancel
Showing results for 
Search instead for 
Did you mean: 

Custom Bootloader Testing & Debug

AAgar.2
Associate III

I am trying to write a custom bootloader. I have compiled both bootloader and application binaries and concatenated them in the makefile. When I flash the device with the binary (via ST-Link) my application is not booting up.

1) I suspect the issue is with incorrectly setting the location of SCB->VTOR. If my application starts at address 0x8002000 what is the correct location of the application VTOR?

2) I suspect the issue could also be with incorrect concatenation of the .bin files (i.e. padding the application binary). I have posted the code which I used to concatenate the files. Is this the correct way to do so?

3) Is there a way for me to debug what is exactly wrong? Its difficult because I cannot go into debug mode with the concatenated binary.

Appreciate your time.

My bootloader memory config is as follows: 

// In bootloader.ld
 
MEMORY
{
 RAM  (xrw)   : ORIGIN = 0x20000000, LENGTH = 160K
 BOOT   (rx)  : ORIGIN = 0x8000000, LENGTH = 8K
 FLASH  (rx)  : ORIGIN = 0x8002000, LENGTH = 502K
}
 
__bootrom_start__ = ORIGIN(BOOT);
__bootrom_size__ = LENGTH(BOOT);
__approm_start__ = ORIGIN(FLASH);
__approm_size__ = LENGTH(FLASH);

My application memory config is as follows: 

// In application.ld
 
MEMORY
{
 RAM  (xrw)   : ORIGIN = 0x20000000, LENGTH = 160K
 FLASH  (rx)  : ORIGIN = 0x8002000, LENGTH = 498K
}

Below is the code in for my bootloader: 

// In bootloader.h
 
#pragma once
 
#include <stdint.h>
#include "stm32l4xx_hal.h"
 
extern int __bootrom_start__;
extern int __bootrom_size__;
extern int __approm_start__;
extern int __approm_size__;
 
void bootloader_init(void);

// In bootloader.c
 
void bootloader_init(void)
{
	uint32_t *app_code = (uint32_t) &__approm_start__;
	uint32_t sp = &(app_code[0]);
	uint32_t pc = &(app_code[1]);
	__disable_irq();
 
	SCB->VTOR = &(app_code[0]);
 
	// Jumping to application stack pointer
 
	__asm__ __volatile__("mov sp,%0\n\t"
			"bx %1\n\t"
			: /* no output */
			: "r" (sp), "r" (pc)
			: "sp");
 
	// Should never reach here
	while (1) {}
}

I have compiled both bootloader and application binaries and concatenated them via the following lines in the makefile. Where STM32L452RE _Bootloader_Boot.bin is just the bootloader binary and STM32L452RE _Boot.bin is the bootloader+application concatenated library.

STM32L452RE_Bootloader_Boot.bin: $(EXECUTABLES)
	arm-none-eabi-objcopy --gap-fill=0xFF --pad-to 0x2000 -O binary $(EXECUTABLES) "STM32L452RE_Bootloader_Boot.bin"
	@echo 'Finished building: $@'
	@echo ' '
 
STM32L452RE_Bootloader.bin: $(OBJCOPY_BIN) $(APPLICATION)
	cat $^ > $@
	@echo 'Finished concatenating: $@'
	@echo ' '

1 ACCEPTED SOLUTION

Accepted Solutions
NWeis.19
Associate II

Check out the examples for STm32F4 etc.. should be the same.

On F4 with Keil I had no issues.

in file system_stm32xxx.c (can be system_stm32f4xx. c or similar)

at the end of SystemInit function add the following:

 /* Configure the Vector Table location add offset address ------------------*/

#ifdef BOOT_LOADER

 // Vector Table Relocation in Internal BL area FLASH

 NVIC_SetVectorTable(FLASH_BASE_ADDR, BL_VEC_OFFSET);

#else

 // Vector Table Relocation in Internal APP area FLASH

 NVIC_SetVectorTable(FLASH_BASE_ADDR, APP_VEC_OFFSET); 

#endif

You can use the same file for the boot loader and application. In your boot loader project you just need to add a define in your compiler settings BOOT_LOADER

This solves the VTOR definition. If you do not have NVIC_SetVectorTable you can simply change the code to

#ifdef BOOT_LOADER

 // Vector Table Relocation in Internal BL area FLASH

 SCB->VTOR = FLASH_BASE | BL_VEC_OFFSET; 

#else

 // Vector Table Relocation in Internal APP area FLASH

 SCB->VTOR = FLASH_BASE | APP_VEC_OFFSET; 

#endif

------------------------------------------------------------------------------------------------------

As for the boot loader the jump to application is done from main as follows:

typedef void (*pFunction)(void);

static void LoadUserApp(void)

{

 static pFunction Jump_To_Application;

 static uint32_t JumpAddress;

 /* Initialize Flash */

 HAL_FLASH_Lock();

 // test if jump address to were vector table is located is in RAM

 // starts at address0x20xxxxxx

 if(((*(__IO uint32_t*)APP_BASE_ADDR) & 0x2F000000) == 0x20000000)

 {

   JumpAddress = *(__IO uint32_t*)(APP_BASE_ADDR + 4);

   // Jump to user application

   Jump_To_Application = (pFunction) JumpAddress;

   // Initialize user application's Stack Pointer

   __set_MSP(*(__IO uint32_t*)APP_BASE_ADDR);

   __set_CONTROL(0);

   Jump_To_Application();

   // we should not get here !!!

   while(1);

 }

The above worked for me but for some reason in the WB55 with Atollic it does not ????

What IDE are you using ?

View solution in original post

3 REPLIES 3
NWeis.19
Associate II

Check out the examples for STm32F4 etc.. should be the same.

On F4 with Keil I had no issues.

in file system_stm32xxx.c (can be system_stm32f4xx. c or similar)

at the end of SystemInit function add the following:

 /* Configure the Vector Table location add offset address ------------------*/

#ifdef BOOT_LOADER

 // Vector Table Relocation in Internal BL area FLASH

 NVIC_SetVectorTable(FLASH_BASE_ADDR, BL_VEC_OFFSET);

#else

 // Vector Table Relocation in Internal APP area FLASH

 NVIC_SetVectorTable(FLASH_BASE_ADDR, APP_VEC_OFFSET); 

#endif

You can use the same file for the boot loader and application. In your boot loader project you just need to add a define in your compiler settings BOOT_LOADER

This solves the VTOR definition. If you do not have NVIC_SetVectorTable you can simply change the code to

#ifdef BOOT_LOADER

 // Vector Table Relocation in Internal BL area FLASH

 SCB->VTOR = FLASH_BASE | BL_VEC_OFFSET; 

#else

 // Vector Table Relocation in Internal APP area FLASH

 SCB->VTOR = FLASH_BASE | APP_VEC_OFFSET; 

#endif

------------------------------------------------------------------------------------------------------

As for the boot loader the jump to application is done from main as follows:

typedef void (*pFunction)(void);

static void LoadUserApp(void)

{

 static pFunction Jump_To_Application;

 static uint32_t JumpAddress;

 /* Initialize Flash */

 HAL_FLASH_Lock();

 // test if jump address to were vector table is located is in RAM

 // starts at address0x20xxxxxx

 if(((*(__IO uint32_t*)APP_BASE_ADDR) & 0x2F000000) == 0x20000000)

 {

   JumpAddress = *(__IO uint32_t*)(APP_BASE_ADDR + 4);

   // Jump to user application

   Jump_To_Application = (pFunction) JumpAddress;

   // Initialize user application's Stack Pointer

   __set_MSP(*(__IO uint32_t*)APP_BASE_ADDR);

   __set_CONTROL(0);

   Jump_To_Application();

   // we should not get here !!!

   while(1);

 }

The above worked for me but for some reason in the WB55 with Atollic it does not ????

What IDE are you using ?

AAgar.2
Associate III

Dude sweet.

Just tried the examples and got it working!

I'm using the STM32CubeIDE.

Thanks

NWeis.19
Associate II

Great for you,

for some reason I cannot get it to work with Atollic 😂