* Fix pulseIn() on SAMD51 by writing it in plain C, so that the CM0+-specific pulse_asm won't need to be linked. The SAMD51 is fast enough that we can time pulses with micros() Tested with a bunch of pulse lengths from <1us to >1s * Implement a new delayMicroseconds() function for SAMD51 This version enables the "Debug Watchpoint and Trace" module (DWT) in startup.c and then uses the 32bit cycle counter that is part of DWT to count cycles indepenent of instruction timing. Tested for good accuracy with various values between 1 and 2000us.
538 lines
19 KiB
C
538 lines
19 KiB
C
/*
|
|
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 <stdio.h>
|
|
|
|
// 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 (7u)
|
|
//#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 Generic Clock Generator 3 as source for Generic Clock Gen 0 (DFLL48M reference)
|
|
*/
|
|
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(24u);
|
|
|
|
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_GCLK7_Val);
|
|
|
|
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(59); //120 Mhz
|
|
|
|
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_GCLK7_Val);
|
|
|
|
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(49); //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;
|
|
|
|
//*************** 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 */
|
|
}
|
|
|
|
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( (VARIANT_MCK + 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 48MHz.
|
|
*/
|
|
GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ) ; // Generic Clock Generator 0
|
|
|
|
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 ;
|
|
|
|
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
|
|
}
|
|
|