The SAMD clock system

Terms

Essentially every microprocessor or computer needs a consistent way of their own speed of operation so they can communicate with internal components and external devices.

An oscillator is a circuit that makes an oscillating signal - ie, it switches back and forth between to states at a consistent rate. The oscillator works like a metronome. An oscillator alone does not keep track of time; it ticks, but it doesn't count how many ticks have passed.

SAMD processors use these types of oscillators:

  • crystal oscillators - which are tiny pieces of quartz that vibrate under current. This is just like the crystals in a quartz watch.
  • Digital frequency locked loops (DFLL) and fractional digital phase locked loops (FDPLL) - these phase locked loops (PLL) use a reference clock (like the external crystal) to create a consistent (faster) output frequency.
  • Ultra-low-power oscillators - circuits which generate the same frequency vibrations as a crystal power but using lower power consumption to get a less consistent signal.

For any of the oscillators to be useful in keeping track of time, they need to be connected to something else that will count the number of ticks. The oscillator acts as the source for the clock/counter. There can also be a 'divisor' between the ticking source and the counter - that is, the counter can record every 'x' ticks instead of every single tick.

See also: https://blog.thea.codes/understanding-the-sam-d21-clocks/

SAMD21

The SAMD21 clock system

From the SAMD21 Datasheet 14.1:

The clock system on the SAM D21 consists of :

  • Clock sources, controlled by SYSCTRL – A clock source provides a time base that is used by other components, such as Generic Clock Generators. Example clock sources are the internal 8MHz oscillator(OSC8M), External crystal oscillator(XOSC) and the Digital frequency locked loop (DFLL48M).
  • Generic Clock Controller(GCLK) which controls the clock distribution system, made up of:
    • Generic Clock Generators: These are programmable prescalers that can use any of the system clock sources as a time base. The Generic Clock Generator 0 generates the clock signal GCLK_MAIN, which is used by the Power Manager, which in turn generates synchronous clocks.
      • Generic clock generators are configured with GCLK->GENCTRL
    • Generic Clocks: These are clock signals generated by Generic Clock Generators and output by the Generic Clock Multiplexer, and serve as clocks for the peripherals of the system. Multiple instances of a peripheral will typically have a separate Generic Clock for each instance. Generic Clock 0 serves as the clock source for the DFLL48M clock input (when multiplying another clock source).
      • Generic clocks are configured with GCLK->CLKCTRL
  • Power Manager (PM)
    • The PM generates and controls the synchronous clocks on the system. This includes the CPU, bus clocks (APB, AHB) as well as the synchronous (to the CPU) user interfaces of the peripherals. It contains clock masks that can turn on/off the user interface of a peripheral as well as prescalers for the CPU and bus clocks

SAMD21 Clock Requirements Relevant to ModularSensors

The watchdog's peripheral clock must be attached to a currently-on clock source so it can tell how much time has passed and whether it needs to bite. The watchdog peripheral clock is not configured by the core. The flow from a clock source to the WDT on the SAMD21 is:

  • Enable the clock source and the WDT peripheral in the power management system
  • Configure said a clock source to run in standby
  • Configure a divisor between the above source clock and a generic clock generators
  • Configure a generic clock to tie the watchdog's peripheral clock to the above generic clock generator
  • Configure the watchdog itself.

The external interrupt controller must also be attached to a currently-on clock to tell the difference between rising and HIGH or falling and LOW interrupts. If the external interrupt controller is not attached to a running clock, then interrupts will not work! Thus, if the clock source for interrupts is not running in standby, the interrupts will not be able to wake the device. The flow from a clock source to the EIC is the same as that for the WDT.

SAMD21 Settings at Power On

After a power-on reset, the clock generators for peripherals default to:

  • RTC: GCLK0
  • WDT: GCLK2
  • Anything else: GCLK0
  • See 14.8 in the SAMD21 Datasheet

See section 13.7 of the datasheet

SAMD21 Arduino Core Setup Clock Generator Configuration

