SAM D21 Exceptions and Interrupts

On ARM® Cortex®-M0+ Processor Core MCUs, such as the SAM D21 family, peripheral/external interrupts, traps, system calls, and everything else that can disrupt the normal flow of execution are called exceptions and are handled by the Nested Vectored Interrupt Controller (NVIC) in the Cortex-M0+ processor core. This page provides an overview of the Cortex M0+ exception model, as well as the basic NVIC functionality.

Visit the following pages if you are interested in how to program the interrupts and exceptions on SAM D21, or if you would like to try a simple, working SAM D21 Interrupt Project:

 
NVIC Configuration
Learn more >
 
NVIC Example Project
Learn more >

Overview

The NVIC is an example of an interrupt controller with extremely flexible interrupt priority management. It enables programmable priority levels, automatic nested interrupt support, along with support for multiple interrupt masking, while still being very easy to use by the programmer.

cm0plus-nvic-general.png


The NVIC design supports up to 32 external (to the core) interrupt request inputs (IRQs) plus a number of built-in system exceptions. For each IRQ input, there are four programmable priority levels. In addition to the external interrupt requests, the NVIC design supports internal exceptions, for example, an exception input from a 24-bit timer called SysTick, which is often used by an OS. There are also additional system exceptions to support OS operations and a Non-Maskable Interrupt (NMI) input. The NMI and HardFault (one of the system exceptions) have fixed priority levels.

The following table summarizes the exception types, exception and Cortex Microcontroller Software Interface Standard (CMSIS) IRQ numbers, priority levels and default vector addresses for all exceptions supported:

cm0plus-nvic-exception-table.png

Simplified Exception Process

  • A peripheral generates an interrupt request (IRQ) to the processor.
  • The processor hardware detects and accepts the IRQ. The current executing task is suspended and registers R0-R3, R12, R14, the return address PC, and the PSR are pushed into the stack to save the execution context.
  • The processor locates the starting address of the interrupt handler from the vector table and executes the handler associated with this IRQ.
  • The processor finishes the handler execution, restores the context (register values) previously pushed to the stack and resumes the interrupted task.

Vector Table

The interrupt handling is vectored, which means that the hardware automatically determines which interrupt or exception routine to execute. The Vector Table is a lookup table in memory that provides such information. By default, the table begins at address 0x00000000 in the SAM D21 Flash program memory.

cm0plus-nvic-vector-table-default.png

As indicated in the diagram above, the Vector Table can be relocated to change interrupt handlers at runtime using the Vector Table Offset Register (VTOR). This is useful for:

  • Bootloader applications
  • Faster Vector Table fetch (ex. slow flash memory)
  • Dynamic changing of handlers
  • Executing programs from RAM

Cortex-M0+ Boot Process

When the processor is turned on or reset, the processor fetches two words located at the first two locations in the Vector Table, 0x00000000 and 0x00000004. The processor uses the word at 0x00000000 to initialize the Main Stack Pointer register (MSP), and the other one at 0x00000004 to set up the Program Counter PC to point to the start address of the Reset Handler procedure, as determined by the compiler and linker script.

After the PC is initialized, the program begins execution.

SAM D21 Vector Table Detail

The following diagram depicts the detailed Vector Table for the ATSAMD21J18A MCU (not all peripheral IRQs are shown):

samd21-nvic-vector-table-detail.png

Each entry in the table is the starting address of an exception handler with the LSB set to '1' to indicate that the exception handler is in Thumb® mode.

For a given CMSIS interrupt number i, the memory address of its corresponding Interrupt Service Routine (ISR) is located at the i + 16th entry in the Vector Table. Since the Vector Table begins at 0x00000004 and since each entry takes 4 bytes in memory:

$VectorTableAddressOfISR = 0x00000004 + 4*(i + 15)$

For example, the CMSIS interrupt number for the I²S Interrupt is 27, so the memory address of the I2S_Handler can be found by reading the word stored at the following Vector Table address:

$VectorTableAddressOfI2SHandler = 0x00000004 + 4*(27+15) = 0x000000AC$

The CMSIS interrupt number for the NMI Exception is -14, so the memory address of the NMI_Handler can be found by reading the word stored at the following Vector Table address:

$VectorTableAddressOfNMIHandler = 0x00000004 + 4*(-14+15) = 0x00000008$

