cancel
Showing results for 
Search instead for 
Did you mean: 

How do I modify an stm32f439vitx system workbench stm32 project for use with a bootloader.

DCarr.1
Senior

I have an existing stm32f439vitx custom board project which works fine when flashed at address 0x08000000 which I now need to make runnable from an existing bootloader expecting the program to have been flashed at address 0x8008000.

Is it enough to change the linker script ROM origin and length?

26 REPLIES 26

Anything that I can think of (wrong latency setting, invalid cache) would prevent the bootloader from starting the original application, or from running at all. I'm afraid you have to debug this bootloader some more.

0690X00000DXCZfQAP.png@berendi​ 

Well well. It looks like I've found the problem.

It turns out that a huge great chunk of the .bin file is surgically removed before being sent to flash (see the picture) as part of a preprocessing step.

I'm surmising that the original firmware programmer didn't know how to compile his code for address 0x08008000 so he compiled for 0x08000000 and managed to convince the linker to put in 0x8000 unused bytes straight after the vector table. The bootloa

The bootloader itself is basically ok, but my problem now is that, for other reasons, I have to use the exact same preprocessor which means that I'm going to have to find a way to duplicate the same .bin file layout. Do you have any ideas on that one?

This line in the last version of the linker script

. = 0x200; /* apparently this should be relative to the section start */

tells the linker to put the stuff following it at 0x200 bytes from the section start.

Replacing it with

. = 0x8200;

and moving back the start of the ROM section to

ORIGIN = 0x08000000

at the top might do the trick.

@berendi​ 

Ok, so it seems to me that what I need in the .bin file is 512 bytes of vector table at 0x08000000 to 0x080001ff, followed by 0x8000 bytes of space from 0x08000200 to 0x080081ff, followed by the rest of the code from 0x08008200, with the "Reset_Handler" being the first part of the rest of the code.

The vector table will end up being flashed at 0x08008000 to 0x080081ff and the rest of the code exactly where it expected to be.

I can see why your setting the origin back to 0x08000000, but I'm a bit lost with the sections and so on. Is that what your mod is doing?

Section is the terminology of the gnu linker for some contiguous memory area to organize stuff into.

Looks like I haven't used the proper terminology in my previous post, ROM is a memory, not a section. Input sections go into an output section, and output sections go into a memory. But I'm not sure about the exact definition.

Having .isr_vector as a name for both an input and an output sector does not really help understanding it all.

Anyway, .isr_vector (followed by a colon) is the name of the output section which gets loaded first into the ROM memory area, so it starts at wherever ROM memory starts. It contains the input section named .isr_vector (the one in KEEP()), which would then start wherever the output section starts.

The . (dot) is a special variable called the output pointer. It can be moved around with simple assignments or arithmetic expressions. (Moving it backwards would produce weird results though.) The . is counted from the start of the output section, which is in turn the same as the start of ROM memory, so we set it relative to that. When ROM starts at 0x08000000,

.=0x8200

would place the stuff following in, .mystartup, at 0x08008200.

Got it.

The linker seems to be doing the right thing:

.isr_vector     0x08000000     0x8250
                0x08000000                . = ALIGN (0x4)
 *(.isr_vector)
 .isr_vector    0x08000000      0x1ac startup/startup_stm32.o
                0x08000000                g_pfnVectors
                0x00008200                . = 0x8200
 *fill*         0x080001ac     0x8054 
 *(.mystartup)
 .mystartup     0x08008200       0x50 startup/startup_stm32.o
                0x08008200                Reset_Handler
                0x08008250                . = ALIGN (0x4)
 
.text           0x08008280    0x373ac
                0x08008280                . = ALIGN (0x4)
 *(.text)

Although running it directly in the debugger, I can see that there's still something wrong (the SysTick_Handler defined in my stm32f4xx_it.c is never called). No doubt due to some of my other panicky modifications.

Thanks again massively for all the help

Slight update.

I realised that when I run the program directly in the debugger, I need to set SCB->VTOR to 0x08000000 (and that works now). The processed version still needs its SCB->VTOR set to 0x08008000 though and that, sadly, still seems to misbehave. I think I'm going to have to compare what's in the file with what's in FLASH using a binary editor and STlink utility.

@berendi​ 

So. Here's what I know (remember, the bootloader does one of two things, it either jumps directly to the firmware or downloads the firmware and then does a reset which triggers jumping directly to the bootloader):

(0) The bootloader does some inexplicable chicanery with the vector table pointer and the stack pointer before jumping to the firmware.

(1) I build my firmware for address 0x08008000 with the reset handler at 0x08008200 and SCB->VTOR to 0x08000000 and then program it into flash manually at 0x08008000 using ST-link. Resetting runns through the bootloader's "jump to firmware" and starts my firmware, confirming that the bootloader's initialisate, deinitialise, jump to firmare functionality can execute valid binaries at 0x08008000.

(2) I build my firmware for address 0x08000000 with 0x8000 bytes padding from the end of the vector table through to the start of the code (so at 0x08008200), set SCB->VTOR to 0x08000000 in the reset handler and then program it into flash manually at 0x08000000 using ST-link. Resetting the MCU executes the firmware directly, confirming that my firmware works with the vector table at the start of flash and the code at 0x08008200.

(3) I manually strip the padding byte section from the bin file, let the bootloader program the flash and compare my stripped binary to the memory contents at 0x08008000. The first 0x200 bytes of .bin are now at 0x08008000 and everything from 0x8200 onwards in the file is where it would have been anyway, (tentatively) confirming that the binary starting at 0x08008000 is valid.

Needless to say, it doesn't work. So, given (1), (2) and (3), I conclude that shifting the vector table from 0x08000000 to 0x08008000 has somehow broken something. 

With the exception of the first entry, the vector table is just a bunch of absolute pointers to functions so moving it around can't really make any difference. Bearing that in mind, and coupled with (0), I'm thinking about the stack.

The .ist vector section is defined like this (from output.map, I see _estack = 0x20030000):

.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
 
g_pfnVectors:
    .word _estack
    .word Reset_Handler
    .word NMI_Handler
    ..

The very first two instructions in my reset handler (ie, well before SCB->VTOR has been set to point to my vector table) are

ldr  r0, =_estack
mov  sp, r0     /* set stack pointer */

Are these instructions doing this:

 "load r0 with the absolute value 0x20030000"

  

or this:

 "load r0 with the value stored in the first word of the vector table"

I'm hoping it's the second, because that would explain pretty much everything.

Update.

As a small experiment I coded my own trivial bootloader: 

extern "C" int main() {
	asm (
		   "MOVW        R0, #65532;"
		   "MOVT        R0, #8192;"
		   "MOV         SP, R0;"
 
		   "MOVW        R0, #0x8201;"
		   "MOVT        R0, #0;"
		   "BLX         R0;"
	);
}

Which I programmed into flash at 0x08000000 and my stripped firmware at 0x08008000. This failed to run, which kind-of confirms that my stripped and relocated firmware is not valid.

I then replaced

Reset_Handler:
    ldr  r0, =_estack
    mov  sp, r0     /* set stack pointer */

with

Reset_Handler:
  movw    R0, #0
  movt    R0, #8195
  mov     SP, R0 /* set stack pointer */

and then after reset then MCU successfully booted through my trivial bootloader to my stripped and relocated firmware.