SCIF
module reference#include <scif.h>Makefile :
scif
is already included by default
The SCIF (System Control Interface) manages the generation of the system and generic clocks. It features :
Generic clocks are clocks for which the input can be connected to any system clock, that provide an optional divider, and that can be routed to different outputs. There are 12 generic clocks. Each of them is dedicated to a few peripherals, that can use them for internal purposes. The first four generic clocks outputs can be mapped to GPIO pins using the SCIF_GCLKn
signal lines, which can be useful in order to generate clock signals for external components. Generic clocks can use up to two different extern clock inputs as clock sources, SCIF_GCLK_IN0
and SCIF_GCLK_IN1
.
115000
.RCFAST_4MHZ
, RCFAST_8MHZ
or RCFAST_12MHZ
. This oscillator will operate in closed-loop mode based on the 32kHz clock generated by the BPM, and is therefore quite precise.enableOSC0()
.Enable the PLL, which is able to generate a high-frequency clock based on a lower-frequency clock. The low-frequency input clock is provided using the generic clock GCLK9
, which will be connected to the specified referenceClock
running at the specified referenceFrequency
. The ratio between the input frequency and the output frequency is specified using mul
and div
according to the following formulas :
div
> 0 : \(f_{out}=\frac{mul+1}{div}.f_{in}\)div
= 0 : \(f_{out}=2(mul+1).f_{in}\)The PLL is used by the USB module to generate the 48MHz USB clock.
Disable the PLL.
Enable the DFLL, which is able to generate a high-frequency clock based on a lower-frequency clock. The low-frequency input clock is provided using the generic clock GCLK0
, which will be connected to the specified referenceClock
running at the specified referenceFrequency
. The multiplication ratio is calculated from the output frequency
.
Disable the DFLL.
80000000
.GCLKChannel
and GCLKSource
enums in the header below for the full list of channels and sources available, but the most important channels are :
GCLK0_DFLL
: GCLK0 output on pin PB10 by default on CarbideGCLK1_DFLLDITHER
: GCLK1 output on pin PB11 by default on CarbideGCLK2_AST
: GCLK2 output on pin PB12 by default on CarbideGCLK3_CATB
: GCLK3 output on pin PB13 by default on CarbideRC32K
: 32KHz oscillator (locked to the external 32KHz crystal)RCFAST
: 4MHz, 8MHz or 12MHz oscillator, enabled using enableRCFAST()
RC80M
: 80MHz oscillator, enabled using enableRC80M()
(note that the microcontroller can't output clock speeds higher than 48MHz, you need to use a divider)CLKCPU
: clock currently used by the CPUSCIF_GCLKn
GPIO output signals if output
is set.divider
can be specified in order to reduce the clock speed. Use 0 to disable the divider, otherwise you should only use even values. The maximum divider value is 512
for most generic clocks, except for GCLK11_MASTER
which can be divided up to 131072
.The module covers a large part of the SCIF's feature set, but there are advanced aspects that can be customized for specific applications. Interrupts can be generated on some clock-related events. The DFLL has more complex features and options, such as a spread-spectrum generator. There are also fractional prescalers that can be used to tune the output frequency of the generic clocks.
#ifndef _SCIF_H_ #define _SCIF_H_ #include <stdint.h> #include "gpio.h" // System Control Interface // This module manages most of the clock sources : external crystal // oscillator, DFLL/PLL, low-power default RCSYS oscillator, the faster // RC80M and RCFAST oscillators, and the Generic Clocks system. namespace SCIF { // Peripheral memory space base address const uint32_t SCIF_BASE = 0x400E0800; // Registers addresses const uint32_t OFFSET_IER = 0x0000; // Interrupt Enable Register const uint32_t OFFSET_IDR = 0x0004; // Interrupt Disable Register const uint32_t OFFSET_IMR = 0x0008; // Interrupt Mask Register const uint32_t OFFSET_ISR = 0x000C; // Interrupt Status Register const uint32_t OFFSET_ICR = 0x0010; // Interrupt Clear Register const uint32_t OFFSET_PCLKSR = 0x0014; // Power and Clocks Status Register const uint32_t OFFSET_UNLOCK = 0x0018; // Unlock Register const uint32_t OFFSET_CSCR = 0x001C; // Chip Specific Configuration Register const uint32_t OFFSET_OSCCTRL0 = 0x0020; // Oscillator Control Register const uint32_t OFFSET_PLL0 = 0x0024; // PLL0 Control Register const uint32_t OFFSET_DFLL0CONF = 0x0028; // DFLL0 Config Register const uint32_t OFFSET_DFLL0VAL = 0x002C; // DFLL Value Register const uint32_t OFFSET_DFLL0MUL = 0x0030; // DFLL0 Multiplier Register const uint32_t OFFSET_DFLL0STEP = 0x0034; // DFLL0 Step Register const uint32_t OFFSET_DFLL0SSG = 0x0038; // DFLL0 Spread Spectrum Generator Control Register const uint32_t OFFSET_DFLL0RATIO = 0x003C; // DFLL0 Ratio Register const uint32_t OFFSET_DFLL0SYNC = 0x0040; // DFLL0 Synchronization Register const uint32_t OFFSET_RCCR = 0x0044; // System RC Oscillator Calibration Register const uint32_t OFFSET_RCFASTCFG = 0x0048; // 4/8/12MHz RC Oscillator Configuration Register const uint32_t OFFSET_RCFASTSR = 0x004C; // 4/8/12MHz RC Oscillator Status Register const uint32_t OFFSET_RC80MCR = 0x0050; // 80MHz RC Oscillator Register const uint32_t OFFSET_HRPCR = 0x0064; // High Resolution Prescaler Control Register const uint32_t OFFSET_FPCR = 0x0068; // Fractional Prescaler Control Register const uint32_t OFFSET_FPMUL = 0x006C; // Fractional Prescaler Multiplier Register const uint32_t OFFSET_FPDIV = 0x0070; // Fractional Prescaler DIVIDER Register const uint32_t OFFSET_GCCTRL0 = 0x0074; // Generic Clock Control 0 const uint32_t OFFSET_GCCTRL1 = 0x0078; // Generic Clock Control 1 const uint32_t OFFSET_GCCTRL2 = 0x007C; // Generic Clock Control 2 const uint32_t OFFSET_GCCTRL3 = 0x0080; // Generic Clock Control 3 const uint32_t OFFSET_GCCTRL4 = 0x0084; // Generic Clock Control 4 const uint32_t OFFSET_GCCTRL5 = 0x0088; // Generic Clock Control 5 const uint32_t OFFSET_GCCTRL6 = 0x008C; // Generic Clock Control 6 const uint32_t OFFSET_GCCTRL7 = 0x0090; // Generic Clock Control 7 const uint32_t OFFSET_GCCTRL8 = 0x0094; // Generic Clock Control 8 const uint32_t OFFSET_GCCTRL9 = 0x0098; // Generic Clock Control 9 const uint32_t OFFSET_GCCTRL10 = 0x009C; // Generic Clock Control 10 const uint32_t OFFSET_GCCTRL11 = 0x00A0; // Generic Clock Control 11 // Subregisters const uint32_t PCLKSR_OSC0RDY = 0; const uint32_t PCLKSR_DFLL0RDY = 3; const uint32_t PCLKSR_PLL0LOCK = 6; const uint32_t OSCCTRL0_MODE = 0; const uint32_t OSCCTRL0_GAIN = 1; const uint32_t OSCCTRL0_AGC = 3; const uint32_t OSCCTRL0_STARTUP = 8; const uint32_t OSCCTRL0_OSCEN = 16; const uint32_t PLL0_EN = 0; const uint32_t PLL0_PLLOSC = 1; const uint32_t PLL0_PLLOPT = 3; const uint32_t PLL0_PLLDIV = 8; const uint32_t PLL0_PLLMUL = 16; const uint32_t PLL0_PLLCOUNT = 24; const uint32_t DFLL0CONF_EN = 0; const uint32_t DFLL0CONF_MODE = 1; const uint32_t DFLL0CONF_RANGE = 16; const uint32_t DFLL0STEP_FSTEP = 0; const uint32_t DFLL0STEP_CSTEP = 16; const uint32_t RCFASTCFG_EN = 0; const uint32_t RCFASTCFG_TUNEEN = 1; const uint32_t RCFASTCFG_JITMODE = 2; const uint32_t RCFASTCFG_NBPERIODS = 4; const uint32_t RCFASTCFG_FRANGE = 8; const uint32_t RCFASTCFG_LOCKMARGIN = 12; const uint32_t RC80MCR_EN = 0; const uint32_t GCCTRL_CEN = 0; const uint32_t GCCTRL_DIVEN = 1; const uint32_t GCCTRL_OSCSEL = 8; const uint32_t GCCTRL_DIV = 16; // Constants const uint32_t UNLOCK_KEY = 0xAA << 24; // Error codes const uint16_t ERR_PLL_OUT_OF_RANGE = 0x0001; const uint16_t ERR_DFLL_OUT_OF_RANGE = 0x0002; const uint16_t WARN_RCFAST_ALREADY_ENABLED = 0x0003; // RCFAST can be configured to operate in any of these frequencies enum class RCFASTFrequency { RCFAST_4MHZ = 0b00, RCFAST_8MHZ = 0b01, RCFAST_12MHZ = 0b10 }; // Each generic clock channel has one or two specific allocations enum class GCLKChannel { GCLK0_DFLL, // Also GCLK0 pin GCLK1_DFLLDITHER, // Also GCLK1 pin GCLK2_AST, // Also GCLK2 pin GCLK3_CATB, // Also GCLK3 pin GCLK4_AES, GCLK5_GLOC_TC0, GCLK6_ABDAC_IIS, GCLK7_USB, GCLK8_TC1_PEVC0, GCLK9_PLL0_PEVC1, GCLK10_ADC, GCLK11_MASTER }; // Each generic clock can be mapped to any of these clock sources enum class GCLKSource { RCSYS = 0, OSC32K = 1, DFLL = 2, OSC0 = 3, RC80M = 4, RCFAST = 5, RC1M = 6, CLKCPU = 7, CLKHSB = 8, CLKPBA = 9, CLKPBB = 10, CLKPBC = 11, CLKPBD = 12, RC32K = 13, CLK1K = 15, PLL = 16, HRP = 17, FP = 18, GCLKIN0 = 19, GCLKIN1 = 20, GCLK11 = 21 }; enum class PinFunction { GCLK, GCLK_IN }; // Module API // RCSYS (115kHz) is the default RC oscillator on which the chip operates after reset unsigned long getRCSYSFrequency(); // RCFAST is a faster RC oscillator than RCSYS, which can operate at 4MHz, 8MHz or 12MHz void enableRCFAST(RCFASTFrequency frequency); void disableRCFAST(); unsigned long getRCFASTFrequency(); // OSC0 is an external crystal oscillator, which can operate from 0.6MHz to 30MHz. // See datasheet §42.7.1 Oscillator 0 (OSC0) Characteristics for more details on // the required characteristics for this oscillator and its load capacitors. void enableOSC0(unsigned long frequency); void disableOSC0(); unsigned long getOSC0Frequency(); // PLL (Phase Locked Loop) is able to generate a high-frequency clock based on a // lower-frequency one. It is used by the USB module. void enablePLL(int mul, int div, GCLKSource referenceClock=GCLKSource::RCSYS, unsigned long referenceFrequency=115000UL); void disablePLL(); unsigned long getPLLFrequency(); // DFLL (Digital Frequency Locked Loop) is similar to the PLL void enableDFLL(unsigned long frequency, GCLKSource referenceClock=GCLKSource::OSC32K, unsigned long referenceFrequency=32768); void disableDFLL(); unsigned long getDFLLFrequency(); // RC80M is the faster RC oscillator available, operating at 80MHz. It can power the // main clock if downscaled to at most 48MHz, or be used as a generic clock. void enableRC80M(); void disableRC80M(); unsigned long getRC810MFrequency(); // Generic clocks void enableGenericClock(GCLKChannel channel, GCLKSource source, bool output=false, uint32_t divider=0); void disableGenericClock(GCLKChannel channel); // Set the pins used for signal lines void setPin(PinFunction function, int channel, GPIO::Pin pin); } #endif
#include "scif.h" #include "bscif.h" #include "error.h" namespace SCIF { // Package-dependant, defined in pins_sam4l_XX.cpp extern struct GPIO::Pin PINS_GCLK[]; extern struct GPIO::Pin PINS_GCLK_IN[]; // Clocks frequencies unsigned long _rcsysFrequency = 115000UL; unsigned long _osc0Frequency = 0; unsigned long _pllFrequency = 0; unsigned long _dfllFrequency = 0; unsigned long _rcfastFrequency = 0; RCFASTFrequency _rcfastFrequencySelected = RCFASTFrequency::RCFAST_4MHZ; unsigned long _rc80mFrequency = 80000000UL; // Output mask of the generic clocks bool _genericClockOutputEnabled[4] = {false, false, false, false}; // RCSYS frequency is fixed unsigned long getRCSYSFrequency() { return _rcsysFrequency; } // RCFAST void enableRCFAST(RCFASTFrequency frequency) { // If RCFAST is already enabled if (_rcfastFrequency > 0) { // If the correct frequency is already selected, do nothing if (frequency == _rcfastFrequencySelected) { return; } else { // The current RCFAST setting will be overridden, issue a warning Error::happened(Error::Module::SCIF, WARN_RCFAST_ALREADY_ENABLED, Error::Severity::WARNING); disableRCFAST(); } } // Save the frequency for future use switch (frequency) { case RCFASTFrequency::RCFAST_4MHZ: _rcfastFrequency = 4000000UL; break; case RCFASTFrequency::RCFAST_8MHZ: _rcfastFrequency = 8000000UL; break; case RCFASTFrequency::RCFAST_12MHZ: _rcfastFrequency = 12000000UL; break; default: return; } _rcfastFrequencySelected = frequency; // Unlock the RCFASTCFG register, which is locked by default as a safety mesure (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_RCFASTCFG; // ADDR : unlock RCFASTCFG // Configure RCFAST (*(volatile uint32_t*)(SCIF_BASE + OFFSET_RCFASTCFG)) = 1 << RCFASTCFG_EN // EN : enable the oscillator | 1 << RCFASTCFG_TUNEEN // TUNEEN : enable the tuner (closed-loop mode) | 0 << RCFASTCFG_JITMODE // JITMODE : update trim value when lock lost | 5 << RCFASTCFG_NBPERIODS // NBPERIODS : number of 32kHz periods (max : 7) | static_cast<int>(frequency) << RCFASTCFG_FRANGE // FRANGE : desired frequency | 5 << RCFASTCFG_LOCKMARGIN; // LOCKMARGIN : error tolerance of the tuner // Wait for RCFAST to be ready while (!((*(volatile uint32_t*)(SCIF_BASE + OFFSET_RCFASTCFG)) & (1 << RCFASTCFG_EN))); } void disableRCFAST() { // Reset the saved frequency _rcfastFrequency = 0; // Unlock the RCFASTCFG register, which is locked by default as a safety mesure (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_RCFASTCFG; // ADDR : unlock RCFASTCFG // Disable RCFAST (*(volatile uint32_t*)(SCIF_BASE + OFFSET_RCFASTCFG)) = 0; } unsigned long getRCFASTFrequency() { return _rcfastFrequency; } // OSC0 void enableOSC0(unsigned long frequency) { // Unlock the OSCCTRL0 register, which is locked by default as a safety mesure (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_OSCCTRL0; // ADDR : unlock OSCCTRL0 // Save the indicated frequency for future use _osc0Frequency = frequency; // Configure OSC0 (*(volatile uint32_t*)(SCIF_BASE + OFFSET_OSCCTRL0)) = 1 << OSCCTRL0_MODE // MODE : crystal | 3 << OSCCTRL0_GAIN // GAIN : G3 (8MHz to 16MHz) | 3 << OSCCTRL0_STARTUP // STARTUP : ~18ms | 1 << OSCCTRL0_OSCEN; // OSCEN : enabled // Wait for OSC0 to be ready while (!((*(volatile uint32_t*)(SCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_OSC0RDY))); } void disableOSC0() { // Unlock the OSCCTRL0 register, which is locked by default as a safety mesure (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_OSCCTRL0; // ADDR : unlock OSCCTRL0 // Reset the saved frequency _osc0Frequency = 0; // Disable OSC0 (*(volatile uint32_t*)(SCIF_BASE + OFFSET_OSCCTRL0)) = 0; } unsigned long getOSC0Frequency() { return _osc0Frequency; } // PLL void enablePLL(int mul, int div, GCLKSource referenceClock, unsigned long referenceFrequency) { // Enable reference clock SCIF::enableGenericClock(SCIF::GCLKChannel::GCLK9_PLL0_PEVC1, referenceClock); // Check frequency-related parameters if (mul == 0 || mul > 15 || div > 15) { Error::happened(Error::Module::SCIF, ERR_PLL_OUT_OF_RANGE, Error::Severity::CRITICAL); return; } // Save the frequency for future use if (div == 0) { _pllFrequency = 2 * (mul + 1) * referenceFrequency; } else { _pllFrequency = ((mul + 1) * referenceFrequency) / div; } // Disable PLL (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_PLL0; // ADDR : unlock PLL0 (*(volatile uint32_t*)(SCIF_BASE + OFFSET_PLL0)) = 0; // Configure PLL (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_PLL0; // ADDR : unlock PLL0 (*(volatile uint32_t*)(SCIF_BASE + OFFSET_PLL0)) = 1 << PLL0_PLLOSC // PLLOSC : select GCLK9 as a reference | div << PLL0_PLLDIV // PLLDIV : configure division factor | mul << PLL0_PLLMUL; // PLLMUL : configure multiplication factor // Enable PLL (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_PLL0; // ADDR : unlock PLL0 (*(volatile uint32_t*)(SCIF_BASE + OFFSET_PLL0)) |= 1 << PLL0_EN; // EN : enable the oscillator // Wait for PLL to be ready while (!((*(volatile uint32_t*)(SCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_PLL0LOCK))); } void disablePLL() { // Reset the saved frequency _pllFrequency = 0; // Disable PLL (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_PLL0; // ADDR : unlock PLL0 (*(volatile uint32_t*)(SCIF_BASE + OFFSET_PLL0)) = 0; } unsigned long getPLLFrequency() { return _pllFrequency; } // DFLL void enableDFLL(unsigned long frequency, GCLKSource referenceClock, unsigned long referenceFrequency) { // Enable reference 32 KHz clock SCIF::enableGenericClock(SCIF::GCLKChannel::GCLK0_DFLL, referenceClock); // Compute frequency-related parameters uint8_t range = 0; if (frequency >= 96000000 && frequency <= 150000000) { range = 0; } else if (frequency >= 50000000) { range = 1; } else if (frequency >= 25000000) { range = 2; } else if (frequency >= 20000000) { range = 3; } else { Error::happened(Error::Module::SCIF, ERR_DFLL_OUT_OF_RANGE, Error::Severity::CRITICAL); return; } unsigned long mul = frequency / referenceFrequency; if (mul > 65535) { Error::happened(Error::Module::SCIF, ERR_DFLL_OUT_OF_RANGE, Error::Severity::CRITICAL); return; } // Save the frequency for future use _dfllFrequency = frequency; // Enable DFLL (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_DFLL0CONF; // ADDR : unlock DFLL0CONF (*(volatile uint32_t*)(SCIF_BASE + OFFSET_DFLL0CONF)) |= 1 << DFLL0CONF_EN; // EN : enable the oscillator // Wait for DFLL to be ready while (!((*(volatile uint32_t*)(SCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_DFLL0RDY))); // Configure frequency range (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_DFLL0CONF; // ADDR : unlock DFLL0CONF (*(volatile uint32_t*)(SCIF_BASE + OFFSET_DFLL0CONF)) |= range << DFLL0CONF_RANGE; // RANGE : Frequency range value // Configure frequency multiplier (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_DFLL0MUL; // ADDR : unlock DFLL0CONF (*(volatile uint32_t*)(SCIF_BASE + OFFSET_DFLL0MUL)) = mul; // Configure maximum steps (used to adjust the speed at which the DFLL locks) (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_DFLL0STEP; // ADDR : unlock DFLL0CONF (*(volatile uint32_t*)(SCIF_BASE + OFFSET_DFLL0STEP)) = 10 << DFLL0STEP_FSTEP // FSTEP : Fine maximum step | 10 << DFLL0STEP_CSTEP; // CSTEP : Coarse maximum step // Enable Closed Loop mode (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_DFLL0CONF; // ADDR : unlock DFLL0CONF (*(volatile uint32_t*)(SCIF_BASE + OFFSET_DFLL0CONF)) |= 1 << DFLL0CONF_MODE; // MODE : closed loop mode // Wait for DFLL to be ready while (!((*(volatile uint32_t*)(SCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_DFLL0RDY))); } void disableDFLL() { // Reset the saved frequency _dfllFrequency = 0; // Disable DFLL (*(volatile uint32_t*)(SCIF_BASE + OFFSET_UNLOCK)) = UNLOCK_KEY // KEY : Magic word (see datasheet) | OFFSET_DFLL0CONF; // ADDR : unlock DFLL0CONF (*(volatile uint32_t*)(SCIF_BASE + OFFSET_DFLL0CONF)) = 0; } unsigned long getDFLLFrequency() { return _dfllFrequency; } // RC80M void enableRC80M() { // Configure RC80M (*(volatile uint32_t*)(SCIF_BASE + OFFSET_RC80MCR)) = 1 << RCFASTCFG_EN; // EN : enable the oscillator } void disableRC80M() { // Configure RC80M (*(volatile uint32_t*)(SCIF_BASE + OFFSET_RC80MCR)) = 0 << RCFASTCFG_EN; // EN : enable the oscillator } unsigned long getRC80MFrequency() { return _rc80mFrequency; } // Generic clocks void enableGenericClock(GCLKChannel channel, GCLKSource source, bool output, uint32_t divider) { // If this clock has an output, set the corresponding pin in peripheral mode if (output && channel <= GCLKChannel::GCLK3_CATB) { GPIO::enablePeripheral(PINS_GCLK[static_cast<int>(channel)]); _genericClockOutputEnabled[static_cast<int>(channel)] = true; } uint16_t d = 0; if (divider >= 2) { d = divider / 2 - 1; } // Configure clock (*(volatile uint32_t*)(SCIF_BASE + OFFSET_GCCTRL0 + static_cast<int>(channel) * 0x04)) = 1 << GCCTRL_CEN // CEN : enable the clock | (d > 0) << GCCTRL_DIVEN // DIVEN : enable the clock divider if desired | static_cast<int>(source) << GCCTRL_OSCSEL // OSCSEL : select desired clock | d << GCCTRL_DIV; // DIV : desired division factor } void disableGenericClock(GCLKChannel channel) { // Disable the output if it was enabled if (_genericClockOutputEnabled[static_cast<int>(channel)]) { GPIO::disablePeripheral(PINS_GCLK[static_cast<int>(channel)]); _genericClockOutputEnabled[static_cast<int>(channel)] = false; } // Disable the clock (*(volatile uint32_t*)(SCIF_BASE + OFFSET_GCCTRL0 + static_cast<int>(channel) * 0x04)) = 0; } void setPin(PinFunction function, int channel, GPIO::Pin pin) { switch (function) { case PinFunction::GCLK: PINS_GCLK[static_cast<int>(channel)] = pin; break; case PinFunction::GCLK_IN: PINS_GCLK_IN[static_cast<int>(channel)] = pin; break; } } }