Within the SAMD core SystemInit() in startup.c configures clocks with these steps:

  • Enable XOSC32K clock (external on-board 32.768Hz oscillator) or OSC32K (if crystalless).
    • This will be used as DFLL48M reference.
    • SystemInit() uses a default start-up configuration of 0x6 for the (X)OSC (65536 OSCULP32K clock cycles + 3 (X)OSC32K clock cycles = 2000092μs ~= 2s before PCLKSR.XOSC32KRDY is set.)
  • Put XOSC32K or OSC32K as source of Generic Clock Generator 1
  • Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
  • Enable DFLL48M clock in closed loop mode, if there is an external crystal available, or in open loop mode if crystalless
  • Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
  • Modify prescaler value of OSCM to have 8MHz
  • Put OSC8M as source for Generic Clock Generator 3

Resulting generic clock generator speeds:

  • GCLKGEN0 = 48 MHz; sourced from DFLL48M, which does not run in standby.
  • GCLKGEN1 = 32kHz; sourced from XOSC32K or OSC32K, which does not run in standby.
  • GCLKGEN2 = not configured
  • GCLKGEN3 = 8 MHz; sourced from OSC8M, which does not run in standby.
  • GCLKGEN4-GCLKGEN8 = not configured

SAMD21 Arduino Core Library Clock Configuration

  • WInterrupts.c
    • Configures the external interrupt controller (EIC) clock (GCM_EIC) to use GCLKGEN0 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN0
  • wiring_analog.c
    • Configures timer counter clocks (GCM_TC4_TC5 or GCM_TC6_TC7, depending on the analog pin) to use GCLKGEN0 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN0
  • wiring.c
    • Configures the ADC (GCM_ADC) and DAC (GCM_DAC) to use GCLKGEN0 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN0
  • SERCOM
    • Configures the various SERCOM clocks to use GCLKGEN0 at 48 MHz
      • GCM_SERCOM0_CORE -> GCM_SERCOM5_CORE, depending on how many SERCOM's are defined in variant.h
    • Does not change the source or other configuration for GCLKGEN0
  • Tone
    • Configures timer counter 4 and 5 clocks (GCM_TC4_TC5) to use GCLKGEN0 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN0
  • I2S
    • Configures the I2S's generic clocks (I2S_GCLK_ID_0 and I2S_GCLK_ID_1) to use the generic clock generator specified for I2S in variant.h (likely GCLKGEN3)
    • Sets the source of the specified generic clock generator to be the DFLL48 or the OSC8M, depending on the I2S speed
  • USB (host, core, TinyUSB)
    • Configures the USB (GCLK_USB = 0x6) to use GCLKGEN0 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN0
    • NOTE: For some reason, the code uses 0x6 directly instead of the GCLK_USB macro for the generic clock selection ID
  • Servo
    • Configures timer counter clocks (specific clock depending on the analog pin) to use GCLKGEN0 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN0

Clocks Used by Non-Core Libraries for the SAMD21

  • RTCZero
    • Configures the RTC's generic clock (GCM_RTC) to use generic clock generator 2
    • Sets the source for GCKL2 as a 32k oscillator
      • external preferred, internal ultra-low power if crystalless
      • Forces the external 32K oscillator to remain on in standby
    • Uses a 32x divisor to get 1024Hz(ish) clock for time keeping.
  • Adafruit SleepDog
    • Configures the WDT's generic clock (GCM_WDT) to use generic clock generator 2.
    • Sets the source for GCKL2 as the internal ultra-low power 32k oscillator
    • Uses a 32x divisor to get a 1024Hz(ish) clock to manage the watchdog.
  • Arduino Low Power
    • Configures the EIC and ADC's generic clocks (GCM_EIC and GCM_ADC) to use generic clock generator 6
    • Sets the source for GCKL6 as the internal ultra-low power 32k oscillator
    • Does NOT use any clock divisor
  • EnviroDIY SDI-12
    • Configures the TCC2/TC3 clock (GCM_TCC2_TC3) to use generic clock generator 4 (GENERIC_CLOCK_GENERATOR_SDI12 = 4)
    • Sets the source for GCKL4 as the DFLL48M - which is in-turn coming from "main" clock set up in SystemInit() in startup.c.
    • Uses a 6x divisor.
  • Modular Sensors (this library)
    • Configures the EIC and WDT's generic clocks (GCM_EIC and GCM_WDT) to use generic clock generator 5 (GENERIC_CLOCK_GENERATOR_MS = 5)
    • Sets the source for GCKLGEN5 as the internal ultra-low power 32k oscillator.
    • Uses a 32x divisor to get a 1024Hz(ish) clock to manage the watchdog and EIC.

