2020-04-18 10:37 AM
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 ' '
Solved! Go to Solution.
2020-04-18 12:45 PM
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 ?
2020-04-18 12:45 PM
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 ?
2020-04-18 10:26 PM
Dude sweet.
Just tried the examples and got it working!
I'm using the STM32CubeIDE.
Thanks
2020-04-18 11:10 PM
Great for you,
for some reason I cannot get it to work with Atollic :face_with_tears_of_joy: