I am attempting to write a custom bootloader for a STM32F103C8Tx (64k Flash, 20k RAM variant) on a bluepill board.
When the jump from the bootloader occurs the application immediately hardfaults on the next step from the entry point of the application.
I can confirm that SCB->VTOR
is set to 0x08005000
. If I single step the bootloader it does jump to address 0x8005004
.
Here is the stack trace at the jump.
The next step resulting in the hardfault.
Note the call to address 0xfffffffe
witch (I believe) is out of scope of the memory map. I have no idea how to debug this.
Edit: I found the exact instruction where the hardfault occurs in the GDB output. 0x08005014
08005000: 00 50 str r0, [r0, r0]
08005002: 00 20 movs r0, #0
08005004: 35 54 strb r5, [r6, r0]
08005006: 00 08 lsrs r0, r0, #32
08005008: c9 53 strh r1, [r1, r7]
0800500a: 00 08 lsrs r0, r0, #32
0800500c: cf 53 strh r7, [r1, r7]
0800500e: 00 08 lsrs r0, r0, #32
08005010: d7 53 strh r7, [r2, r7]
08005012: 00 08 lsrs r0, r0, #32
08005014: dd 53 strh r5, [r3, r7]
Something I have noticed is that when I run the application from debug
or Terminate and Relaunch
, the application runs fine with no problem while the bootloader is in flash.
If I reset the MCU or the bootloader is not in flash, I get the hardfault.
Additional context
Both BOOT pins are set to 0 to set it to boot from the main flash memory.
The bootloader is placed at 0x8000000
and the application is placed at 0x8005000
.
Bootloader linker script:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 19K
}
Application linker script:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8005000, LENGTH = 36K
}
The application vector table is set as follows:
#define VECT_TAB_OFFSET 0x00005000U
Note: I have written the bootloader in C++ and not C, so there is some name mangling from the map file.
I have modified the startup_xxx.s
file to immediately call the bootloader jump. This is to avoid de-initializing any peripherals or interrupts that may interfere with the application.
LoopFillZerobss:
cmp r2, r4
bcc FillZerobss
bl _Z6blCallv
/* Call the clock system intitialization function.*/
Call the jump to the application
void blCall(void){
typedef void (*jump_app)(void);
uint32_t _jump = (uint32_t) (__IO uint32_t*)0x08005000;
jump_app app_jump = (jump_app) (_jump + 4);
SCB->VTOR = _jump;
__set_MSP(_jump);
app_jump();
}
I also tried this with the same result as per @Justme's suggestion.
void blCall(void){
typedef void (*jump_app)(void);
uint32_t _jump = (uint32_t) (__IO uint32_t*)0x08005000;
jump_app app_jump = (jump_app) (_jump + 4);
SCB->VTOR = _jump;
__set_MSP(_jump + 4);
app_jump();
}
Switched from C++ to C with no change in the result.
The application is nothing special. It is basically a default generated CubeIDE main with the external HSE set and some GPIO pins for LEDs. The application runs fine if I remove the vector table offset.
IDE: STM32CubeIDE V1.9.0
Debugger: Segger J-Link EDU
startup.s
. The bootloader should only init the RAM and Flash from what I understand. In its current state. I had the bootloader de-init any interrupts and clear any flags with the same result. What is shown here is me systematically trying to eliminate any cause of the hardfault over about 2 weeks. \$\endgroup\$0x08005004
? \$\endgroup\$