Understanding and Redirecting the Cortex-M Interrupt Vector Table

Click the card below to follow Arm Technology Academy

This article is authorized to be reproduced from the WeChat official account Pi Zi Heng Embedded. Using the NXP i.MXRT1170 model as an example, this article introduces the method of redirecting the interrupt vector table.

In embedded code design, sometimes certain special operations (such as Flash erase under XIP, low-power mode switching) cannot be interrupted at will, or some shared data areas cannot be accessed disorderly (Task A is reading while Task B wants to write). In these cases, we can use the system global interrupt switch control to achieve what is called critical section protection.

However, in some scenarios, switching off the system global interrupts is not always effective. For example, in the case of Flash erase under XIP, if there is a background timer (like SysTick) running in real-time, turning off the system global interrupts during the Flash erase (which may take a long time) will prevent the timer interrupt from responding, causing system timing deviations. Clearly, we cannot turn off the system global interrupts in this situation.

To ensure that the system can still respond promptly to timer interrupts (executing interrupt handler functions) during Flash erase, we need to link the timer interrupt handler function and its related code to RAM for execution, and we also need to redirect the interrupt vector table to RAM. Today, let’s talk about the method of redirecting the interrupt vector table:

1 Introduction to the Cortex-M Interrupt Vector Table

Friends familiar with the Arm Cortex-M processor should be aware of the following table, which is the interrupt vector table. Each vector in the table is 4 bytes in size, and except for the 0th vector, the rest are function addresses. This table centrally stores the addresses of all system interrupt handler functions (xxxIRQHandler).

Understanding and Redirecting the Cortex-M Interrupt Vector Table

For MCUs with embedded Flash, the initial interrupt vector table is generally required to be fixed linked to the starting address of Flash, because the system startup always retrieves the 0th (initial stack) and 1st vector (initial PC, reset function ResetHandler) from the starting address of Flash to begin executing application code. For some MCUs with BootROM or without internal Flash, the initial interrupt vector table may be placed at other addresses in Flash, depending on the specific chip design.

Once the application program is running, if an interrupt occurs, the system will find the corresponding peripheral interrupt handler function in the interrupt vector table based on the interrupt number issued by the requesting peripheral and execute it. The Cortex-M core (except for CM0) has a dedicated VTOR register in the SCB module to control the starting address of the interrupt vector table (note that the address needs to be 128 bytes aligned). After the program starts running, users can configure the SCB->VTOR register to reset the interrupt vector table address.

Understanding and Redirecting the Cortex-M Interrupt Vector Table
Understanding and Redirecting the Cortex-M Interrupt Vector Table

2 Method of Redirecting the Interrupt Vector Table

Now we will introduce the method of redirecting the interrupt vector table using the NXP i.MXRT1170 model as an example, demonstrated in the \\SDK_2.9.1_MIMXRT1170-EVK\\boards\\evkmimxrt1170\\demo_apps\\led_blinky\\cm7\\iar project.

2.1 Files Related to the Interrupt Vector Table

In this led_blinky project, there are two files related to the interrupt vector table: one is startup_MIMXRT1176_cm7.s startup file, which contains the entity definition of the interrupt vector table and the reset function ResetHandler(). From the reset function, you can see that it first resets the SCB->VTOR register.

        THUMB
        PUBWEAK Reset_Handler        SECTION .text:CODE:REORDER:NOROOT(2)Reset_Handler        CPSID   I               ; Mask interrupts        LDR     R0, =0xE000ED08      ; SCB->VTOR        LDR     R1, =__vector_table  ; section .intvec segment start address        STR     R1, [R0]        LDR     R2, [R1]        MSR     MSP, R2        LDR     R0, =SystemInit        BLX     R0        CPSIE   I               ; Unmask interrupts        LDR     R0, =__iar_program_start        BX      R0

The value of __vector_table used in the reset function is determined by the following statement set in the MIMXRT1176xxxxx_cm7_flexspi_nor.icf linker file. Since the i.MXRT1170 does not have internal Flash, the system mapping starting address allocated to the external NOR Flash (connected to the FlexSPI1 peripheral) is 0x30000000, while 0x30002000 is one of the application initial interrupt vector table addresses supported by BootROM (indicated in the IVT startup header).

