2024-06-19 04:45 AM
Hello.
I am developing a UART bootloader. Currently developing it on the Nucleo H7S3L8 that sports the STM32H7S3L8 microcontroller, 65K flash, ~450K something RAM.
I have implemented the ol' JumpToApplication pattern that can be found all over the internet:
typedef void (*pFunction)(void);
#define FLASH_APP_START_ADDRESS ((uint32_t)0x8008000U)
#define BOOTLOADER_START_ADDRESS ((uint32_t)0x8000000U) // Just for testing
void JumpToApp(void)
{
const uint32_t jump_address = *(__IO uint32_t*) (FLASH_APP_START_ADDRESS + 4U);
const pFunction jump_to_application = (pFunction) jump_address;
SCB->VTOR = FLASH_APP_START_ADDRESS;
uint32_t sp_addr = *(__IO uint32_t*)FLASH_APP_START_ADDRESS;
__set_MSP(sp_addr);
__enable_irq();
jump_to_application();
}
If I use the BOOTLOADER_START_ADDRESS as jump_address, it will (just as expected) jump back to the ResetHandler of the bootloader, that resides in the startup.s file (generated from CubeIDE). So I have verified that my "jumping" works, and it can jump arbitrarily many times.
If I use the FLASH_APP_START_ADDRESS however, it does not work. Rather, while stepping in Instruction Stepping Mode, I can successfully jump to the address where my App ResetHandler resides (which happens to be 0x080086C5) so that I hit the first assembly instruction:
/* Address 080086c4 will be hit when stepping from "jump_to_application" */
080086c4: ldr r0, [pc, #60] @ (0x8008704)
080086c6: mov sp, r0
080086c8: ldr r4, [pc, #60] @ (0x8008708) /* Debug dummy instruction, not in originally generated startup file */
080086ca: ldr r4, [pc, #64] @ (0x800870c) /* Debug dummy instruction */
080086cc: ldr r4, [pc, #64] @ (0x8008710) /* Debug dummy instruction */
080086ce: bl 0x8008698
080086d2: ldr r0, [pc, #64] @ (0x8008714)
080086d4: ldr r1, [pc, #64] @ (0x8008718)
And I have verified the assembly instructions are the same here where I have flashed the app, comparing the same memory area when I flash the app through CubeIDE with SWD.
However, when I step to the next instruction, everything goes haywire, the PC goes to some invalid address 0xFFFFFFFF and the assembly view is broken. Looking at the registers, I see the following
Here is the start of the linker script from my bootloader
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
__FLASH_BEGIN = 0x08000000;
__FLASH_SIZE = 64K;
__RAM_BEGIN = 0x24000000;
__RAM_SIZE = 0x71C00;
__RAM_NONCACHEABLEBUFFER_SIZE = 0x400;
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = __RAM_BEGIN, LENGTH = __RAM_SIZE
RAM_NONCACHEABLEBUFFER (xrw) : ORIGIN = __RAM_BEGIN + __RAM_SIZE, LENGTH = __RAM_NONCACHEABLEBUFFER_SIZE
ITCM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x00010000
DTCM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000
SRAMAHB (rw) : ORIGIN = 0x30000000, LENGTH = 0x00008000
BKPSRAM (rw) : ORIGIN = 0x38800000, LENGTH = 0x00001000
FLASH (xrw) : ORIGIN = __FLASH_BEGIN, LENGTH = __FLASH_SIZE
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
etc...
And here's the linker script of my application:
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
__FLASH_BEGIN = 0x08008000;
__FLASH_SIZE = 32K;
__RAM_BEGIN = 0x24000000;
__RAM_SIZE = 0x71C00;
__RAM_NONCACHEABLEBUFFER_SIZE = 0x400;
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = __RAM_BEGIN, LENGTH = __RAM_SIZE
RAM_NONCACHEABLEBUFFER (xrw) : ORIGIN = __RAM_BEGIN + __RAM_SIZE, LENGTH = __RAM_NONCACHEABLEBUFFER_SIZE
ITCM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x00010000
DTCM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000
SRAMAHB (rw) : ORIGIN = 0x30000000, LENGTH = 0x00008000
BKPSRAM (rw) : ORIGIN = 0x38800000, LENGTH = 0x00001000
FLASH (xrw) : ORIGIN = __FLASH_BEGIN, LENGTH = __FLASH_SIZE
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
etc...
In many of the resources online about this "jump to application" pattern states that you should Deinit HAL, RCC, disable interrupts, write certain bits to control memory locations etc., which is probably true for doing it robustly, but jumping back to my bootloader ResetHandler seems to work just fine without doing all that stuff, so I figured that for now it should work without it (and believe me, I have tried with all that stuff too and it still doesn't work).
And I have disabled the MPU (or rather, I have not enabled it, and it didn't work with it either). The only thing I had to keep in my bootloader main was "SCB_EnableDCache", because without it writing to flash wasn't working for whatever reason.
So what could I be missing?
Solved! Go to Solution.
2024-07-17 12:30 PM
2024-06-19 04:56 AM - edited 2024-06-19 04:58 AM
So a quick update, when flashing both projects at the same time (and of course not transferring code using UART) using a debug configuration in STM32CUBEIDE, (i.e. adding both .elf files into the configuration, but entering on the bootloader elf), stepping through the app code works just fine.
2024-06-19 05:12 AM
Another update, comparing the application memory region (starting at 0x0800_8000, length 32K), it's identical when comparing the bytes there, whether the region was populated by the bootloader from reading UART transmission of the app, or when the app was flashed together with the bootloader from CubeIDE over SWD... So the code is the same, and still it doesn't work? =/
2024-06-19 06:06 AM
Another update, I set up so that both bootloader and application are flashed through CubeIDE SWD, I then copy all the bytes of the application memory area (0x08008000, length 8232 bytes) to some memory I allocated on the heap using malloc, I then flash the application through UART (still during the same session), then compare the application memory area with the memory copied to my heap buffer, and they are IDENTICAL!!!
I don't get it, I put the exact same bytes in the application memory area, and then it doesn't work...
2024-06-19 07:26 AM
Yet another update, copying the SWD downloaded app flash to a malloc'ed buffer, then erasing the app flash, then writing to the app flash again makes things not working (all this in the same run session). So even if I copy the data, then write the exact same data back, it doesn't work. Seems like I can't execute on flash memory that has been erased/written to...
Have I missed "releasing" some sort of flash write resource? I use HAL_FLASH_Lock after every manipulation of the flash memory... Or is there some memory protection mechanism that prevents me from executing on flash sectors that have been erased/written to?
2024-06-19 08:14 AM - edited 2024-06-19 08:14 AM
Update 5/x: Tried adding SCB_InvalidateDCache before jumping to application, didn't work...
2024-06-19 09:59 AM
Blind use of SCB_InvalidateDCache() can be highly destructive, like throwing away pending writes to RAM / Stack Frame/Context. It's the Nuke from Orbit method.
Always use the byAddr form to avoid collateral damage.
2024-06-19 10:12 AM
Yeah sounds like a bad idea to use it...
Any idea on what could be wrong with my original problem? Not being able to execute from flash that I have erased and then written to...
2024-07-17 12:30 PM