SAMD51 and SAME51

The SAMD51 clock system

From 13.1 of the SAMD51 Datasheet)

The SAM D5x/E5x clock system consists of:

  • Clock sources, i.e. oscillators controlled by OSCCTRL and OSC32KCTRL
    • A clock source provides a time base that is used by other components, such as Generic Clock Generators. Example clock sources include the external crystal oscillators (XOSC0 and XOSC1) and the Digital Frequency Locked Loop (DFLL48M).
  • Generic Clock Controller (GCLK), which generates, controls and distributes asynchronous clocks consisting of:
    • Generic Clock Generators: These are programmable prescalers that can use any of the system clock sources as a time base. The Generic Clock Generator 0 generates the clock signal GCLK_MAIN, which is used by the Power Manager and the Main Clock (MCLK) module, which in turn generates synchronous clocks.
  • Generic Clocks: These are clock signals generated by Generic Clock Generators and output by the Peripheral Channels, and serve as clocks for the peripherals of the system. Multiple instances of a peripheral will typically have a separate Generic Clock for each instance. Generic Clock 0 serves as the clock source for the DFLL48M clock input (when multiplying another clock source).
  • Main Clock Controller (MCLK)
    • The MCLK generates and controls the synchronous clocks on the system. This includes the CPU, bus clocks (APB, AHB) as well as the synchronous (to the CPU) user interfaces of the peripherals. It contains clock masks that can turn on/off the user interface of a peripheral as well as prescalers for the CPU and bus clocks.

SAMD51 Clock Requirements Relevant to ModularSensors

The SAMD51 WDT uses the 1K output from the OSCULP32k; there are no other possible clock sources for the WDT. No separate clock generator or peripheral clock configuration is needed. The OSCULP32k cannot be turned off in standby.

The external interrupt controller must be attached to a currently-on clock to tell the difference between rising and HIGH or falling and LOW interrupts. If the external interrupt controller is not attached to a running clock, then interrupts will not work! One the SAMD51, the EIC can be configured to work directly with the OSCULP32k without having to setup a separate clock generator. If the EIC is not configured to connect directly to the OSCULP32k, the GCLK it is configured to must be set to run in standby. The path from a clock source to the EIC on the SAMD51 is very similar to that of the SAMD21.

SAMD51 Settings at Power On

See section 13.7 of the datasheet.

SAMD51 Arduino Core Setup Clock Generator Configuration

Within the SAMD core SystemInit() in startup.c configures clocks with these steps:

  • Enable XOSC32K clock (external on-board 32.768Hz oscillator) if a crystal is available
    • Also enable the 32k output, the 1k output, standard gain mode, and configure the oscillator pins for a crystal connected between XIN32 and XOUT32
    • Sets start-up time to 0x0 = 2048 clock cycles ~= 65.592ms
    • Sets on-demand and run-in-standby both to 0, so the external 32k oscillator will always run in active or idle mode and will only run if requested by peripheral in standby mode (table 29-1)
  • Set XOSC32K or OSC32K (if crystalless) as source of Generic Clock Generator 3
  • Set OSCULP32K (internal ultra-low power 32.768Hz oscillator) as the source for Generic Clock Generator 0
    • NOTE: The default power-on source of generic clock generator 0 is the DFLL48.
    • NOTE: Farther down, generic clock generator 0 is resourced from DPLL0 (at 120MHz)
  • Configure the DFLL48M clock in open loop mode (no reference clock)
    • Source generic clock generator 5 (GENERIC_CLOCK_GENERATOR_1M) from the DFLL with a divisor of 48
    • Sets on-demand and run-in-standby both to 0, so the DFLL48M will always run in active or idle mode and will not run in standby mode (28.8.7, slightly different than table 29-1 for (X)OSC32K)
  • Configure DPLL peripheral clocks
    • Configure PLL0 at 120MHz (or F_CPU), using generic clock generator 5 (DFLL48M / 48) as the reference clock
    • Configure PLL1 at 100MHz, using generic clock generator 5 (DFLL48M / 48) as the reference clock
    • Sets on-demand and run-in-standby both to 0 for both FDPLL, so the PLLs will always run in active or idle mode and will not run in standby mode (28.8.12)
  • Configure other generic clock generators to use for peripheral clocks
    • Source generic clock generator 1 from the DFLL48M with no divisor
      • 48MHz clock generator; used for the USB and "stuff"
    • Source generic clock generator 2 from the PLL1 at 100MHz with no divisor
      • 100MHz clock generator; used for "other peripherals"
    • Source generic clock generator 4 from the DFLL48M at 48MHz with 4x divisor
      • 12MHz clock generator; used for the DAC
  • Set the main clock source as the source for the main generic clock generator
    • MAIN_CLOCK_SOURCE = GCLK_GENCTRL_SRC_DPLL0
    • GENERIC_CLOCK_GENERATOR_MAIN = 0
    • This is resetting the source of generic clock generator 0 to be the DPLL0 at 120MHz, it previously had been set to the OSCULP32K.