define symbol m_interrupts_start       = 0x30002000;define symbol m_interrupts_end         = 0x300023FF;
define exported symbol __VECTOR_TABLE          = m_interrupts_start;
place at address mem: m_interrupts_start    { readonly section .intvec };

After compiling the project, you can find the final linked address of the initial interrupt vector table in the corresponding generated iledblinky_cm7.map mapping file. For ease of subsequent problem analysis, we also list the timer interrupt handler function addresses:

********************************************************************************** PLACEMENT SUMMARY***
"A0":  place at address 0x3000'2000 { ro section .intvec };
  Section              Kind         Address    Size  Object  -------              ----         -------    ----  ------"A0":                                         0x400  .intvec              ro code  0x3000'2000   0x400  startup_MIMXRT1176_cm7.o [1]                              - 0x3000'2400   0x400
********************************************************************************** ENTRY LIST***
Entry                       Address   Size  Type      Object  -----                       -------   ----  ----      ------SysTick_Handler         0x3000'5767   0x10  Code  Gb  led_blinky.o [1]__VECTOR_TABLE {Abs}    0x3000'2000         Data  Gb  <internal module>__Vectors               0x3000'2000          --   Gb  startup_MIMXRT1176_cm7.o [1]__Vectors_End           0x3000'2400         Data  Gb  startup_MIMXRT1176_cm7.o [1]__Vectors_Size {Abs}          0x400          --   Gb  startup_MIMXRT1176_cm7.o [1]__vector_table          0x3000'2000         Data  Gb  startup_MIMXRT1176_cm7.o [1]

2.2 Example of Interrupt Redirection Function

The timer interrupt handler function SysTick_Handler() linked in Flash is clearly not feasible. We use IDE features (for IAR, it is the __ramfunc modifier) to link it to RAM (the MIMXRT1176xxxxx_cm7_flexspi_nor.icf defines the TEXT2_region:0x0-0x3FFFF space for storing section.textrw segments), recompile the project, and check the mapping file to see that the new allocated address is 0x1.

printf("hello world!");
********************************************************************************** ENTRY LIST***
Entry                       Address   Size  Type      Object  -----                       -------   ----  ----      ------SysTick_Handler                 0x1   0x14  Code  Gb  led_blinky.o [1]

Now we try to manually relocate the interrupt vector table in the code by finding a free RAM area (such as 0x20000000-0x200003FF) and directly copying the contents of the interrupt vector table there. The sample code is as follows. The main function calls this relocate_vector_table() function at the beginning, and everything runs normally after downloading the modified project to the board, indicating that the interrupt vector table redirection operation was successful.

extern uint32_t __VECTOR_TABLE[];
void relocate_vector_table(void){    __disable_irq();    // Copy the initial interrupt vector table from 0x30002000 to the new address 0x20000000    memcpy((void *)0x20000000, (void *)__VECTOR_TABLE, 0x400);    // Set VTOR to point to 0x20000000    SCB->VTOR = 0x20000000;    __enable_irq();}
int main(void){    relocate_vector_table();
    // Other code}

Recommended Reading

  • Arm Expands Cortex-M Product Line, Bringing AI to Ultra-Small Endpoint Devices

  • Special Considerations for Using FreeRTOS with Cortex-M Cores

  • Can Cortex-M Microcontrollers Run Linux Operating Systems?

Understanding and Redirecting the Cortex-M Interrupt Vector Table
Understanding and Redirecting the Cortex-M Interrupt Vector Table
Understanding and Redirecting the Cortex-M Interrupt Vector Table

Long press to recognize the QR code to add Miss Jishu WeChat (aijishu20) and join the Arm Embedded Developer Group.

Follow Arm Technology Academy

Understanding and Redirecting the Cortex-M Interrupt Vector Table Click the button below “Read the Original“, to read more articles in the Embedded Inn’s column.

Leave a Comment

×