cancel
Showing results for 
Search instead for 
Did you mean: 

Boot on QSPI => VTOR change in BOOT or APP firmware ?

COSEBE
Senior

Hi,

Can someone clarify why some examples of boot to QSPI change the SCB->VTOR register in JumpApp function :

SCB->VTOR = (uint32_t)Application_vector;
JumpToApp = (pFunction) (*(__IO uint32_t *)(Application_vector + 4u));
__set_MSP(*(__IO uint32_t*) Application_vector);

And some examples change the SCB->VTOR register in void SystemInit(void) function:

SCB->VTOR = 0x90000000;

 

I think both works but is there a best way and can someone explain the advantage and the inconvenient to update VTOR register in BOOT project or APP project.

7 REPLIES 7

Hi,

Changing the vector table means you tell the mcu its new place. Normally, each firmware should have its own vector table including application. SCB->VTOR = (uint32_t)Application_vector in jump function could be delayed until you make the jump to application but you need to make sure you won't have any interrupts until you call SystemInit in application. I recommend doing the following:

- Call jump function (disable interrupts)

- Jump to Application

- Call SystemInit from startup file

- Set new vector table address SCB->VTOR = (uint32_t)Application_vector

There's significant flexibility here.

The loader knows where the image is situated.

The linker fixes the location, and the absolute addresses within the vector table.

ST has SystemInit() set it based on compiler defines, but COULD use Linker symbols to set based on a pointer, and then you wouldn't need to change multiple files, and the loader / app could use the same code.

When using QSPI, it would be recommended to set up the clocks, PLL, QSPI interface/pins ONCE, in the loader, and then not repeat that work with a mapped memory and running system in the app.

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

Usually you don't want the interrupt vectors table located in external flash. Better copy it to the internal RAM and set VTOR to the address in the internal RAM.

Hi,

OK, so in your opinion, you recommend to set new vector table in APPLICATION firmware in SystemInit function.

You write : - Call jump function (disable interrupts)

If I disable interrupt with __disable_irq() in BOOT firmware, shoud I enable it in APPLICATION firmware in SystemInit function ?

Hi,

Does it mean you also recommend to change VTOR in APPLICATION SystemInit function ?

For the QSPI configuration, this is what I did : Configuration and mapped mode is only set up in LOADER.

Hi,

 

That is interesting !

ST examples do not do this (what I see).

Does it means :

1. I configure QSPI on mapped memory, in LOADER

2. __Disable_IRQ() in LOADER

3. Jump to the APPLICATION (in QSPI 0x90000000), in LOADER

4. Copy the interrupt vector of the APPLICATION in internal RAM (any address location), in SystemInit() APPLICATION

5. set the VTOR register to this RAM location, in SystemInit() APPLICATION

7. __EnableIRQ() in SystemInit() APPLICATION

 

Do you have an example that I can use as inspiration?

MY preference would be to make the application images as free standing as possible, setting the SP and enabling interrupts in Reset_Handler.

The loader would be highly robust provide several modes of recover, and validating/authenticating anything before calling it. The worst situation is for a corrupt or partial firmware in QSPI basically bricking the system.

You might want multiple application images you can call, and for methods for staging and updating the primary application.

I'd have most of the board bring-up code in the loader, so contractually I wouldn't need to do that again.

Decide what code is responsible for what.. and do that consistently.

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