Resulting generic clock speeds

  • GCLK0 = F_CPU (likely 120MHz, but could be different depending on variant.h); sourced from DLPP0, which does not run in standby.
  • GCLK1 = 48 MHz; sourced from DFLL48M, which does not run in standby.
  • GCLK2 = 100 MHz; sourced from DLPP1, which does not run in standby.
  • GCLK3 = 32 kHz; sourced from XOSC32K, which does run in standby if requested by peripheral (I think?)
  • GCLK4 = 12 MHz; sourced from DFLL48M, which does not run in standby.

SAMD51 Arduino Core Library Clock and Peripheral Configuration

  • WInterrupts.c
    • Configures the external interrupt controller (EIC) clock (EIC_GCLK_ID) to use GCLKGEN2 at 100 MHz
    • Does not change the source or other configuration for GCLKGEN2
  • wiring_analog.c
    • Configures timer counter clocks (specific clock depending on the analog pin) to use GCLKGEN0 at 120 MHz
    • Does not change the source or other configuration for GCLKGEN0
  • wiring.c
    • Configures the ADC (ADC0_GCLK_ID and ADC1_GCLK_ID) to use GCLKGEN1 at 48 MHz
    • Does not change the source or other configuration for GCLKGEN1
    • Configures the DAC (DAC_GCLK_ID) to use GCLKGEN4 at 12 MHz
    • Does not change the source or other configuration for GCLKGEN4
  • SERCOM
    • Configures the various SERCOM clocks to various sources depending on the speed of the SERCOM peripheral
      • SERCOM0_GCLK_ID_CORE/SERCOM0_GCLK_ID_SLOW -> SERCOM7_GCLK_ID_CORE/SERCOM7_GCLK_ID_SLOW, depending on how many SERCOM's are defined in variant.h
    • Does not change the source or other configuration of any of the clock generators
  • Tone
    • Configures timer counter 0 clock (TONE_TC_GCLK_ID = TC0_GCLK_ID) to use GCLKGEN0 at 120 (or F_CPU) MHz
    • Does not change the source or other configuration for GCLKGEN0
  • I2S
    • Configures the I2S's generic clocks (I2S_GCLK_ID_0 and I2S_GCLK_ID_1) to use the generic clock generator specified for I2S in variant.h (likely GCLKGEN3)
    • Sets the source of the specified generic clock generator to be the DFLL48 or the OSC8M, depending on the I2S speed
  • USB (host, core, TinyUSB)
    • Configures the USB (USB_GCLK_ID) to use GCLKGEN0 at 120 (or F_CPU) MHz
    • Does not change the source or other configuration for GCLKGEN0
  • Servo
    • Configures timer counter clocks (specific clock depending on the analog pin) to use GCLKGEN0 at 120 MHz
    • Does not change the source or other configuration for GCLKGEN0

Thus, if the clock source for interrupts is not running in standby, the interrupts will not be able to wake the device. In WInterrupts.c in the Adafruit SAMD core, generic clock generator 2 (from the PLL1 at 100MHz with no divisor) is used for the EIC peripheral. The Arduino core does NOT configure the generic clock generator 0 (ie GCLK_MAIN = DFLL48M) to stay awake in standby!

