cancel
Showing results for 
Search instead for 
Did you mean: 

Vector table and flash origin addresses when using a bootloader to redirect to one of two apps

LKett.1
Associate II

I am trying to allow an STM32G070x MCU I'm using in a project to be (OTA) updatable by a second MCU. To that end, I followed Viktor Vano's instructions, here and here.

As described there, there is a (secondary) bootloader programmed at flash address 0x8000000 ("partition 1") and two versions of firmware for the MCU to run, at later flash addresses, in my case at 0x08003000 and 0x08011000 ("partition 2" and "partition 3"). The bootloader makes a decision of which firmware version to jump to, then jumps there using an assembly instruction, as also noted in the code here.

That works fine when the two versions of the MCU firmware are programmed to the MCU using the STM32CubeIDE, or similar, and each version has the FLASH  (rx)  : ORIGIN value set to 0x08003000 or 0x08011000 in the STM32G070CBTX_FLASH.ld file, and the VECT_TAB_OFFSET value set to 0x00003000U or 0x00011000U in the system_stm32g0xx.c file. That writes them to the correct place, and the bootloader can jump to one of the two partitions and run the appropriate firmware version.

The problem comes when I get the second MCU to send a new version of the firmware to the STM32 MCU. I want to write this firmware to either "partition 2" or "partition 3", depending on which one has the "oldest" firmware in. For that to be possible, the firmware needs to be writable to either partition (when an update arrives), so that the bootloader can run the new code, to test it works, before marking that firmware version as the "current" one to run on future reboots.

But, since the values for the FLASH  (rx)  : ORIGIN and VECT_TAB_OFFSET are essentially hard-coded into the firmware, if I write firmware that was destined for "partition 2" to "partition 3", the bootloader jumps there, but those FLASH  (rx)  : ORIGIN and VECT_TAB_OFFSET values seem to redirect code execution back to "partition 2".

That means that I'd have to have two versions of the firmware available each time the STM32 MCU needed to have an update, one that works in "partition 2" and one that works in "partition 3", and the second MCU would need to know which one was about to be written (when the update is sent to the STM32 MCU), so it could send the appropriate version for the "partition" (flash location) it would be written into.

I've read a few posts that say that STM's approach with this is "broken", and doesn't really allow for any flexibility where code is written to/run from, without the hard-coding of these addresses, but I'm not sure what would be a better approach.

Does anyone have any suggestions for a way to tackle this, that wouldn't require needing two versions of the firmware sent to the second MCU each time the STM32 MCU needs an update?

Thank you for any help you can give.

15 REPLIES 15
Javier1
Principal

>>I've read a few posts that say that STM's approach with this is "broken", and doesn't really allow for any flexibility where code is written to/run from, without the hard-coding of these addresses, but I'm not sure what would be a better approach.

But it does..... VECT_TAB_OFFSET is just a register some smt32 families have, you could have as many memory partitions as you need.

If you follow the bread crumbs the VECT_TAB_OFFSET is set by SystemInit(). (sets the SCB->VTOR)

You could just modify SystemInit() to set the VECT_TAB_OFFSET you need every time.

 >>Does anyone have any suggestions for a way to tackle this, that wouldn't require needing two versions of the firmware sent to the second MCU each time the STM32 MCU needs an update?

Example:

There is a fixed spot in the flash memory, lets say :

uint32_t * dynamicVECT_TABLE_OFFSET=0x8000A00;//you could even locate it in RAM

 Before jumping to a new application you just modify the content of the memory pointed by dynamicVECT_TABLE_OFFSET.

And all your applications SystemInit() functions are modified to set:

SCB->VTOR=(uint32_t)*dynamicVECT_TABLE_OFFSET;//instead of SCB->VTOR=VECT_TABLE_OFFSET

Extra ball:You could also follow this approach, relocating your vector table to ram .

https://community.st.com/s/question/0D53W00000trgpiSAA/how-to-boot-to-random-address-without-vecttaboffset-stm32f072

I did it for stm32f072(they dont have vector table offset) but it should work for any stm32

we dont need to firmware by ourselves, lets talk
MM..1
Chief III

If only VECT OFFSET is issue , you can simply handle by code position and setup it.

Second question is build address independent code...

Pavel A.
Evangelist III

STM32G0 is Cortex-M0(+) and it does not have SCB.VTOR.

The vector table is located at address 0.

So you have to map the RAM to address 0 (allocate a part of the RAM) and copy here the vector table from the app image.

No assembly is needed, it all can be done in plain C.

Position independent code is slightly less efficient and more complicated to make.

LKett.1
Associate II

Thank you for the suggestions, everyone. I have some things to look into.

It does seem that this processor has VTOR (unless there's some other VTOR?), as I find this code in the file system_stm32g0xx.c (not code I added myself):

void SystemInit(void)
{
 /* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
 SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation */
#endif /* USER_VECT_TAB_ADDRESS */
}

The problem I have with modifying something (at a fixed position) in flash is that I'd need set aside 2 Kbytes of flash in order to modify it (as that's the minimum page erase that allows me to modify something, in a fixed position), and I'm at about the limit of flash usage with all of the things that are going on in the bootloader and firmware partitions.

Maybe something in RAM is the way to go...

Position-Independent Code with GCC for ARM Cortex-M | MCU on Eclipse

only for VTOR simply get PC position in SystemInit code and if < 0x8011000 set VTOR 1 else 2,

but this isnt that simple

Creating a customized/ fixed-up vector table in RAM can deal with different physical address spaces.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

"Unfortunately, it is not that simple. That option opened up a ‘rabbit hole’ with lots of wonderful, powerful and strange things." Yep this is exactly what I mean.

ST could implement a "poor man PIC" in form of remap/relocation base address registers for executable memories, this has been proposed in ideas. Not going to happen, I guess.

gbm
Lead III

All the STM32 series other than F0 have VTOR. I don't know why ST decided to make developer's life harder by setting the VTOR in SystemInit() but it looks like new MCU support packages have this piece of code commented out - good.

In my opinion, the easiest way of dealing with Bootloader or mutiple apps is to leave the VTOR seting to the bootloaer, so that it's value is not hardcoded in the "application" firmware. This way the only place to set the application location (just single ROM base address) in Flash is the linker script and no other pieces of app code need to know the Flash addresses. The Bootloader should set VTOR and SP right before invoking the application. Of course the bootloader must know the app address or addresses.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
MM..1
Chief III

Most simple is create builds for partition2 and too for partition3 and in update process bootloader request what need. Then code dont require be PIC and VTOR is set in build = zero complication.