cancel
Showing results for 
Search instead for 
Did you mean: 

Potentially wrong initial value of SCB->VTOR

dfrejek
Associate III

Good day,

after troubleshooting some issues related to a bootloader, I have figured out that the address of the interrupt vector table (SCB->VTOR) is defined in a hard-coded, non linker aware way as "SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET". This means, if the FLASH region is relocated to make space for a bootloader, it requires manual changes to "VECT_TAB_OFFSET".

Is there any reason, why we don't use the address of "g_pfnVectors" (the actual vector table) instead? This would always point to the vector table as defined in the startup code.

Of course, I can simply add "SCB->VTOR = (uint32_t)&g_pfnVectors;" to the start of the main(), but I'm trying to understand, why the default value is hard-coded instead of using the actual table location.

Can someone explain that to me?

 

CubeMX Version: 6.12.0
Controller: STM32C031K6Tx
Also on STM32G431 with an older CubeMX version

1 ACCEPTED SOLUTION

Accepted Solutions

You are right. I checked with the STM32CubeMX 6.13.0 for the development board STM32C0316-DK. It indeed generates the code as you show.

I agree this is a bug. There are ugly workarounds such excluding system_stm32c0xx.c from build and creating a copy of this file with modifications. Because modifying this file directly will result in it being overwritten when re-generating code.

I think there are several solutions ST could provide:

  1. Use g_pfnVectors
  2. Make proper use of defines so that if USER_VECT_TAB_ADDRESS is defined users can specify the address in other defines and override the defaults.
  3. Create user code sections in system_stm32*.c files just like in all generated files so users can add persistent modifications to generated files.
  4. STM32CubeMX configuration for application offset. This should edit the linker file. Then use g_pfnVectors or generated defines in the application.

3 might be the quickest for them to implement.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

View solution in original post

6 REPLIES 6

I think SCB->VTOR is only assigned if USER_VECT_TAB_ADDRESS is defined.

You could add these lines:

 

 

int main(void) {
  extern void *g_pfnVectors;
  SCB->VTOR = (uint32_t)&g_pfnVectors;

 

 

or

 

 

int main(void) { 
  extern uint32_t g_pfnVectors[];
  SCB->VTOR = (uint32_t)g_pfnVectors;

 

 

 

What I don't understand is that if USER_VECT_TAB_ADDRESS is defined the user cannot define the vector table address. I've written several bootloaders and applications to be loaded by a bootloader and I simple worked around this quirk. You can also set it in the bootloader. It's not user friendly, I agree.

 

And why would the linker need to be aware? VTOR is nothing but a table of pointers to be called by the hardware in case of interrupts or certain events (e.g. hardfault).

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

Thanks for your reply.

I have already implemented in exactly the way you described and it works as intended.

 

>>> I think SCB->VTOR is only assigned if USER_VECT_TAB_ADDRESS is defined.

Sadly no. At least for the C0 and G4 with the respective SDK version. The F0 however does not do this.

Normally, I would set SCB->VTOR in the bootloader before jumping to the application. This assumes, that the application would either use the default value or sets it correctly itself. But for the C0 and G4, the "SystemInit" function overrides these with its own (potentially wrong) defaults.

 

void SystemInit(void)
{
  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

 

It sems a bit strange, that the SystemInit code is doing this. After all, the flash would be mapped to address 0 anyway, so keeping the SCB->VTOR at the default of 0 would be equivalent to assigning FLASH_BASE to it.

You are right. I checked with the STM32CubeMX 6.13.0 for the development board STM32C0316-DK. It indeed generates the code as you show.

I agree this is a bug. There are ugly workarounds such excluding system_stm32c0xx.c from build and creating a copy of this file with modifications. Because modifying this file directly will result in it being overwritten when re-generating code.

I think there are several solutions ST could provide:

  1. Use g_pfnVectors
  2. Make proper use of defines so that if USER_VECT_TAB_ADDRESS is defined users can specify the address in other defines and override the defaults.
  3. Create user code sections in system_stm32*.c files just like in all generated files so users can add persistent modifications to generated files.
  4. STM32CubeMX configuration for application offset. This should edit the linker file. Then use g_pfnVectors or generated defines in the application.

3 might be the quickest for them to implement.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

Thanks for marking my answer as a solution, but I do not consider this solved. Sure you can work around the, but I think ST should fix this.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

Hello, the F0 does not do this because it is a cortex M0 (not +), and as such does not have the VTOR register.

I agree with you that SystemInit shall not do that...

ST has been aware of this for well over a decade, but chooses to need multiple file changes rather than just let the Linker and script define where a specific instance lives.

For the F0, when you have multiple instances in FLASH, you can copy the vectors into the base of RAM and remap that at zero, via SYSCFG or whatever.

Setting VTOR is helpful when you can't guarantee what's mapped at zero. Say the BOOT pins are wrong, the System Loader observed FLASH was blank at initial reset, or the debugger changed expectations. 

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