CMSIS IRQ numbers are located in the device header file (ex. samd21j18a.h)

Exception Types

Reset

Reset is invoked on power-up or through a user reset. The exception model treats reset as a special form of exception. When a reset is asserted, the operation of the processor stops, potentially at any point in an instruction. When a reset is deasserted, execution restarts from the address provided by the reset entry in the vector table. Execution restarts as a privileged execution in Thread mode.

In the SAM D21, the reset signals (user reset, power reset) are generated by the Power Manager (PM) peripheral.

Non-Maskable Interrupt (NMI)

The NMI is similar to the IRQ signal, but it cannot be disabled and has the highest priority apart from reset.

In the SAM D21, the NMI signal is generated by the External Interrupt Controller (EIC) peripheral.

HardFault

A HardFault is an exception that occurs because of an error that occurred during program execution. HardFaults have a fixed priority of –1, meaning they have higher priority than any exception with configurable priority. Examples include:

  • Trying to execute an unknown opcode
  • Bus or Memory System Fault
  • Illegal operations
  • Unaligned reads/writes to memory

Cortex-M0+ does not include a divide instruction, so there will be no hardware exception for that. The behavior will be defined by your compiler; for C and C++ it is an "undefined" behavior and will be flagged as a warning upon compilation.

SVCall (Supervisor Call)

SVCall exception takes place when the SVC instruction is executed. SVC is used in OS-based applications, allowing applications to access system resources.

PendSV (Pendable Service Call)

PendSV is another exception for OS-based applications. Unlike the SVCall exception, PendSV can be delayed, and allows an OS to schedule system operations only when high priority tasks are completed.

SysTick

If the device implements the SysTick Timer, a SysTick exception is generated when the SysTick timer reaches zero.

In the SAM D21 Cortex-M0+ Core, the SysTick Timer is implemented.

IRQs

An external-to-the-core interrupt (or IRQ) is an exception signaled by a peripheral, or generated by a software request. All interrupts are asynchronous to instruction execution. In the system, peripherals use interrupts to communicate with the processor. For each IRQ input, there are four programmable priority levels.

On SAM D21, the core implements 28 IRQs, which are generated by on-chip peripherals (SERCOM, ADC, etc.) as well as the External Interrupt Controller (EIC).

Exception Priority Level

Priority determines the order of interrupts to be serviced. Each kind of exception has its own exception priority value; numerically lower numbers correspond to higher urgency. Priority values can be fixed or programmable.

cm0plus-nvic-exception-priority-level-general.png

Priority Levels

Cortex-M0+ processors support three fixed highest priority levels for three of the system exceptions, and four programmable levels for all other exceptions, including interrupts. An 8-bit Priority Level Register is associated with each exception having programmable priority, however, note that only the two MSBs are implemented, as shown:

cm0plus-nvic-priority-level-register.png

With this setup, we have four possible programmable priority levels being 0x00 (highest urgency), 0x40, 0x80, and 0xC0 (lowest urgency) as shown:

cm0plus-nvic-priority-levels-summary.png
  • Out of reset, all interrupts and exceptions with configurable priority have the same default priority of 0x00. This priority number represents the highest-possible interrupt urgency.
  • If two exceptions happen at the same time and they have the same programmed priority level, the exception with the lower CMSIS IRQ number will be processed first.

Priority Level Configuration

Eight NVIC registers (NVIC_IPR0..7) are used to provide 32 priority configuration registers for each of the 32 IRQs:

cm0plus-nvic-priority-level-config-ipr.png

Configuring Interrupt Priority

CMSIS provides a number of functions for NVIC control, including the following for setting priority:

void NVIC_SetPriority(IRQn_t IRQn, uint32_t priority);

Where priority values (0, 1, 2, 3) correspond to interrupt priority register (IPRx) settings 0x00, 0x40, 0x80, 0xC0.
cm0plus-nvic-api-priority-levels-summary.png

So, we see that a higher priority parameter corresponds to a lower programmed interrupt urgency (priority).

Enabling IRQs Globally

Often in real-time embedded programming, it is necessary to perform certain operations atomically to prevent data corruption. The simplest way to achieve the atomicity is to briefly disable and re-enable interrupts. The PRIMASK CPU-core register prevents activation of all exceptions with configurable priority.

cm0plus-nvic-priority-level-config-primask.png

bit 0

PM: Prioritizable Interrupt Mask