Clocks Used by Non-Core Libraries for the SAMD51

  • RTCZero
    • The RTC of the SAMD51 is sourced directly from an oscillator, not via the generic clock generator system. This library only configures the RTC oscillator on the SAMD51.
  • Adafruit SleepDog
    • The WDT on the SAMD51 is directly attached to OSCULP32K. This library doesn't make any clock changes for the SAMD51.
  • Arduino Low Power
    • This library doesn't support the SAMD51
  • EnviroDIY SDI-12
    • Configures the TC2 clock (TC2_GCLK_ID) to use generic clock generator 6 (GENERIC_CLOCK_GENERATOR_SDI12 = 6)
    • Sets the source for GCKL6 as the DPLL0 at 120MHz
    • Uses a 15x divisor between the DPLL0 and GCKL6.
  • Modular Sensors (this library)
    • This library sets OSCULP32K as the source for the EIC and disables GCLK_EIC.
    • This library also resets GCLK7 so it is disconnected from any source.
    • This library disables the following peripheral timers and ties them to the disabled GCLK7:
      • 4 - GCLK_EIC
      • 5 - GCLK_FREQM_MSR
      • 6 - GCLK_FREQM_REF
      • 9 - GCLK_TC0/GCLK_TC1
      • 11 - GCLK_EVSYS0
      • 12 - GCLK_EVSYS1
      • 13 - GCLK_EVSYS2
      • 14 - GCLK_EVSYS3
      • 15 - GCLK_EVSYS4
      • 16 - GCLK_EVSYS5
      • 17 - GCLK_EVSYS6
      • 18 - GCLK_EVSYS7
      • 19 - GCLK_EVSYS8
      • 20 - GCLK_EVSYS9
      • 21 - GCLK_EVSYS10
      • 22 - GCLK_EVSYS11
      • 25 - GCLK_TCC0/GCLK_TCC1
      • 26 - GCLK_TC2/GCLK_TC3
      • 27 - GCLK_CAN0
      • 28 - GCLK_CAN1
      • 29 - GCLK_TCC2/GCLK_TCC3
      • 30 - GCLK_TC4/GCLK_TC5
      • 31 - GCLK_PDEC
      • 32 - GCLK_AC
      • 33 - GCLK_CCL
      • 38 - GCLK_TCC4
      • 39 - GCLK_TC6/GCLK_TC7
      • 42 - GCLK_DAC
      • 43 - GCLK_I2S
      • 44 - GCLK_I2S
      • 45 - GCLK_SDHC0
      • 46 - GCLK_SDHC1
      • 47 - GCLK_CM4_TRACE

Summary of Peripheral Clock Assignments

  • GCLK_SERCOM[0..7]_SLOW/GCLK_SDHC0_SLOW/GCLK_SDHC0_SLOW (3) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_EIC (4) - GCLKGEN0 (F_CPU; sourced from DLPP0) - WInterrupts.c
    • This is disabled by Modular Sensors!
  • GCLK_TC0/GCLK_TC1 (9) - GCLKGEN0 (F_CPU; sourced from DLPP0) - Tone.cpp, Servo.cpp, wiring_analog.c
  • GCLK_USB (10) - GCLKGEN0 (F_CPU; sourced from DLPP0) - samd21_host.c, USBCore.cpp, Adafruit_TinyUSB_samd.cpp
  • GCLK_SERCOM2_CORE (23) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_SERCOM3_CORE (24) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_TC2/GCLK_TC3 (26) - GCLKGEN0 (F_CPU; sourced from DLPP0) - Servo.cpp, wiring_analog.c potential conflict with SDI-12, be cautious
  • GCLK_TC2/GCLK_TC3 (26) - GCLKGEN6 (F_CPU; sourced from DLPP0) - SDI12_boards.cpp potential conflict with servo, be cautious
  • GCLK_TC4/GCLK_TC5 (30) - GCLKGEN0 (F_CPU; sourced from DLPP0) - Servo.cpp, wiring_analog.c
  • GCLK_SERCOM4_CORE (34) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_SERCOM5_CORE (35) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_SERCOM6_CORE (36) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_SERCOM7_CORE (37) - potentially any of GCLK0-GCLK4 - SERCOM.cpp
  • GCLK_TC6/GCLK_TC7 (39) - GCLKGEN0 (F_CPU; sourced from DLPP0) - Servo.cpp, wiring_analog.c
  • GCLK_ADC0 (40) - GCLKGEN1 (48 MHz; sourced from DFLL48M) - wiring.c
  • GCLK_ADC12 (41) - GCLKGEN1 (48 MHz; sourced from DFLL48M) - wiring.c
  • GCLK_DAC (42) - GCLKGEN4 (12 MHz; sourced from DFLL48M) - wiring.c
  • GCLK_I2S[0] (43) - GCLKGEN3 (32 kHz; sourced from XOSC32K) most likely - I2S.cpp
  • GCLK_I2S[1] (44) - GCLKGEN3 (32 kHz; sourced from XOSC32K) most likely - I2S.cpp

