Configuring SAM D21 Interrupts

SAM D21 interrupt operation must be carefully initialized by the application developer. This page summarizes the key initialization and usage steps required for using peripheral interrupts in an application. We will use the GNU compiler collection (GCC), running within the Atmel Studio 7 IDE. Examples use the ATSAMD21J18A MCU.

Visit the following pages if you are interested in learning the details on the Nested Vectored Interrupt Controller (NVIC) on SAM D21, or if you would like to try a simple, working SAM D21 interrupt project:

 
NVIC Overview
Learn more >
 
NVIC Example Project
Learn more >

Step 1. Include the required files

For a GCC C Executable-type project in Atmel Studio 7, all required interrupt support header/source files are included when you first execute Build > Rebuild-All.

samd21-nvic-configuration-support-files.png

Step 2. Provide the interrupt handler routine

Default handler functions are defined in startup_samd21.c.

samd21-nvic-configuration-default-handlers.png


Note that these functions are defined as “weak”, so you can override them with your own implementation.

Acknowledge the Interrupt

Within the handler, you must acknowledge (reset) the interrupt flag in the INTFLAG register which is the cause of the interrupt. Here is an example for a Timer/Counter 3 handler, which is triggered by a compare match event:

void TC3_Handler(void){

// Interrupt processing code

// Acknowledge the interrupt (clear MC0 interrupt flag to re-arm)
TC3->COUNT16.INTFLAG.reg |= 0b00010000;

}

Step 3. Enable a specific interrupt on the peripheral

We will briefly review the SAM D21 Timer/Counter module in this section in order to provide a specific example of enabling a peripheral interrupt. In this example, we configure the Timer/Counter 3 to generate compare interrupts every 100 ms, using a 1 MHz CPU Clock and GCLK0.

Timer/Counter Overview

The Timer/Counter (TC) module provides a set of timing and counting related functionality, such as the generation of periodic waveforms, the capturing of a periodic waveform's frequency/duty cycle, and software timekeeping for periodic operations. TC modules can be configured to use an 8-, 16-, or 32-bit counter size.

16-bit Compare Mode Configuration

In this mode, the module uses a compare channel (channel 0 in this example) to create a simple, periodic time delay function:

samd21-nvic-configuration-tc3-compare-mode.png

The compare, "waveform generation" mode is set to 'Match Frequency Operation', whereby the period time is controlled by the value in the CC0 register.

samd21-nvic-configuration-tc3-match-freq-operation.png
  • COUNT is reset to '0' on each match
  • WO[0] toggles on each match, generating an interrupt event

WO[0] may be optionally connected to an external MCU pin.

Peripheral Interrupt Registers

Each peripheral module has their own set of interrupt registers, which must be set to enable interrupt generation.

  • INTENSET - Atomic interrupt enable
  • INTENCLR - Atomic interrupt disable
  • INTFLAG - Interrupt flag status and clear

These registers may be accessed in C using an indirect method as shown here:

/* Enable TC3 Overflow Interrupt Signal */
TC3->COUNT16.INTENSET.bit.OVF = 1;

/* Enable TC3 Error Interrupt Signal */
TC3->COUNT16.INTENSET.bit.ERR = 1;

Configure the TC3 Interrupt Generation

Follow these coding steps:

  1. Configure an asynchronous clock source (GCLK_TC)
  2. Configure a synchronous bus clock
  3. Configure Count Mode (16-bit)
  4. Configure Prescaler
  5. Configure Compare Mode
  6. Initialize compare value (CC0)
  7. Enable TCx compare mode interrupts
  8. Enable TCx module


Here is the code snippet that performs these steps (note: a 1 MHz CPU Clock and 1 MHz GCLK0 Generator are already enabled and running):

// Configure asynchronous clock source
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_TCC2_TC3_Val;    // select TC3 peripheral channel
GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_GEN_GCLK0;        // select source GCLK_GEN[0]
GCLK->CLKCTRL.bit.CLKEN = 1;            // enable TC3 generic clock

// Configure synchronous bus clock
PM->APBCSEL.bit.APBCDIV = 0;            // no prescaler
PM->APBCMASK.bit.TC3_ = 1;                // enable TC3 interface

// Configure Count Mode (16-bit)
TC3->COUNT16.CTRLA.bit.MODE = 0x0;

// Configure Prescaler for divide by 2 (500kHz clock to COUNT)
TC3->COUNT16.CTRLA.bit.PRESCALER = 0x1;

// Configure TC3 Compare Mode for compare channel 0
TC3->COUNT16.CTRLA.bit.WAVEGEN = 0x1;            // "Match Frequency" operation

// Initialize compare value for 100mS @ 500kHz
TC3->COUNT16.CC[0].reg = 50000;

// Enable TC3 compare mode interrupt generation
TC3->COUNT16.INTENSET.bit.MC0 = 0x1;    // Enable match interrupts on compare channel 0 

// Enable TC3
TC3->COUNT16.CTRLA.bit.ENABLE = 1;

// Wait until TC3 is enabled
while(TC3->COUNT16.STATUS.bit.SYNCBUSY == 1);

Step 4. Set the priority and enable the NVIC line

Set the NVIC interrupt priority

To set the TC3 interrupt priority level (0, 1, 2, 3), call the NVIC_SetPriority() CMSIS function included in the core_cm0plus.h file.

/* Set TC3 Interrupt Priority to Level 3 */
NVIC_SetPriority(TC3_IRQn, 3);

Recall that a higher priority number parameter corresponds to a lower interrupt priority.
cm0plus-nvic-api-priority-levels-summary.png

Enable the NVIC Line

To enable the TC3 interrupt, call the NVIC_EnableIRQ() CMSIS function included in the core_cm0plus.h file.

/* Enable TC3 NVIC Interrupt Line */
NVIC_EnableIRQ(TC3_IRQn);

Step 5. Enable global interrupts

Finally, the CMSIS file, cmsis_gcc.h, provides the following intrinsic functions for globally enabling/disabling IRQs:

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

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

 Learn More

Go to the NVIC example project to see a complete working project, or the NVIC overview page to review the Cortex M0+ exception model and NVIC functionality.

 
NVIC Overview
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.