1 = all exceptions with configurable priority are disabled
0 = (default) all IRQs enabled


The software uses the cpsie i and cpsid i assembly language instructions to atomically clear or set the PM bit, thus enabling/disabling IRQs globally. CMSIS provides the following intrinsic functions for these instructions in cmsis_gcc.h:

/* Disable Interrupts */
void __disable_irq(void);

/* Enable Interrupts */
void __enable_irq(void);

Interrupt Latency

The interrupt latency on the Cortex-M0+ is deterministic and doesn’t have any hidden software overhead, which can be observed in many other architectures.

Entry Latency

Entry latency determines how quickly we can act on any particular input event. Once an interrupt occurs, the NVIC hardware automatically stacks an exception frame (registers xPSR, PC, LR, r12 and r3-r0) onto the Process Stack (PSP) and branches to the interrupt handler routine in Handler Mode (which uses the Main Stack).

Entry Latency on Cortex-M0+ is 15 cycles.

Exit Latency

The exit latency is 13 cycles. The interrupt exit latency is two cycles fewer than the interrupt entry latency, as the processor can recognize in advance when the handler is terminating and doesn't need to synchronize an external signal. Apart from that, it has to complete the same operations but in reverse.

Interrupt Nesting

When the processor is executing an exception handler, an exception can preempt the exception handler if its priority is higher than the priority of the exception being handled. When one exception preempts another, the exceptions are called "nested exceptions".

cm0plus-nvic-nested-exceptions.png

Tail-Chaining

The Cortex-M0+ incorporates a feature for switching from the end of one interrupt straight to the start of another. This is called tail-chaining. Because the context is already saved on the stack from the first interrupt, there is no need to go through the entire save/restore context procedure between the end of one interrupt and the start of the next. The processor simply switches from one to the other. Rather than 28 cycles (15 + 13), this takes only six.

cm0plus-nvic-tail-chaining.png

Late Arriving

This mechanism speeds up preemption. If a higher priority exception occurs during state saving for a previous exception, the processor switches to handle the higher priority exception and initiates the vector fetch for that exception. State saving is not affected by late arrival because the state saved would be the same for both exceptions. On return from the exception handler of the late-arriving exception, the normal tail-chaining rules apply.

cm0plus-nvic-late-arriving.png

NVIC/Exception Support Files

Upon performing a 'Rebuild-Solution' action on a GCC C Executable type project in Atmel Studio, several source code files are added to the project to support interrupt-driven applications.

samd21-nvic-programming-support-files.png

Vector Table Support

Source file startup_samd21.c contains a declaration of the Vector Table.

samd21-nvic-programming-vector-table.png

Linker script samd21j18a_flash.ld maps the Vector Table to address 0x00000000 in Flash program memory.

samd21-nvic-programming-linker-file.png

CMSIS IRQ Numbers

Device header file samd21j18a.h contains the peripheral-interrupt-to-CMSIS-IRQ-number mapping.

samd21-nvic-programming-cmsis-irqs.png

These enumerated constants are used to identify IRQ numbers when using the NVIC_xxx( ) APIs. For example:

void NVIC_SetPriority(IRQn_t IRQn, uint32_t priority);

NVIC-Specific Functions

CMSIS provides a number of functions for NVIC control, such as:

/* Set the priority for an interrupt */
void NVIC_SetPriority(IRQn_t IRQn, uint32_t priority);

/* Enable a device specific interrupt */
void NVIC_EnableIRQ (IRQn_Type IRQn);

/* Disable a device specific interrupt */
void NVIC_DisableIRQ (IRQn_Type IRQn)

CMSIS functions associated with NVIC are located in the core_cm0plus.h header file. Functions are implemented as inline code. Here are two examples:
samd21-nvic-programming-cmsis-inline-code.png


As discussed above, CMSIS also provides the following intrinsic functions in cmsis_gcc.h to globally enable/disable (atomically) all exceptions with programmable priority:

/* Disable Interrupts */
void __disable_irq(void);

/* Enable Interrupts */
void __enable_irq(void);

Exception and Interrupt Handlers

Default exception handler functions are defined in startup_samd21.c. They're defined as “weak” functions, so you can override the default implementation with your own.

samd21-nvic-programming-handlers.png

 Learn More

 
NVIC Configuration
Learn more >
 
NVIC Example Project
Learn more >
© 2018 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.