Skip to main content
Visitor II
July 9, 2024
Question

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

  • July 9, 2024
  • 4 replies
  • 2905 views

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.

    This topic has been closed for replies.

    4 replies

    Graduate II
    July 9, 2024

    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

    COSEBEAuthor
    Visitor II
    July 9, 2024

    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 ?

    Graduate II
    July 10, 2024

    I recommend to set the VTOR in the main of application before you re-enable the interrupts. 

     

    Graduate II
    July 9, 2024

    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.

    COSEBEAuthor
    Visitor II
    July 9, 2024

    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.

    Graduate II
    July 9, 2024

    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.

    Super User
    July 9, 2024

    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.

    COSEBEAuthor
    Visitor II
    July 9, 2024

    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?

    COSEBEAuthor
    Visitor II
    July 11, 2024

    You all seem to prefer changing VTOR in the app.
    And yet, all the examples in the ST CUBE repository that I found do the opposite. Do you know why ?

     

     

    @Pavel A.  propose to copy the vector table in RAM and update the VTOR after.

    Does someone have an example project on a STM32H7 MCU doing this ?

    Graduate II
    July 11, 2024

    >> Do you know why ?

    Does it matter?  ST has historically set it in SystemInit(), via a bunch of #defines

    Disabling the MCU IRQ, and where the table changes shouldn't be important. You shouldn't have interrupts firing. If you point at the new vector table, all the RAM and peripheral instances are completely out of context. And they way the HAL/CUBE examples work the status-quo won't be resolved until deeper into main()

    What you should be doing is tearing down all interrupts / peripheral so the hand-over is clean