Hello,
In our project I want to examine the case, when vector table relocated to RAM (ITCM region 0x00000000)
My evaluation board: MIMXRT1060-EVK.
The application is allocated on QSPI.
My workbench: IAR 8.32.2
Attached original icf file.
What changes is required to move the vector table to RAM place?
Any example?
int main(void)
{
/* Init board hardware. */
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
BOARD_InitBootPeripherals();
.....
}
Kind Regards,
Leon.
I know this question already is answered, but maybe for "the next guy" who tries to achieve the same. I did the following:
1 - disable managed linker script and move the generated linker script
2 - adjust the linker script to your needs
3 - Adjust the startup code so that stuff gets copied over and VTOR pointer points to new location
Before you do anything, make sure you compiled your program so that you can steal the generated working linker scripts sitting in the Debug folder of your project.
Then afterwards, right click on project and open properties.
In the same window, adjust the location of the linker script one folder up so that it no longer sits in Debug folder (which gets nuked when you clean the app, and you would loose your changes).
Optionally, you can also merge the three generated linker scripts into one, for me it doesn't add anything to have the linker script scattered over three files. If you choose to leave them separated, you also need to fix the include paths of the 2 included linker scripts.
Then simply drag the linker script (or if you didn't merge, linker scripts) from Debug folder one folder up (in the root of the project).
If you open the linker script in its new location, you'll see the part where stuff gets added to .text.
I preferred to have the vector table in its own section. That's not mandatory of course, so edit as your please. I changed it to the following:
.vector : ALIGN(4)
{
__vector_table_flash_start__ = ADDR(.vector) ;
KEEP(*(.isr_vector))
__vector_table_flash_end__ = ABSOLUTE(.) ;
. = ALIGN(4) ;
} >SRAM_ITC AT>PROGRAM_FLASH
I added this, right after the boot_hdr part.
So what we do here, is we defined some linker variables which will get the address location at the start of the vector tables, and one at the end. Nice would be to also add LOADADDR(.vector) to get the address of the part in ITC memory, but since it's 0x0 anyway I didn't bother.
PS: make sure you properly clean up the KEEP(*(.isr_vector)) from the .text section, since it has no purpose anymore there. The linker won't duplicate the vector, but it's confusing to leave in "dead code".
That's it, off to the start up code
This looks a bit bloated, but since the ResetHandler (aka ResetISR) is a naked attributed function, I am a bit scared to define variables on the stack. I'm a bit scared to write any code, since i don't exactly know where the limitations lie, but at least the following will do the trick
Define the extern variables, and whatever we need as stack variable, we'll just declare them globally instead.
volatile extern unsigned int __vector_table_flash_start__;
volatile extern unsigned int __vector_table_flash_end__;
unsigned int *vector_table_flash;
unsigned int *vector_table_itc;
unsigned int index;
unsigned int vector_table_size;
And then, inside the ResetISR we set some variables and copy the data from flash to ITC.
//
// Copy vector table to ram
//
vector_table_flash = const_cast<unsigned int*>(&__vector_table_flash_start__);
vector_table_itc = reinterpret_cast<unsigned int*>(0x0);
vector_table_size = static_cast<unsigned int>(&__vector_table_flash_end__ - &__vector_table_flash_start__);
for (index = 0u; index < vector_table_size; ++index)
{
vector_table_itc[index] = vector_table_flash[index];
}
The same code with some existing code to give a better idea where you should make your changes
// Volatile for ease of debugging, stuff tends to get optimized out which is annoying :). We'll nuke the volatile-ness with a const_cast (iewww).
volatile extern unsigned int __vector_table_flash_start__;
volatile extern unsigned int __vector_table_flash_end__;
// Some local variables. Not sure if this has to be global. You could make them static but meh, I didn't really care
unsigned int *vector_table_flash;
unsigned int *vector_table_itc;
unsigned int index;
unsigned int vector_table_size;
extern unsigned int __data_section_table;
extern unsigned int __data_section_table_end;
extern unsigned int __bss_section_table;
extern unsigned int __bss_section_table_end;
//*****************************************************************************
// Reset entry point for your code.
// Sets up a simple runtime environment and initializes the C/C++
// library.
//*****************************************************************************
__attribute__ ((naked, section(".after_vectors.reset")))
void ResetISR(void) {
// Disable interrupts
__asm volatile ("cpsid i");
__asm volatile ("MSR MSP, %0" : : "r" (&_vStackTop) : );
//
// Copy vector table to ram
//
vector_table_flash = const_cast<unsigned int*>(&__vector_table_flash_start__);
vector_table_itc = reinterpret_cast<unsigned int*>(0x0);
vector_table_size = static_cast<unsigned int>(&__vector_table_flash_end__ - &__vector_table_flash_start__);
for (index = 0u; index < vector_table_size; ++index)
{
__asm volatile ("nop");
vector_table_itc[index] = vector_table_flash[index];
}
Almost done... one more thing to do. If you go to the implementation of the SystemInit somewhere half way through the ResetISR function, the IDE will bring you to the generated device/system_MIMXRT_1024.cpp.
In the SystemInit function, the VTOR gets it's final location. Since we just copied the vector table to ITC, we need to set the VTOR to 0x0.
#if defined(__MCUXPRESSO)
//extern uint32_t g_pfnVectors[]; /* Vector table defined in startup code */
//SCB->VTOR = (uint32_t)g_pfnVectors;
SCB->VTOR = (uint32_t)0x0;
#endif
If you now compile, upload and start debugging, you be able to step through startup code, and eventually see the jump to main. Try any peripheral to see if the interrupt handlers still work. I fired up freertos since it relies on a hardware timer.
"It works on my board" .
Hope it helps somebody, some day
I would also like to know how to swap out the interrupt vector table, but at run time. I have a factory image, running from QSPI, that will download an application and save in to a different part of the same QSPI flash. I then want to run the downloaded image, which uses a different vector table. If the application causes a reboot, the factory image will again run and decide how to handle the reboot.
Hi
To relocate the vector table the following can be done
memcpy(new_location, original_location, sizeof(vector table));
VTOR = new_location;
New location can be anywhere in RAM (best in ITC) and should be aligned to a 512 byte boundary). The area should not be used by other storage - the easiest way to control this is to locate it at the start of ITC and change the start of the RAM in the linker script file from 0x00000000 to 0x00000300. 0x300 ensures that there is enough space for the largest vector table in any of the i.MX RT parts..
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]
Hi Kerry,
I mean that my code run from QSPI. In main (), before all bsp initializatons, I want to replace only the vector table from QSPI to ITCM. Is it possible? if yes, how?
Kind Regards,
Leon.
You want to download the code to the QSPI, after boot, the code copy to the ITCM and run from the ITCM, right?
If yes, I suggest you to use the free IDE, MCUXPresso IDE, it will be more easy to realize it.
You can configure the linker file like this:
Then the project will be download to the external QSPI and run from the ITCM.
I also attach my MCUXPresso IDE project for your reference.
The MCUXpresso IDE can be downloaded from the official website:
IAR will be not easy to realize this function, that's why I suggest you to use the MCUXPresso IDE.
You can try it.
If you still have questions about it, please kindly let me know.
Wish it helps you!
Have a great day,
Kerry
-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!
- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------
Hi Kerry,
Thank you for the info.
I'll try this.
I want only to emphasize, I'm not relocate my code from external flash (QSPI) to ITCM, only vector table. I want to do that only examine if I have performance improvement.
From your experience, is there any significance to this action?
Best Regards,
Leon.
Hi Leonid Shigris,
My code will copy all your app code which located in the external QSPI to the internal ITCM, not just vector table.
You can check it, whether this method is useful to you.
Best Regards,
Kerry
Hi Leonid Shigris,
If you want to run the code in the ITCM, you can refer to the NXP SDK for RT1060, which can be downloaded from this link:
Debug – Compiler optimization is set to low, and debug information is generated for the executable. The linker
file is RAM linker, where text and data section is put in internal TCM.
You just need to select the debug, then build the project, you will find the related linker file.
The SDK download link:
Welcome | MCUXpresso SDK Builder
Wish it helps you!
Have a great day,
Kerry
-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!
- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------