3
\$\begingroup\$

I've written a bootloader application for NXP Kinetis microcontroller. Following are the things I did to do the same: 1. Created a bootloader application in CFlash addresses 0x0000 to 0x8000 2. Created my main application code from addresses 0x8000 to 0x1FFFF

This code is working fine. Now my doubt is, I have ISRs placed in both bootloader as well as main application code and didn't use any ISR vector relocation. Is it necessary to relocate the vector tables in main application?

PS: I may not be facing the issue just because the ISRs in both the apps are same.

\$\endgroup\$
  • \$\begingroup\$ You will be facing the issue, the table of the bootloader cannot be equal to the user application, unless the bootloader doesn't have one. (do not forget the exception handlers!) \$\endgroup\$ – Jeroen3 Sep 5 '18 at 7:37
1
\$\begingroup\$

You do not need to relocate the vector table--the toolchain should correctly locate your vector table in your binary--but you do need to tell the MCU where the correct vector table is located, as well as where the stack pointer should start, when you jump from bootloader to application. By default, on ARM cores, the vector table is found at the very beginning of your application binary. The first entry will be the initial stack pointer, and the second entry will be the reset vector (the application entry point). The rest of the entries are defined by the specific ARM architecture as well as the specific implementation.

At startup or a hardware reset, the hardware will initialize the Vector Table Offset Register to 0x00000000, set the stack pointer to the first value in the vector table, and then jump to the location given in the second entry in the table. But when you jump from a bootloader to the application, you have to do each of those things yourself.

\$\endgroup\$
2
\$\begingroup\$

Yes - you have to relocate your vector table, otherwise the interrupts will fire handlers of the bootloader, which will almost certainly lead to a crash.

First you modify the linker script to "move the flash" a little bit higher (eg. 0x8000 in your case), this will also mean that the new vector table starts at 0x8000, unless you remove it all together and place it in RAM - but that is a slightly different topic (remember about the 256-byte alignment requirement for the NVIC in that case).

I usually use a piece of code like this to jump to the application:

#define APPLICATION_BASE 0x8000
__attribute__((noreturn)) static void start_application(void){

    SCB->VTOR = APPLICATION_BASE; //move interrupt vector base
    typedef void (*function_void_t)(void);
    #define avuint32(avar) (*((volatile uint32_t *) (avar)))

    function_void_t application;
    application = (function_void_t)(avuint32(APPLICATION_BASE+4));

    __DSB();
    application();
    __builtin_unreachable();
}

The "jump" is offset by 4 because the first word in the blob is the initial stack pointer, the second word is the reset vector of the application. This code will make the application use the stack of the bootloader, so you may have to tweak it a little (some bytes of the stack will be lost because they were used by the bootloader).

\$\endgroup\$
0
\$\begingroup\$

The last step your bootloader must do before passing control to your application's start address is to initialize the LR register and then point the MCU's vector table to the application's vector table.

\$\endgroup\$
  • 2
    \$\begingroup\$ Perhaps you meant to say initialize the stack pointer? That is necessary unless you want the main application to inherit a partially used stack. But initializing the LR should not matter - the entry point of the application should never try to return. \$\endgroup\$ – Chris Stratton Sep 5 '18 at 4:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.