/** * @brief Configure clock sources and the cpu frequency */ static void clk_init(void) { /* enable clocks for the power, sysctrl and gclk modules */ PM->APBAMASK.reg = (PM_APBAMASK_PM | PM_APBAMASK_SYSCTRL | PM_APBAMASK_GCLK); /* adjust NVM wait states, see table 42.30 (p. 1070) in the datasheet */ #if (CLOCK_CORECLOCK > 24000000) PM->APBAMASK.reg |= PM_AHBMASK_NVMCTRL; NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(1); PM->APBAMASK.reg &= ~PM_AHBMASK_NVMCTRL; #endif /* configure internal 8MHz oscillator to run without prescaler */ SYSCTRL->OSC8M.bit.PRESC = 0; SYSCTRL->OSC8M.bit.ONDEMAND = 1; SYSCTRL->OSC8M.bit.RUNSTDBY = 0; SYSCTRL->OSC8M.bit.ENABLE = 1; while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {} #if CLOCK_USE_PLL /* reset the GCLK module so it is in a known state */ GCLK->CTRL.reg = GCLK_CTRL_SWRST; while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} /* setup generic clock 1 to feed DPLL with 1MHz */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(8) | GCLK_GENDIV_ID(1)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_ID(1)); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN(1) | GCLK_CLKCTRL_ID(1) | GCLK_CLKCTRL_CLKEN); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} /* enable PLL */ SYSCTRL->DPLLRATIO.reg = (SYSCTRL_DPLLRATIO_LDR(CLOCK_PLL_MUL)); SYSCTRL->DPLLCTRLB.reg = (SYSCTRL_DPLLCTRLB_REFCLK_GCLK); SYSCTRL->DPLLCTRLA.reg = (SYSCTRL_DPLLCTRLA_ENABLE); while(!(SYSCTRL->DPLLSTATUS.reg & (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK))) {} /* select the PLL as source for clock generator 0 (CPU core clock) */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_PLL_DIV) | GCLK_GENDIV_ID(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_FDPLL | GCLK_GENCTRL_ID(0)); #else /* do not use PLL, use internal 8MHz oscillator directly */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_DIV) | GCLK_GENDIV_ID(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_ID(0)); #endif /* make sure we synchronize clock generator 0 before we go on */ while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} /* Setup Clock generator 2 with divider 1 (32.768kHz) */ GCLK->GENDIV.reg = (GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_SRC_OSCULP32K); while (GCLK->STATUS.bit.SYNCBUSY) {} /* redirect all peripherals to a disabled clock generator (7) by default */ for (int i = 0x3; i <= 0x22; i++) { GCLK->CLKCTRL.reg = ( GCLK_CLKCTRL_ID(i) | GCLK_CLKCTRL_GEN_GCLK7 ); while (GCLK->STATUS.bit.SYNCBUSY) {} } }
void _sysctrl_init_referenced_generators(void) { void *hw = (void *)SYSCTRL; #if CONF_DFLL_CONFIG == 1 # if CONF_DFLL_USBCRM != 1 && CONF_DFLL_MODE != CONF_DFLL_OPEN_LOOP_MODE hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(0) | GCLK_CLKCTRL_GEN(CONF_DFLL_GCLK) | ( 1 << GCLK_CLKCTRL_CLKEN_Pos )); # endif hri_sysctrl_write_DFLLCTRL_reg(hw, SYSCTRL_DFLLCTRL_ENABLE); while(!hri_sysctrl_get_PCLKSR_DFLLRDY_bit(hw)) {; } hri_sysctrl_write_DFLLMUL_reg(hw, SYSCTRL_DFLLMUL_CSTEP( CONF_DFLL_CSTEP) | SYSCTRL_DFLLMUL_FSTEP(CONF_DFLL_FSTEP) | SYSCTRL_DFLLMUL_MUL(CONF_DFLL_MUL)); hri_sysctrl_write_DFLLVAL_reg(hw, CONF_DFLLVAL); hri_sysctrl_dfllctrl_reg_t tmp = ( CONF_DFLL_WAITLOCK << SYSCTRL_DFLLCTRL_WAITLOCK_Pos ) | ( CONF_DFLL_BPLCKC << SYSCTRL_DFLLCTRL_BPLCKC_Pos ) | ( CONF_DFLL_QLDIS << SYSCTRL_DFLLCTRL_QLDIS_Pos ) | ( CONF_DFLL_CCDIS << SYSCTRL_DFLLCTRL_CCDIS_Pos ) | ( CONF_DFLL_RUNSTDBY << SYSCTRL_DFLLCTRL_RUNSTDBY_Pos ) | ( CONF_DFLL_USBCRM << SYSCTRL_DFLLCTRL_USBCRM_Pos ) | ( CONF_DFLL_LLAW << SYSCTRL_DFLLCTRL_LLAW_Pos ) | ( CONF_DFLL_STABLE << SYSCTRL_DFLLCTRL_STABLE_Pos ) | ( CONF_DFLL_MODE << SYSCTRL_DFLLCTRL_MODE_Pos ) | ( CONF_DFLL_ENABLE << SYSCTRL_DFLLCTRL_ENABLE_Pos ); hri_sysctrl_write_DFLLCTRL_reg(hw, tmp); #endif #if CONF_DPLL_CONFIG == 1 # if CONF_DPLL_REFCLK == SYSCTRL_DPLLCTRLB_REFCLK_GCLK_Val hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(1) | GCLK_CLKCTRL_GEN(CONF_DPLL_GCLK) | ( 1 << GCLK_CLKCTRL_CLKEN_Pos )); # endif hri_sysctrl_write_DPLLCTRLA_reg(hw, ( CONF_DPLL_RUNSTDBY << SYSCTRL_DPLLCTRLA_RUNSTDBY_Pos ) | ( CONF_DPLL_ENABLE << SYSCTRL_DPLLCTRLA_ENABLE_Pos )); hri_sysctrl_write_DPLLRATIO_reg(hw, SYSCTRL_DPLLRATIO_LDRFRAC(CONF_DPLL_LDRFRAC) | SYSCTRL_DPLLRATIO_LDR(CONF_DPLL_LDR)); hri_sysctrl_write_DPLLCTRLB_reg(hw, SYSCTRL_DPLLCTRLB_DIV( CONF_DPLL_DIV) | ( CONF_DPLL_LBYPASS << SYSCTRL_DPLLCTRLB_LBYPASS_Pos ) | SYSCTRL_DPLLCTRLB_LTIME(CONF_DPLL_LTIME) | SYSCTRL_DPLLCTRLB_REFCLK(CONF_DPLL_REFCLK) | ( CONF_DPLL_WUF << SYSCTRL_DPLLCTRLB_WUF_Pos ) | ( CONF_DPLL_LPEN << SYSCTRL_DPLLCTRLB_LPEN_Pos ) | SYSCTRL_DPLLCTRLB_FILTER(CONF_DPLL_FILTER)); #endif #if CONF_DFLL_CONFIG == 1 # if CONF_DFLL_ENABLE == 1 if (hri_sysctrl_get_DFLLCTRL_MODE_bit(hw)) { # if CONF_DFLL_USBCRM == 0 hri_sysctrl_pclksr_reg_t status_mask = SYSCTRL_PCLKSR_DFLLRDY | SYSCTRL_PCLKSR_DFLLLCKF | SYSCTRL_PCLKSR_DFLLLCKC; # else hri_sysctrl_pclksr_reg_t status_mask = SYSCTRL_PCLKSR_DFLLRDY; # endif while(hri_sysctrl_get_PCLKSR_reg(hw, status_mask) != status_mask) {; } } else { while(!hri_sysctrl_get_PCLKSR_DFLLRDY_bit(hw)) {; } } # endif # if CONF_DFLL_ONDEMAND == 1 hri_sysctrl_set_DFLLCTRL_ONDEMAND_bit(hw); # endif #endif #if CONF_DPLL_CONFIG == 1 # if CONF_DPLL_ENABLE == 1 while (!( hri_sysctrl_get_DPLLSTATUS_ENABLE_bit(hw) || hri_sysctrl_get_DPLLSTATUS_LOCK_bit(hw) || hri_sysctrl_get_DPLLSTATUS_CLKRDY_bit(hw))) {; } # endif # if CONF_DPLL_ONDEMAND == 1 hri_sysctrl_set_DPLLCTRLA_ONDEMAND_bit(hw); # endif #endif #if CONF_DFLL_CONFIG == 1 while(hri_gclk_get_STATUS_SYNCBUSY_bit(GCLK)) {; } #endif #if CONF_OSC32K_CONFIG == 0 || CONF_OSC32K_ENABLE == 0 /* Disable after all possible configurations needs sync written. */ hri_sysctrl_clear_OSC32K_ENABLE_bit(hw); #endif (void)hw; }