The Non-Volatile Interrupt Controller (NVIC)

This entire section is copied selections from Microchip's developer help on the NVIC.

NVIC Overview

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. The four possible programmable priority levels are 0x00 (highest urgency), 0x40, 0x80, and 0xC0 (lowest urgency).

  • 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.

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. The CMSIS IRQ numbers (the peripheral-interrupt-to-CMSIS-IRQ-number mapping) are defined in the processor specific include files within the bootloader. That is this file for the UF2 bootloader for the SAMD51 variant the EnviroDIY Stonefly is based on.

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.

1/* Disable **All** Interrupts */
2void __disable_irq(void);
3
4/* Enable **ALL** Interrupts */
5void __enable_irq(void);

NVIC-Specific Functions

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

1/* Set the priority for an interrupt */
2void NVIC_SetPriority(IRQn_t IRQn, uint32_t priority);
3
4/* Enable a device specific interrupt */
5void NVIC_EnableIRQ (IRQn_Type IRQn);
6
7/* Disable a device specific interrupt */
8void 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.

From the SAMD51 datasheet, here are the interrupt line mapping numbers for interrupts in the NVIC

[Datasheet Table 10-1 Interrupt Line Mapping](

Table 10-1: Interrupt Line Mapping
ModuleSourceLineEnabled?
EIC NMI - External Interrupt ControlNMINMIenabled
PM - Power ManagerSLEEPRDY0disabled
MCLK - Main ClockCKRDY1disabled
OSCCTRL - Oscillators ControlXOSCFAIL02disabled
XOSCRDY0
XOSCFAIL13disabled
XOSCRDY1
DFLLLCKC4disabled
DFLLLCKF
DFLLOOB
DFLLRCS
DFLLRDY
DPLL00LCKF5disabled
DPLL0LCKR
DPLL0LDRTO
DPLL0LTO
DPLL1LCKF6disabled
DPLL1LCKR
DPLL1LDRTO
DPLL1LTO
OSC32KCTRL - 32 kHz Oscillators ControlXOSC32KFAIL7disabled
XOSC32KRDY
SUPC - Supply ControllerBOD33RDY8disabled
B33SRDY
VCORERDY
VREGRDY
BOD33DET9disabled
WDT - Watchdog TimerEW10enabled
RTC - Real-Time CounterCMP011disabled
CMP1
CMP2
CMP3
OVF
PER0
PER1
PER2
PER3
PER4
PER5
PER6
PER7
TAMPER
ALARM0
ALARM1
EIC - External Interrupt ControllerEXTINT 012enabled
EXTINT 113enabled
EXTINT 214enabled
EXTINT 315enabled
EXTINT 416enabled
EXTINT 517enabled
EXTINT 618enabled
EXTINT 719enabled
EXTINT 820enabled
EXTINT 921enabled
EXTINT 1022enabled
EXTINT 1123enabled
EXTINT 1224enabled
EXTINT 1325enabled
EXTINT 1426enabled
EXTINT 1527enabled
FREQM - Frequency MeterDONE28disabled
NVMCTRL - Non-Volatile Memory ControllerDONE29disabled
ADDRE
PROGE
LOCKE
ECCSE
ECCDE
NVME
SUSPE
SEESFULL30disabled
SEESOVF
SEEWRC
DMAC - Direct Memory Access ControllerSUSP 031enabled
TCMPL 0
TERR 0
SUSP 132enabled
TCMPL 1
TERR 1
SUSP 233enabled
TCMPL 2
TERR 2
SUSP 334enabled
TCMPL 3
TERR 3
SUSP 4..3135enabled
TCMPL 4..31
TERR 4..31
EVSYS - Event System InterfaceEVD 036disabled
OVR 0
EVD 137disabled
OVR 1
EVD 238disabled
OVR 2
EVD 339disabled
OVR 3
EVD 4..1140disabled
OVR 4..11
PAC - Peripheral Access ControllerERR41disabled
RAM ECCSINGLEE45disabled
DUALE
SERCOM0 - Serial Communication Interface 0046disabled
147disabled
248disabled
349disabled
4
5
7
SERCOM1 - Serial Communication Interface 1050disabled
151disabled
252disabled
353disabled
4
5
7
SERCOM2 - Serial Communication Interface 2054enabled
155enabled
256enabled
357enabled
4
5
7
SERCOM3 - Serial Communication Interface 3058enabled
159enabled
260enabled
361enabled
4
5
7
SERCOM4 - Serial Communication Interface 4062enabled
163enabled
264enabled
365enabled
4
5
7
SERCOM5 - Serial Communication Interface 5066enabled
167enabled
268enabled
369enabled
4
5
7
SERCOM6 - Serial Communication Interface 6070enabled
171enabled
272enabled
373enabled
4
5
7
SERCOM7 - Serial Communication Interface 7074disabled
175disabled
276disabled
377disabled
4
5
7
CAN0 - Control Area Network 0LINE 078disabled
LINE 1
CAN1 - Control Area Network 1LINE 079disabled
LINE 1
USB - Universal Serial BusEORSM/DNRSM80enabled
EORST/RST
LPM/DCONN
LPMSUSP/DDISC
RAMACER
RXSTP/TXSTP 0..7
STALL0/STALL 0..7
STALL1 0..7
SUSPEND
TRFAIL0/TRFAIL 0..7
TRFAIL1/PERR 0..7
UPRSM
WAKEUP
SOF/HSOF81enabled
TRCPT0 0..782enabled
TRCPT1 0..783enabled
GMAC - Ethernet MACGMAC84disabled
WOL
TCC0 - Timer Counter Control 0CNT85disabled
DFS
ERR
FAULTA
FAULTB
FAULT0
FAULT1
OVF
TRG
UFS
MC086disabled
MC187disabled
MC288disabled
MC389disabled
MC490disabled
MC591disabled
TCC1 - Timer Counter Control 1CNT92disabled
DFS
ERR
FAULTA
FAULTB
FAULT0
FAULT1
OVF
TRG
UFS
MC093disabled
MC194disabled
MC295disabled
MC396disabled
TCC2 - Timer Counter Control 2CNT97disabled
DFS
ERR
FAULTA
FAULTB
FAULT0
FAULT1
OVF
TRG
UFS
MC098disabled
MC199disabled
MC2100disabled
TCC3 - Timer Counter Control 3CNT101disabled
DFS
ERR
FAULTA
FAULTB
FAULT0
FAULT1
OVF
TRG
UFS
MC0102disabled
MC1103disabled
TCC4 - Timer Counter Control 4CNT104disabled
DFS
ERR
FAULTA
FAULTB
FAULT0
FAULT1
OVF
TRG
UFS
MC0105disabled
MC1106disabled
TC0 - Basic Timer Counter 0ERR107disabled
MC0
MC1
OVF
TC1 - Basic Timer Counter 1ERR108disabled
MC0
MC1
OVF
TC2 - Basic Timer Counter 2ERR109disabled
MC0
MC1
OVF
TC3 - Basic Timer Counter 3ERR110disabled
MC0
MC1
OVF
TC4 - Basic Timer Counter 4ERR111disabled
MC0
MC1
OVF
TC5 - Basic Timer Counter 5ERR112disabled
MC0
MC1
OVF
TC6 - Basic Timer Counter 6ERR113disabled
MC0
MC1
OVF
TC7 - Basic Timer Counter 7ERR114disabled
MC0
MC1
OVF
PDEC - Position DecoderDIR115disabled
ERR
OVF
VLC
MC0116disabled
MC1117disabled
ADC0 - Analog Digital Converter 0OVERRUN118disabled
WINMON
RESRDY119disabled
ADC1 - Analog Digital Converter 1OVERRUN120disabled
WINMON
RESRDY121disabled
AC - Analog ComparatorsCOMP0122disabled
COMP1
WIN0
DAC - Digital-to-Analog ConverterOVERRUN0123disabled
OVERRUN1
UNDERRUN0
UNDERRUN1
EMPTY0124disabled
EMPTY1125disabled
RESRDY0126disabled
RESRDY1127disabled
I2S - Inter-IC Sound InterfaceRXOR0128disabled
RXOR1
RXRDY0
RXRDY1
TXRDY0
TXRDY1
TXUR0
TXUR1
PCC - Parallel Capture ControllerDRDY129disabled
OVRE
AES - Advanced Encryption StandardENCCMP130disabled
GFMCMP
TRNG - True Random GeneratorDATARDY131disabled
ICM - Integrity Check MonitorAll ICM Interrupts132disabled
ReservedReserved133disabled
QSPI - Quad SPI interfaceRXC134disabled
DRE
TXC
ERROR
CSRISE
INSTREND
SDHC0 - SD/MMC Host Controller 0All SDHC0 Interrupts135disabled
SDHC1 - SD/MMC Host Controller 1All SDHC1 Interrupts136disabled

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.

NVIC Interrupts Defined in the Adafruit SAMD U2F Bootloader and Arduino Core

SAMD51 NVIC

  • SERCOMs - sercom.cpp - priority of 3
    • SERCOM0_0_IRQn -> SERCOM5_3_IRQn
    • SERCOM6_0_IRQn -> SERCOM6_3_IRQn, iff variant defines SERCOM6
    • SERCOM7_0_IRQn -> SERCOM7_3_IRQn, iff variant defines SERCOM7
  • Timers:
    • TC0 (TC5_IRQn) - Tone.cpp - priority of 5(?)
    • TC1 (TC1_IRQn) - Servo.cpp - priority of 0
      • NOTE: The servo library has a to-do flag in it to allow a second timer, but as of November of 2024 only supports one timer for servo in the SAMD core.rv
  • External Interrupt Controller - WInterrupts.c - priority of 0
    • EIC_0_IRQn -> EIC_15_IRQn
    • A single EIC interrupt for the USB pin is also enabled by Adafruit_USBH_Host.cpp if TinyUSB is used.
  • USB - samd21_host.c and USBCore.cpp - priority 0
    • NOTE: Despite the name, samd21_host.c is used for all SAMD boards
    • USB_0_IRQn -> USB_3_IRQn
  • DMAC - Adafruit_ZeroDMA.cpp or I2S/../DMA.cpp
    • DMAC_0_IRQn -> DMAC_4_IRQn - priority of 3

SAMD21 NVIC

  • SERCOMs - sercom.cpp - priority of 3
    • SERCOM0_IRQn -> SERCOM3_IRQn
    • SERCOM4_IRQn, iff variant defines SERCOM4
    • SERCOM5_IRQn, iff variant defines SERCOM5
  • Timers:
    • TC5 (TC5_IRQn) - Tone.cpp - priority of 5(?)
    • TC4 (TC4_IRQn) - Servo.cpp - priority of 0
      • NOTE: The servo library has a to-do flag in it to allow a second timer, but as of November of 2024 only supports one timer for servo in the SAMD core.
  • External Interrupt Controller - WInterrupts.c - priority of 0
    • EIC_IRQn
    • The EIC interrupts are also enabled by Adafruit_USBH_Host.cpp if TinyUSB is used.
  • USB - samd21_host.c and USBCore.cpp - priority 0
    • USB_IRQn
  • DMAC - Adafruit_ZeroDMA.cpp or I2S/../DMA.cpp
    • DMAC_IRQn - priority of 3