Interrupts And Exceptions

The Cortex-M3 controller features a Nested Vector Interrupt Controller, or NVIC. The NVIC supports a numer of exceptions, including a fixed number of system exceptions and a number of external interrupts, commonly known as IRQs.
Depending on the implementation used by the silicon manufacturer, the NVIC can support up to 240 external interrupts with up to 256 different priority levels that can be dynamically reprioritized.

The Cortex-M3 vector table contains the address of the exception handlers and ISR. The initial stack pointer and the address of the reset handler must be located at 0x0 and 0x4 respectively.
These values are then loaded into the appropriate CPU registers at reset.

Exception types

On Cortex-M3, the interrupts/exceptions are divided into two categories, based on their priority: configurable and unconfigurable.
The unconfigurable exceptions have fixed priority, and consist of following :

Priority Levels

The NVIC supports software-configurable priority levels. You can assign a priority level from 0 to 255 to an interrupt. Hardware priority decreases with increasing interrupt number.
Priority level 0 is the highest priority level, and priority level 255 is the lowest. The priority level overrides the hardware priority.

For example, if you assign priority level 1 to IRQ[0] and priority level 0 to IRQ[31], then IRQ[31] has higher priority than IRQ[0].

When multiple interrupts have the same priority number, the pending interrupt with the lowest interrupt number takes precedence.
For example, if both IRQ[0] and IRQ[1] are priority level 1, then IRQ[0] has higher priority than IRQ[1].

  Important :

Software prioritization does not affect Reset, Non-Maskable Interrupt (NMI), and hard fault. They always have higher priority than the external interrupts.

Interrupt Vector Table

The Cortex-M3 processor uses a re-locatable vector table that contains the address of the function to be executed for a particular interrupt handler.
On accepting an interrupt, the processor fetches the address from the vector table through the instruction bus interface.

Following picutre shows the order of the exception vectors in the vector table :

Interrupt Vector Table

On system reset, the vector table is fixed at address 0x0000.0000. Privileged software can relocate the vector table start address to a different memory location.

Interrupt Service Routine

Interrupt service routine is defined in this way :

procedure interrupt(); iv IVT_INT_TIMER0A; ics ICS_OFF;
begin
    // Interrupt service routine code
end;

where :

If interrupt context saving is not explicitly declared, compiler will set ICS_AUTO by default.

User can explicitly declare starting interrupt routine address using org directive :

procedure interrupt(); org 0xC00; iv IVT_INT_TIMER0A; ics ICS_OFF;
begin
    // Interrupt service routine code
end;

Function Calls from Interrupt

Calling functions from within the interrupt routine is possible. The compiler takes care about the registers being used, both in "interrupt" and in "main" thread, and performs "smart" context-switching between two of them, saving only the registers that have been used in both threads. It is not recommended to use a function call from interrupt. In case of doing that take care of stack depth.

Disable Context Saving

Use the DisableContextSaving to instruct the compiler not to automatically perform context-switching.
This means that no register will be saved/restored by the compiler on entrance/exit from interrupt service routine.


This enables the user to manually write code for saving registers upon entrance and to restore them before exit from interrupt.

Interrupt Example

Here is a simple example of handling the interrupts from Timer0A (if no other interrupts are allowed):

program Timer0_interrupt;

procedure Timer0A_interrupt(); iv IVT_INT_TIMER0A ics ICS_OFF;
begin
  TIMER_ICR_TATOCINT_bit := 1;              // Clear time-out timer A interrupt
  GPIO_PORTJ_DATA := not GPIO_PORTJ_DATA;   // Toggle PORTJ led's
end;

begin
  GPIO_Digital_Output(@GPIO_PORTJ, _GPIO_PINMASK_ALL);  // Enable digital output on PORTJ
  GPIO_PORTJ_DATA := 0;

  SYSCTL_RCGC1_TIMER0_bit := 1;        // Enable clock gating for timer module 0

  EnableInterrupts();                  // Enables the processor interrupt.

  TIMER_CTL_TAEN_bit := 0;             // Disable timer
  TIMER0_CFG := 0;                     // Set 32-bit timer configuration
  TIMER0_TAMR := TIMER0_TAMR or 2;     // Set periodic mode
  TIMER0_TAILR := Get_Fosc_kHz()*1000; // Set interval load
  NVIC_IntEnable(IVT_INT_TIMER0A);     // Enable timer interrupt
  TIMER_IMR_TATOIM_bit := 1;           // Enable time-out timer A interrupt
  TIMER_CTL_TAEN_bit := 1;             // Enable timer A

  while true do
    ;
end.