Arm Cortex-M interrupts

From SEGGER Wiki
Jump to: navigation, search

This article describes the Arm NVIC (Nested Vectored Interrupt Controller) and the ARM Cortex-M interrupt system.

Interrupt vectors

The ARM Cortex-M is using an NVIC (Nested Vectored Interrupt Controller). The NVIC uses a vector table which consists of 32-Bit vector entries. A vector entry stores the address of the according interrupt handler routine.

The first entry in the vector table is not an actual interrupt routine address but the initial stack pointer value. After reset the Cortex-M hardware reads that value and stores it in the stack pointer MSP (main stack pointer). The symbol __stack_end__ must be defined in the linker file. The actual symbol name can differ.

The second entry is the address of the first instruction which is executed after reset.

The exception numbers 1-15 are defined by ARM, that is, they are part of the core and equal for all Cortex-M devices. The names of these handlers are defined by an ARM standard called CMSIS. It is good practice to keep these names.

The exceptions above 15 are vendor specific which means that they are implemented by vendors like NXP, TI, STM, and many others and are for peripherals like UART/I²C/USB/etc.

_vectors:
        //
        // Core specific interrupts
        //
        .word __stack_end__
        .word Reset_Handler
        .word NMI_Handler
        .word HardFault_Handler
        .word MemManage_Handler
        .word BusFault_Handler
        .word UsageFault_Handler
        .word 0
        .word 0
        .word 0
        .word 0
        .word SVC_Handler
        .word 0
        .word 0
        .word PendSV_Handler
        .word SysTick_Handler
        //
        // Device specific interrupts
        //
        .word UART_IRQHandler
        .word SPI_IRQHandler
        .word USB_IRQHandler
        .word I2C_IRQHandler
        ...

VTOR Vector table offset register

The VTOR indicates the offset of the vector table base address from memory address 0x00000000 and the reset value is 0x00. With most Cortex-M Flash is located at address 0x00 and a Cortex-M application will place the vector table at 0x00. But VTOR can be used to place the vector table at different locations in FLASH (e.g. when an application is started by a bootloader in the same flash) or even in RAM. Placing the vector table in RAM gives the opportunity to change vector table entries at run-time

Interrupt priorities

A numerically low value in the interrupt register specifies a high interrupt priority and a numerically high value in the interrupt register specifies a low interrupt priority. At reset, all interrupt priorities have a priority value of zero assigned, which is the highest possible priority. Reset, NMI, and HardFault have a fixed priority and cannot be disabled. For all other interrupts the priority can be configured individually in an according NVIC priority register.

Priority bits

The interrupt priority for each interrupt is assigned within an 8 Bit priority register. Arm specified this 8 Bit register but a chip vendor can implement less bits. The minimum is 2 Bits for Cortex-M0/M0+/M1 and 3 Bits for Cortex-M3/M4/M7. The number of implemented bits can be found in the CMSIS device specific header file as __NVIC_PRIO_BITS.

The implemented priority bits are implemented as most significant bits.

For example:

Let's assume three bits are implemented:

Bit7 Bit6 Bit5 | Bit4 Bit3 Bit2 Bit1 Bit0 
Implemented    | Read as zero

With 3 bits we can have 8 priority levels 0-7.

001 1
010 2
011 3
100 4
101 5
110 6
111 7

But the actual possible values in the priority register are 0, 32, 64, 96, ..., 224.

001 00000  32
010 00000  64
011 00000  96
100 00000  128
101 00000  160
110 00000  192
111 00000  224

Please note it depends on the used API which value is expected as a parameter. For example the CMSIS function NVIC_SetPriority() expects the non shifted value whereas the embOS API function OS_ARM_DisableISR() expects the shifted value.

How to read the priority for a specific interrupt

The NVIC uses for each device specific interrupt a 8 Bit priority level register starting at address 0xE000E400.

0xE000E400   Device specific interrupt #0
0xE000E401   Device specific interrupt #1
0xE000E402   Device specific interrupt #2
...

Example

If we assume the vector table above and we want to know the interrupt priority value of the USB interrupt we need to read 8 Bits from address 0xE000E402.