/* Copyright (c) 2015 Arduino LLC. All right reserved. SAMD51 support added by Adafruit - Copyright (c) 2018 Dean Miller for Adafruit Industries This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sam.h" #include "variant.h" #include // Constants for Clock generators #define GENERIC_CLOCK_GENERATOR_MAIN (0u) #if defined(__SAMD51__) #define GENERIC_CLOCK_GENERATOR_XOSC32K (3u) #define GENERIC_CLOCK_GENERATOR_48M (1u) #define GENERIC_CLOCK_GENERATOR_48M_SYNC GCLK_SYNCBUSY_GENCTRL1 #define GENERIC_CLOCK_GENERATOR_100M (2u) #define GENERIC_CLOCK_GENERATOR_100M_SYNC GCLK_SYNCBUSY_GENCTRL2 #define GENERIC_CLOCK_GENERATOR_12M (4u) #define GENERIC_CLOCK_GENERATOR_12M_SYNC GCLK_SYNCBUSY_GENCTRL4 //USE DPLL0 for 120MHZ #define MAIN_CLOCK_SOURCE GCLK_GENCTRL_SRC_DPLL0 #define GENERIC_CLOCK_GENERATOR_1M (5u) //#define CRYSTALLESS #else #define GENERIC_CLOCK_GENERATOR_XOSC32K (1u) #endif #define GENERIC_CLOCK_GENERATOR_OSC32K (1u) #define GENERIC_CLOCK_GENERATOR_OSCULP32K (2u) /* Initialized at reset for WDT */ #define GENERIC_CLOCK_GENERATOR_OSC8M (3u) // Constants for Clock multiplexers #define GENERIC_CLOCK_MULTIPLEXER_DFLL48M (0u) void SystemInit( void ) { //***************** SAMD51 ************************// #if defined(__SAMD51__) NVMCTRL->CTRLA.reg |= NVMCTRL_CTRLA_RWS(0); #ifndef CRYSTALLESS /* ---------------------------------------------------------------------------------------------- * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator) */ OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ENABLE | OSC32KCTRL_XOSC32K_EN32K | OSC32KCTRL_XOSC32K_EN32K | OSC32KCTRL_XOSC32K_CGM_XT | OSC32KCTRL_XOSC32K_XTALEN; while( (OSC32KCTRL->STATUS.reg & OSC32KCTRL_STATUS_XOSC32KRDY) == 0 ){ /* Wait for oscillator to be ready */ } #endif //CRYSTALLESS //software reset GCLK->CTRLA.bit.SWRST = 1; while ( GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_SWRST ){ /* wait for reset to complete */ } #ifndef CRYSTALLESS /* ---------------------------------------------------------------------------------------------- * 2) Put XOSC32K as source of Generic Clock Generator 3 */ GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_XOSC32K) | //generic clock gen 3 GCLK_GENCTRL_GENEN; #else /* ---------------------------------------------------------------------------------------------- * 2) Put OSCULP32K as source of Generic Clock Generator 3 */ GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN; //generic clock gen 3 #endif while ( GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL3 ){ /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 3) Put OSCULP32K as source for Generic Clock Generator 0 */ GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN; /* ---------------------------------------------------------------------------------------------- * 4) Enable DFLL48M clock */ while ( GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL0 ){ /* Wait for synchronization */ } /* DFLL Configuration in Open Loop mode */ OSCCTRL->DFLLCTRLA.reg = 0; //GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK3_Val); OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP( 0x1 ) | OSCCTRL_DFLLMUL_FSTEP( 0x1 ) | OSCCTRL_DFLLMUL_MUL( 0 ); while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLMUL ) { /* Wait for synchronization */ } OSCCTRL->DFLLCTRLB.reg = 0; while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLCTRLB ) { /* Wait for synchronization */ } OSCCTRL->DFLLCTRLA.reg |= OSCCTRL_DFLLCTRLA_ENABLE; while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_ENABLE ) { /* Wait for synchronization */ } OSCCTRL->DFLLVAL.reg = OSCCTRL->DFLLVAL.reg; while( OSCCTRL->DFLLSYNC.bit.DFLLVAL ); OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_WAITLOCK | OSCCTRL_DFLLCTRLB_CCDIS | OSCCTRL_DFLLCTRLB_USBCRM ; while ( !OSCCTRL->STATUS.bit.DFLLRDY ) { /* Wait for synchronization */ } GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(48u); while ( GCLK->SYNCBUSY.bit.GENCTRL5 ){ /* Wait for synchronization */ } /* ------------------------------------------------------------------------ * Set up the PLLs */ //PLL0 is 120MHz GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val); // This rounds to nearest full-MHz increment; not currently using frac OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR((F_CPU - 500000) / 1000000); while(OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.DPLLRATIO); //MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51 OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_GCLK | OSCCTRL_DPLLCTRLB_LBYPASS; OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE; while( OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY == 0 || OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK == 0 ); //PLL1 is 100MHz GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val); OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(99); //100 Mhz while(OSCCTRL->Dpll[1].DPLLSYNCBUSY.bit.DPLLRATIO); //MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51 OSCCTRL->Dpll[1].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_GCLK | OSCCTRL_DPLLCTRLB_LBYPASS; OSCCTRL->Dpll[1].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE; while( OSCCTRL->Dpll[1].DPLLSTATUS.bit.CLKRDY == 0 || OSCCTRL->Dpll[1].DPLLSTATUS.bit.LOCK == 0 ); /* ------------------------------------------------------------------------ * Set up the peripheral clocks */ //48MHZ CLOCK FOR USB AND STUFF GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_48M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_IDC | //GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN; while ( GCLK->SYNCBUSY.reg & GENERIC_CLOCK_GENERATOR_48M_SYNC) { /* Wait for synchronization */ } //100MHZ CLOCK FOR OTHER PERIPHERALS GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_100M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DPLL1_Val) | GCLK_GENCTRL_IDC | //GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN; while ( GCLK->SYNCBUSY.reg & GENERIC_CLOCK_GENERATOR_100M_SYNC) { /* Wait for synchronization */ } //12MHZ CLOCK FOR DAC GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_12M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_IDC | GCLK_GENCTRL_DIV(4) | //GCLK_GENCTRL_DIVSEL | //GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN; while ( GCLK->SYNCBUSY.reg & GENERIC_CLOCK_GENERATOR_12M_SYNC) { /* Wait for synchronization */ } /*--------------------------------------------------------------------- * Set up main clock */ GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_MAIN].reg = GCLK_GENCTRL_SRC(MAIN_CLOCK_SOURCE) | GCLK_GENCTRL_IDC | //GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN; while ( GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL0 ) { /* Wait for synchronization */ } MCLK->CPUDIV.reg = MCLK_CPUDIV_DIV_DIV1; /* Use the LDO regulator by default */ SUPC->VREG.bit.SEL = 0; /* If desired, enable cache! */ #if defined(ENABLE_CACHE) __disable_irq(); CMCC->CTRL.reg = 1; __enable_irq(); #endif /*--------------------------------------------------------------------- * Start up the "Debug Watchpoint and Trace" unit, so that we can use * it's 32bit cycle counter for timing. */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; /* ---------------------------------------------------------------------------------------------- * 5) Load AC factory calibration values */ uint32_t bias0 = (*((uint32_t *)AC_FUSES_BIAS0_ADDR) & AC_FUSES_BIAS0_Msk) >> AC_FUSES_BIAS0_Pos; AC->CALIB.reg = AC_CALIB_BIAS0(bias0); /* ---------------------------------------------------------------------------------------------- * 6) Load ADC factory calibration values */ // ADC0 Bias Calibration uint32_t biascomp = (*((uint32_t *)ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos; uint32_t biasr2r = (*((uint32_t *)ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos; uint32_t biasref = (*((uint32_t *)ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos; ADC0->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref) | ADC_CALIB_BIASR2R(biasr2r) | ADC_CALIB_BIASCOMP(biascomp); // ADC1 Bias Calibration biascomp = (*((uint32_t *)ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos; biasr2r = (*((uint32_t *)ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos; biasref = (*((uint32_t *)ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos; ADC1->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref) | ADC_CALIB_BIASR2R(biasr2r) | ADC_CALIB_BIASCOMP(biascomp); /* ---------------------------------------------------------------------------------------------- * 7) Load USB factory calibration values */ //USB Calibration uint32_t usbtransn = (*((uint32_t *)USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; uint32_t usbtransp = (*((uint32_t *)USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; uint32_t usbtrim = (*((uint32_t *)USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos; USB->DEVICE.PADCAL.reg = USB_PADCAL_TRIM(usbtrim) | USB_PADCAL_TRANSN(usbtransn) | USB_PADCAL_TRANSP(usbtransp); //*************** END SAMD51 *************************// #else //********************** SAMD21 *********************// /** * \brief SystemInit() configures the needed clocks and according Flash Read Wait States. * At reset: * - OSC8M clock source is enabled with a divider by 8 (1MHz). * - Generic Clock Generator 0 (GCLKMAIN) is using OSC8M as source. * We need to: * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator), will be used as DFLL48M reference. * 2) Put XOSC32K as source of Generic Clock Generator 1 * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) * 4) Enable DFLL48M clock * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. * 6) Modify PRESCaler value of OSCM to have 8MHz * 7) Put OSC8M as source for Generic Clock Generator 3 */ /* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */ NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val ; /* Turn on the digital interface clock */ PM->APBAMASK.reg |= PM_APBAMASK_GCLK ; #if defined(CRYSTALLESS) /* ---------------------------------------------------------------------------------------------- * 1) Enable OSC32K clock (Internal 32.768Hz oscillator) */ uint32_t calib = (*((uint32_t *) FUSES_OSC32K_CAL_ADDR) & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos; SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) | SYSCTRL_OSC32K_STARTUP( 0x6u ) | // cf table 15.10 of product datasheet in chapter 15.8.6 SYSCTRL_OSC32K_EN32K | SYSCTRL_OSC32K_ENABLE; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC32KRDY) == 0 ); // Wait for oscillator stabilization #else // has crystal /* ---------------------------------------------------------------------------------------------- * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator) */ SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */ SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K ; SYSCTRL->XOSC32K.bit.ENABLE = 1 ; /* separate call, as described in chapter 15.6.3 */ while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 ) { /* Wait for oscillator stabilization */ } #endif /* Software reset the module to ensure it is re-initialized correctly */ /* Note: Due to synchronization, there is a delay from writing CTRL.SWRST until the reset is complete. * CTRL.SWRST and STATUS.SYNCBUSY will both be cleared when the reset is complete, as described in chapter 13.8.1 */ GCLK->CTRL.reg = GCLK_CTRL_SWRST ; while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ) { /* Wait for reset to complete */ } /* ---------------------------------------------------------------------------------------------- * 2) Put XOSC32K as source of Generic Clock Generator 1 */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) ; // Generic Clock Generator 1 while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* Write Generic Clock Generator 1 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC32K ) | // Generic Clock Generator 1 #if defined(CRYSTALLESS) GCLK_GENCTRL_SRC_OSC32K | // Selected source is Internal 32KHz Oscillator #else GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator #endif // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_GENEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0 GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source GCLK_CLKCTRL_CLKEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 4) Enable DFLL48M clock */ /* DFLL Configuration in Closed Loop mode, cf product datasheet chapter 15.6.7.1 - Closed-Loop Operation */ /* Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905 */ SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* The DFLL48M clock is specified for 48 MHz, cf product datasheet chapter 37.13.3 - Digital Frequency Locked Loop (DFLL48M) Characteristics. Configuring other frequencies might work, but is not supported. */ #if F_CPU >= 32000000L #define F_DFLL F_CPU #define GCLK0_DIV -1 #elif F_CPU == 24000000L #define F_DFLL 48000000L #define GCLK0_DIV 0 #elif F_CPU == 16000000L #define F_DFLL 32000000L #define GCLK0_DIV 0 #elif F_CPU == 12000000L #define F_DFLL 48000000L #define GCLK0_DIV 1 #elif F_CPU == 8000000L #define F_DFLL 32000000L #define GCLK0_DIV 1 #elif F_CPU == 6000000L #define F_DFLL 48000000L #define GCLK0_DIV 2 #elif F_CPU == 4000000L #define F_DFLL 32000000L #define GCLK0_DIV 2 #elif F_CPU == 3000000L #define F_DFLL 48000000L #define GCLK0_DIV 3 #elif F_CPU == 1500000L #define F_DFLL 48000000L #define GCLK0_DIV 4 #else #error supported F_CPU values are 1500000L, 3000000L, 6000000L, 12000000L, 24000000L and 48000000L #endif SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value SYSCTRL_DFLLMUL_MUL( (F_DFLL + VARIANT_MAINOSC/2) / VARIANT_MAINOSC ) ; // External 32KHz is the reference while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } #if defined(CRYSTALLESS) #define NVM_SW_CALIB_DFLL48M_COARSE_VAL 58 // Turn on DFLL uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4) + (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32)) >> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32) ) & ((1 << 6) - 1); if (coarse == 0x3f) { coarse = 0x1f; } // TODO(tannewt): Load this value from memory we've written previously. There // isn't a value from the Atmel factory. uint32_t fine = 0x1ff; SYSCTRL->DFLLVAL.bit.COARSE = coarse; SYSCTRL->DFLLVAL.bit.FINE = fine; /* Write full configuration to DFLL control register */ SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 0x1f / 4 ) | // Coarse step is 31, half of the max value SYSCTRL_DFLLMUL_FSTEP( 10 ) | SYSCTRL_DFLLMUL_MUL( (48000) ) ; SYSCTRL->DFLLCTRL.reg = 0; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_USBCRM | /* USB correction */ SYSCTRL_DFLLCTRL_BPLCKC; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* Enable the DFLL */ SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ; #else // has crystal /* Write full configuration to DFLL control register */ SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */ SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_QLDIS ; /* Disable Quick lock */ while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* Enable the DFLL */ SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 || (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 ) { /* Wait for locks flags */ } #endif while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at F_CPU. */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0 (GCLK0_DIV >= 0? GCLK_GENDIV_DIV(GCLK0_DIV) : 0); // Divide by 2^(GCLK0_DIV + 1) while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* Write Generic Clock Generator 0 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0 GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_IDC | // Set 50/50 duty cycle GCLK_GENCTRL_GENEN | (GCLK0_DIV >= 0? GCLK_GENCTRL_DIVSEL : 0); while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 6) Modify PRESCaler value of OSC8M to have 8MHz */ SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_0_Val ; //CMSIS 4.5 changed the prescaler defines SYSCTRL->OSC8M.bit.ONDEMAND = 0 ; /* ---------------------------------------------------------------------------------------------- * 7) Put OSC8M as source for Generic Clock Generator 3 */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) ; // Generic Clock Generator 3 /* Write Generic Clock Generator 3 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) | // Generic Clock Generator 3 GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset) // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_GENEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* * Now that all system clocks are configured, we can set CPU and APBx BUS clocks. * There values are normally the one present after Reset. */ PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1 ; PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val ; PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val ; PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val ; SystemCoreClock=VARIANT_MCK ; /* ---------------------------------------------------------------------------------------------- * 8) Load ADC factory calibration values */ // ADC Bias Calibration uint32_t bias = (*((uint32_t *) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; // ADC Linearity bits 4:0 uint32_t linearity = (*((uint32_t *) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; // ADC Linearity bits 7:5 linearity |= ((*((uint32_t *) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity); /* * 9) Disable automatic NVM write operations */ NVMCTRL->CTRLB.bit.MANW = 1; #endif }