mbed library sources
Fork of mbed-src by
Diff: targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/system/clock/clock_samd21_r21/clock.c
- Revision:
- 613:bc40b8d2aec4
- Parent:
- 612:fba1c7dc54c0
- Child:
- 614:9d86c2ae5de0
--- a/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/system/clock/clock_samd21_r21/clock.c Tue Aug 18 15:00:09 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,958 +0,0 @@ -#include <compiler.h> -#include <clock.h> -#include <conf_clocks.h> -#include <system.h> - -#ifndef SYSCTRL_FUSES_OSC32K_ADDR -# define SYSCTRL_FUSES_OSC32K_ADDR SYSCTRL_FUSES_OSC32K_CAL_ADDR -# define SYSCTRL_FUSES_OSC32K_Pos SYSCTRL_FUSES_OSC32K_CAL_Pos -#endif - -/** - * \internal - * \brief DFLL-specific data container. - */ -struct _system_clock_dfll_config { - uint32_t control; - uint32_t val; - uint32_t mul; -}; - -/** - * \internal - * \brief DPLL-specific data container. - */ -struct _system_clock_dpll_config { - uint32_t frequency; -}; - - -/** - * \internal - * \brief XOSC-specific data container. - */ -struct _system_clock_xosc_config { - uint32_t frequency; -}; - -/** - * \internal - * \brief System clock module data container. - */ -struct _system_clock_module { - volatile struct _system_clock_dfll_config dfll; - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL - volatile struct _system_clock_dpll_config dpll; -#endif - - volatile struct _system_clock_xosc_config xosc; - volatile struct _system_clock_xosc_config xosc32k; -}; - -/** - * \internal - * \brief Internal module instance to cache configuration values. - */ -static struct _system_clock_module _system_clock_inst = { - .dfll = { - .control = 0, - .val = 0, - .mul = 0, - }, - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL - .dpll = { - .frequency = 0, - }, -#endif - .xosc = { - .frequency = 0, - }, - .xosc32k = { - .frequency = 0, - }, -}; - -/** - * \internal - * \brief Wait for sync to the DFLL control registers. - */ -static inline void _system_dfll_wait_for_sync(void) -{ - while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY)) { - /* Wait for DFLL sync */ - } -} - -/** - * \internal - * \brief Wait for sync to the OSC32K control registers. - */ -static inline void _system_osc32k_wait_for_sync(void) -{ - while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC32KRDY)) { - /* Wait for OSC32K sync */ - } -} - -static inline void _system_clock_source_dfll_set_config_errata_9905(void) -{ - - /* Disable ONDEMAND mode while writing configurations */ - SYSCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control & ~SYSCTRL_DFLLCTRL_ONDEMAND; - _system_dfll_wait_for_sync(); - - SYSCTRL->DFLLMUL.reg = _system_clock_inst.dfll.mul; - SYSCTRL->DFLLVAL.reg = _system_clock_inst.dfll.val; - - /* Write full configuration to DFLL control register */ - SYSCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control; -} - -/** - * \brief Retrieve the frequency of a clock source. - * - * Determines the current operating frequency of a given clock source. - * - * \param[in] clock_source Clock source to get the frequency - * - * \returns Frequency of the given clock source, in Hz. - */ -uint32_t system_clock_source_get_hz( - const enum system_clock_source clock_source) -{ - switch (clock_source) { - case SYSTEM_CLOCK_SOURCE_XOSC: - return _system_clock_inst.xosc.frequency; - - case SYSTEM_CLOCK_SOURCE_OSC8M: - return 8000000UL >> SYSCTRL->OSC8M.bit.PRESC; - - case SYSTEM_CLOCK_SOURCE_OSC32K: - return 32768UL; - - case SYSTEM_CLOCK_SOURCE_ULP32K: - return 32768UL; - - case SYSTEM_CLOCK_SOURCE_XOSC32K: - return _system_clock_inst.xosc32k.frequency; - - case SYSTEM_CLOCK_SOURCE_DFLL: - - /* Check if the DFLL has been configured */ - if (!(_system_clock_inst.dfll.control & SYSCTRL_DFLLCTRL_ENABLE)) - return 0; - - /* Make sure that the DFLL module is ready */ - _system_dfll_wait_for_sync(); - - /* Check if operating in closed loop mode */ - if (_system_clock_inst.dfll.control & SYSCTRL_DFLLCTRL_MODE) { - return system_gclk_chan_get_hz(SYSCTRL_GCLK_ID_DFLL48) * - (_system_clock_inst.dfll.mul & 0xffff); - } - - return 48000000UL; - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL - case SYSTEM_CLOCK_SOURCE_DPLL: - if (!(SYSCTRL->DPLLSTATUS.reg & SYSCTRL_DPLLSTATUS_ENABLE)) { - return 0; - } - - return _system_clock_inst.dpll.frequency; -#endif - - default: - return 0; - } -} - -/** - * \brief Configure the internal OSC8M oscillator clock source. - * - * Configures the 8MHz (nominal) internal RC oscillator with the given - * configuration settings. - * - * \param[in] config OSC8M configuration structure containing the new config - */ -void system_clock_source_osc8m_set_config( - struct system_clock_source_osc8m_config *const config) -{ - SYSCTRL_OSC8M_Type temp = SYSCTRL->OSC8M; - - /* Use temporary struct to reduce register access */ - temp.bit.PRESC = config->prescaler; - temp.bit.ONDEMAND = config->on_demand; - temp.bit.RUNSTDBY = config->run_in_standby; - - SYSCTRL->OSC8M = temp; -} - -/** - * \brief Configure the internal OSC32K oscillator clock source. - * - * Configures the 32KHz (nominal) internal RC oscillator with the given - * configuration settings. - * - * \param[in] config OSC32K configuration structure containing the new config - */ -void system_clock_source_osc32k_set_config( - struct system_clock_source_osc32k_config *const config) -{ - SYSCTRL_OSC32K_Type temp = SYSCTRL->OSC32K; - - /* Update settings via a temporary struct to reduce register access */ - temp.bit.EN1K = config->enable_1khz_output; - temp.bit.EN32K = config->enable_32khz_output; - temp.bit.STARTUP = config->startup_time; - temp.bit.ONDEMAND = config->on_demand; - temp.bit.RUNSTDBY = config->run_in_standby; - temp.bit.WRTLOCK = config->write_once; - - SYSCTRL->OSC32K = temp; -} - -/** - * \brief Configure the external oscillator clock source. - * - * Configures the external oscillator clock source with the given configuration - * settings. - * - * \param[in] config External oscillator configuration structure containing - * the new config - */ -void system_clock_source_xosc_set_config( - struct system_clock_source_xosc_config *const config) -{ - SYSCTRL_XOSC_Type temp = SYSCTRL->XOSC; - - temp.bit.STARTUP = config->startup_time; - - if (config->external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) { - temp.bit.XTALEN = 1; - } else { - temp.bit.XTALEN = 0; - } - - temp.bit.AMPGC = config->auto_gain_control; - - /* Set gain if automatic gain control is not selected */ - if (!config->auto_gain_control) { - if (config->frequency <= 2000000) { - temp.bit.GAIN = 0; - } else if (config->frequency <= 4000000) { - temp.bit.GAIN = 1; - } else if (config->frequency <= 8000000) { - temp.bit.GAIN = 2; - } else if (config->frequency <= 16000000) { - temp.bit.GAIN = 3; - } else if (config->frequency <= 30000000) { - temp.bit.GAIN = 4; - } - - } - - temp.bit.ONDEMAND = config->on_demand; - temp.bit.RUNSTDBY = config->run_in_standby; - - /* Store XOSC frequency for internal use */ - _system_clock_inst.xosc.frequency = config->frequency; - - SYSCTRL->XOSC = temp; -} - -/** - * \brief Configure the XOSC32K external 32KHz oscillator clock source. - * - * Configures the external 32KHz oscillator clock source with the given - * configuration settings. - * - * \param[in] config XOSC32K configuration structure containing the new config - */ -void system_clock_source_xosc32k_set_config( - struct system_clock_source_xosc32k_config *const config) -{ - SYSCTRL_XOSC32K_Type temp = SYSCTRL->XOSC32K; - - temp.bit.STARTUP = config->startup_time; - - if (config->external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) { - temp.bit.XTALEN = 1; - } else { - temp.bit.XTALEN = 0; - } - - temp.bit.AAMPEN = config->auto_gain_control; - temp.bit.EN1K = config->enable_1khz_output; - temp.bit.EN32K = config->enable_32khz_output; - - temp.bit.ONDEMAND = config->on_demand; - temp.bit.RUNSTDBY = config->run_in_standby; - temp.bit.WRTLOCK = config->write_once; - - /* Cache the new frequency in case the user needs to check the current - * operating frequency later */ - _system_clock_inst.xosc32k.frequency = config->frequency; - - SYSCTRL->XOSC32K = temp; -} - -/** - * \brief Configure the DFLL clock source. - * - * Configures the Digital Frequency Locked Loop clock source with the given - * configuration settings. - * - * \note The DFLL will be running when this function returns, as the DFLL module - * needs to be enabled in order to perform the module configuration. - * - * \param[in] config DFLL configuration structure containing the new config - */ -void system_clock_source_dfll_set_config( - struct system_clock_source_dfll_config *const config) -{ - _system_clock_inst.dfll.val = - SYSCTRL_DFLLVAL_COARSE(config->coarse_value) | - SYSCTRL_DFLLVAL_FINE(config->fine_value); - - _system_clock_inst.dfll.control = - (uint32_t)config->wakeup_lock | - (uint32_t)config->stable_tracking | - (uint32_t)config->quick_lock | - (uint32_t)config->chill_cycle | - ((uint32_t)config->on_demand << SYSCTRL_DFLLCTRL_ONDEMAND_Pos); - - if (config->loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { - - _system_clock_inst.dfll.mul = - SYSCTRL_DFLLMUL_CSTEP(config->coarse_max_step) | - SYSCTRL_DFLLMUL_FSTEP(config->fine_max_step) | - SYSCTRL_DFLLMUL_MUL(config->multiply_factor); - - /* Enable the closed loop mode */ - _system_clock_inst.dfll.control |= config->loop_mode; - } - if (config->loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) { - - _system_clock_inst.dfll.mul = - SYSCTRL_DFLLMUL_MUL(config->multiply_factor); - - /* Enable the USB recovery mode */ - _system_clock_inst.dfll.control |= config->loop_mode | - SYSCTRL_DFLLCTRL_BPLCKC; - } -} - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL -/** - * \brief Configure the DPLL clock source. - * - * Configures the Digital Phase-Locked Loop clock source with the given - * configuration settings. - * - * \note The DPLL will be running when this function returns, as the DPLL module - * needs to be enabled in order to perform the module configuration. - * - * \param[in] config DPLL configuration structure containing the new config - */ -void system_clock_source_dpll_set_config( - struct system_clock_source_dpll_config *const config) -{ - - uint32_t tmpldr; - uint8_t tmpldrfrac; - uint32_t refclk; - - refclk = config->reference_frequency; - - /* Only reference clock REF1 can be divided */ - if (config->reference_clock == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF1) { - refclk = refclk / config->reference_divider; - } - - /* Calculate LDRFRAC and LDR */ - tmpldr = (config->output_frequency << 4) / refclk; - tmpldrfrac = tmpldr & 0x0f; - tmpldr = (tmpldr >> 4) - 1; - - SYSCTRL->DPLLCTRLA.reg = - ((uint32_t)config->on_demand << SYSCTRL_DPLLCTRLA_ONDEMAND_Pos) | - ((uint32_t)config->run_in_standby << SYSCTRL_DPLLCTRLA_RUNSTDBY_Pos); - - SYSCTRL->DPLLRATIO.reg = - SYSCTRL_DPLLRATIO_LDRFRAC(tmpldrfrac) | - SYSCTRL_DPLLRATIO_LDR(tmpldr); - - SYSCTRL->DPLLCTRLB.reg = - SYSCTRL_DPLLCTRLB_DIV(config->reference_divider) | - ((uint32_t)config->lock_bypass << SYSCTRL_DPLLCTRLB_LBYPASS_Pos) | - SYSCTRL_DPLLCTRLB_LTIME(config->lock_time) | - SYSCTRL_DPLLCTRLB_REFCLK(config->reference_clock) | - ((uint32_t)config->wake_up_fast << SYSCTRL_DPLLCTRLB_WUF_Pos) | - ((uint32_t)config->low_power_enable << SYSCTRL_DPLLCTRLB_LPEN_Pos) | - SYSCTRL_DPLLCTRLB_FILTER(config->filter); - - /* - * Fck = Fckrx * (LDR + 1 + LDRFRAC / 16) - */ - _system_clock_inst.dpll.frequency = - (config->reference_frequency * - (((tmpldr + 1) << 4) + tmpldrfrac) - ) >> 4; -} -#endif - -/** - * \brief Writes the calibration values for a given oscillator clock source. - * - * Writes an oscillator calibration value to the given oscillator control - * registers. The acceptable ranges are: - * - * For OSC32K: - * - 7 bits (max value 128) - * For OSC8MHZ: - * - 8 bits (Max value 255) - * For OSCULP: - * - 5 bits (Max value 32) - * - * \note The frequency range parameter applies only when configuring the 8MHz - * oscillator and will be ignored for the other oscillators. - * - * \param[in] clock_source Clock source to calibrate - * \param[in] calibration_value Calibration value to write - * \param[in] freq_range Frequency range (8MHz oscillator only) - * - * \retval STATUS_OK The calibration value was written - * successfully. - * \retval STATUS_ERR_INVALID_ARG The setting is not valid for selected clock - * source. - */ -enum status_code system_clock_source_write_calibration( - const enum system_clock_source clock_source, - const uint16_t calibration_value, - const uint8_t freq_range) -{ - switch (clock_source) { - case SYSTEM_CLOCK_SOURCE_OSC8M: - - if (calibration_value > 0xfff || freq_range > 4) { - return STATUS_ERR_INVALID_ARG; - } - - SYSCTRL->OSC8M.bit.CALIB = calibration_value; - SYSCTRL->OSC8M.bit.FRANGE = freq_range; - break; - - case SYSTEM_CLOCK_SOURCE_OSC32K: - - if (calibration_value > 128) { - return STATUS_ERR_INVALID_ARG; - } - - _system_osc32k_wait_for_sync(); - SYSCTRL->OSC32K.bit.CALIB = calibration_value; - break; - - case SYSTEM_CLOCK_SOURCE_ULP32K: - - if (calibration_value > 32) { - return STATUS_ERR_INVALID_ARG; - } - - SYSCTRL->OSCULP32K.bit.CALIB = calibration_value; - break; - - default: - Assert(false); - return STATUS_ERR_INVALID_ARG; - break; - } - - return STATUS_OK; -} - -/** - * \brief Enables a clock source. - * - * Enables a clock source which has been previously configured. - * - * \param[in] clock_source Clock source to enable - * - * \retval STATUS_OK Clock source was enabled successfully and - * is ready - * \retval STATUS_ERR_INVALID_ARG The clock source is not available on this - * device - */ -enum status_code system_clock_source_enable( - const enum system_clock_source clock_source) -{ - switch (clock_source) { - case SYSTEM_CLOCK_SOURCE_OSC8M: - SYSCTRL->OSC8M.reg |= SYSCTRL_OSC8M_ENABLE; - return STATUS_OK; - - case SYSTEM_CLOCK_SOURCE_OSC32K: - SYSCTRL->OSC32K.reg |= SYSCTRL_OSC32K_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_XOSC: - SYSCTRL->XOSC.reg |= SYSCTRL_XOSC_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_XOSC32K: - SYSCTRL->XOSC32K.reg |= SYSCTRL_XOSC32K_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_DFLL: - _system_clock_inst.dfll.control |= SYSCTRL_DFLLCTRL_ENABLE; - _system_clock_source_dfll_set_config_errata_9905(); - break; - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL - case SYSTEM_CLOCK_SOURCE_DPLL: - SYSCTRL->DPLLCTRLA.reg |= SYSCTRL_DPLLCTRLA_ENABLE; - break; -#endif - - case SYSTEM_CLOCK_SOURCE_ULP32K: - /* Always enabled */ - return STATUS_OK; - - default: - Assert(false); - return STATUS_ERR_INVALID_ARG; - } - - return STATUS_OK; - } - - /** - * \brief Disables a clock source. - * - * Disables a clock source that was previously enabled. - * - * \param[in] clock_source Clock source to disable - * - * \retval STATUS_OK Clock source was disabled successfully - * \retval STATUS_ERR_INVALID_ARG An invalid or unavailable clock source was - * given - */ - enum status_code system_clock_source_disable( - const enum system_clock_source clock_source) -{ - switch (clock_source) { - case SYSTEM_CLOCK_SOURCE_OSC8M: - SYSCTRL->OSC8M.reg &= ~SYSCTRL_OSC8M_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_OSC32K: - SYSCTRL->OSC32K.reg &= ~SYSCTRL_OSC32K_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_XOSC: - SYSCTRL->XOSC.reg &= ~SYSCTRL_XOSC_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_XOSC32K: - SYSCTRL->XOSC32K.reg &= ~SYSCTRL_XOSC32K_ENABLE; - break; - - case SYSTEM_CLOCK_SOURCE_DFLL: - _system_clock_inst.dfll.control &= ~SYSCTRL_DFLLCTRL_ENABLE; - SYSCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control; - break; - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL - case SYSTEM_CLOCK_SOURCE_DPLL: - SYSCTRL->DPLLCTRLA.reg &= ~SYSCTRL_DPLLCTRLA_ENABLE; - break; -#endif - - case SYSTEM_CLOCK_SOURCE_ULP32K: - /* Not possible to disable */ - - default: - Assert(false); - return STATUS_ERR_INVALID_ARG; - - } - - return STATUS_OK; - } - - /** - * \brief Checks if a clock source is ready. - * - * Checks if a given clock source is ready to be used. - * - * \param[in] clock_source Clock source to check if ready - * - * \returns Ready state of the given clock source. - * - * \retval true Clock source is enabled and ready - * \retval false Clock source is disabled or not yet ready - */ - bool system_clock_source_is_ready( - const enum system_clock_source clock_source) -{ - uint32_t mask = 0; - - switch (clock_source) { - case SYSTEM_CLOCK_SOURCE_OSC8M: - mask = SYSCTRL_PCLKSR_OSC8MRDY; - break; - - case SYSTEM_CLOCK_SOURCE_OSC32K: - mask = SYSCTRL_PCLKSR_OSC32KRDY; - break; - - case SYSTEM_CLOCK_SOURCE_XOSC: - mask = SYSCTRL_PCLKSR_XOSCRDY; - break; - - case SYSTEM_CLOCK_SOURCE_XOSC32K: - mask = SYSCTRL_PCLKSR_XOSC32KRDY; - break; - - case SYSTEM_CLOCK_SOURCE_DFLL: - if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { - mask = (SYSCTRL_PCLKSR_DFLLRDY | - SYSCTRL_PCLKSR_DFLLLCKF | SYSCTRL_PCLKSR_DFLLLCKC); - } else { - mask = SYSCTRL_PCLKSR_DFLLRDY; - } - break; - -#ifdef FEATURE_SYSTEM_CLOCK_DPLL - case SYSTEM_CLOCK_SOURCE_DPLL: - return ((SYSCTRL->DPLLSTATUS.reg & - (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK)) == - (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK)); -#endif - - case SYSTEM_CLOCK_SOURCE_ULP32K: - /* Not possible to disable */ - return true; - - default: - return false; - } - - return ((SYSCTRL->PCLKSR.reg & mask) == mask); -} - -/* Include some checks for conf_clocks.h validation */ -#include "clock_config_check.h" - -#if !defined(__DOXYGEN__) -/** \internal - * - * Configures a Generic Clock Generator with the configuration from \c conf_clocks.h. - */ -# define _CONF_CLOCK_GCLK_CONFIG(n, unused) \ - if (CONF_CLOCK_GCLK_##n##_ENABLE == true) { \ - struct system_gclk_gen_config gclk_conf; \ - system_gclk_gen_get_config_defaults(&gclk_conf); \ - gclk_conf.source_clock = CONF_CLOCK_GCLK_##n##_CLOCK_SOURCE; \ - gclk_conf.division_factor = CONF_CLOCK_GCLK_##n##_PRESCALER; \ - gclk_conf.run_in_standby = CONF_CLOCK_GCLK_##n##_RUN_IN_STANDBY; \ - gclk_conf.output_enable = CONF_CLOCK_GCLK_##n##_OUTPUT_ENABLE; \ - system_gclk_gen_set_config(GCLK_GENERATOR_##n, &gclk_conf); \ - system_gclk_gen_enable(GCLK_GENERATOR_##n); \ - } - -/** \internal - * - * Configures a Generic Clock Generator with the configuration from \c conf_clocks.h, - * provided that it is not the main Generic Clock Generator channel. - */ -# define _CONF_CLOCK_GCLK_CONFIG_NONMAIN(n, unused) \ - if (n > 0) { _CONF_CLOCK_GCLK_CONFIG(n, unused); } -#endif - -/** \internal - * - * Switch all peripheral clock to a not enabled general clock - * to save power. - */ -static void _switch_peripheral_gclk(void) -{ - uint32_t gclk_id; - struct system_gclk_chan_config gclk_conf; - -#if CONF_CLOCK_GCLK_1_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_1; -#elif CONF_CLOCK_GCLK_2_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_2; -#elif CONF_CLOCK_GCLK_3_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_3; -#elif CONF_CLOCK_GCLK_4_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_4; -#elif CONF_CLOCK_GCLK_5_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_5; -#elif CONF_CLOCK_GCLK_6_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_6; -#elif CONF_CLOCK_GCLK_7_ENABLE == false - gclk_conf.source_generator = GCLK_GENERATOR_7; -#else - gclk_conf.source_generator = GCLK_GENERATOR_7; -#endif - - for (gclk_id = 0; gclk_id < GCLK_NUM; gclk_id++) { - system_gclk_chan_set_config(gclk_id, &gclk_conf); - } -} - -/** - * \brief Initialize clock system based on the configuration in conf_clocks.h. - * - * This function will apply the settings in conf_clocks.h when run from the user - * application. All clock sources and GCLK generators are running when this function - * returns. - * - * \note OSC8M is always enabled and if user selects other clocks for GCLK generators, - * the OSC8M default enable can be disabled after system_clock_init. Make sure the - * clock switch successfully before disabling OSC8M. - */ -void system_clock_init(void) -{ - /* Various bits in the INTFLAG register can be set to one at startup. - This will ensure that these bits are cleared */ - SYSCTRL->INTFLAG.reg = SYSCTRL_INTFLAG_BOD33RDY | SYSCTRL_INTFLAG_BOD33DET | - SYSCTRL_INTFLAG_DFLLRDY; - - system_flash_set_waitstates(CONF_CLOCK_FLASH_WAIT_STATES); - - /* Switch all peripheral clock to a not enabled general clock to save power. */ - _switch_peripheral_gclk(); - - /* XOSC */ -#if CONF_CLOCK_XOSC_ENABLE == true - struct system_clock_source_xosc_config xosc_conf; - system_clock_source_xosc_get_config_defaults(&xosc_conf); - - xosc_conf.external_clock = CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL; - xosc_conf.startup_time = CONF_CLOCK_XOSC_STARTUP_TIME; - xosc_conf.auto_gain_control = CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL; - xosc_conf.frequency = CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY; - xosc_conf.on_demand = CONF_CLOCK_XOSC_ON_DEMAND; - xosc_conf.run_in_standby = CONF_CLOCK_XOSC_RUN_IN_STANDBY; - - system_clock_source_xosc_set_config(&xosc_conf); - system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC); -#endif - - - /* XOSC32K */ -#if CONF_CLOCK_XOSC32K_ENABLE == true - struct system_clock_source_xosc32k_config xosc32k_conf; - system_clock_source_xosc32k_get_config_defaults(&xosc32k_conf); - - xosc32k_conf.frequency = 32768UL; - xosc32k_conf.external_clock = CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL; - xosc32k_conf.startup_time = CONF_CLOCK_XOSC32K_STARTUP_TIME; - xosc32k_conf.auto_gain_control = CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL; - xosc32k_conf.enable_1khz_output = CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT; - xosc32k_conf.enable_32khz_output = CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT; - xosc32k_conf.on_demand = false; - xosc32k_conf.run_in_standby = CONF_CLOCK_XOSC32K_RUN_IN_STANDBY; - - system_clock_source_xosc32k_set_config(&xosc32k_conf); - system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC32K); - while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_XOSC32K)); - if (CONF_CLOCK_XOSC32K_ON_DEMAND) { - SYSCTRL->XOSC32K.bit.ONDEMAND = 1; - } -#endif - - - /* OSCK32K */ -#if CONF_CLOCK_OSC32K_ENABLE == true - SYSCTRL->OSC32K.bit.CALIB = - (*(uint32_t *)SYSCTRL_FUSES_OSC32K_ADDR >> SYSCTRL_FUSES_OSC32K_Pos); - - struct system_clock_source_osc32k_config osc32k_conf; - system_clock_source_osc32k_get_config_defaults(&osc32k_conf); - - osc32k_conf.startup_time = CONF_CLOCK_OSC32K_STARTUP_TIME; - osc32k_conf.enable_1khz_output = CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT; - osc32k_conf.enable_32khz_output = CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT; - osc32k_conf.on_demand = CONF_CLOCK_OSC32K_ON_DEMAND; - osc32k_conf.run_in_standby = CONF_CLOCK_OSC32K_RUN_IN_STANDBY; - - system_clock_source_osc32k_set_config(&osc32k_conf); - system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC32K); -#endif - - - /* DFLL Config (Open and Closed Loop) */ -#if CONF_CLOCK_DFLL_ENABLE == true - struct system_clock_source_dfll_config dfll_conf; - system_clock_source_dfll_get_config_defaults(&dfll_conf); - - dfll_conf.loop_mode = CONF_CLOCK_DFLL_LOOP_MODE; - dfll_conf.on_demand = false; - - if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN) { - dfll_conf.coarse_value = CONF_CLOCK_DFLL_COARSE_VALUE; - dfll_conf.fine_value = CONF_CLOCK_DFLL_FINE_VALUE; - } - -# if CONF_CLOCK_DFLL_QUICK_LOCK == true - dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE; -# else - dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE; -# endif - -# if CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK == true - dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK; -# else - dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK; -# endif - -# if CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP == true - dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP; -# else - dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_LOSE; -# endif - -# if CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE == true - dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE; -# else - dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE; -# endif - - if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { - dfll_conf.multiply_factor = CONF_CLOCK_DFLL_MULTIPLY_FACTOR; - } - - dfll_conf.coarse_max_step = CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE; - dfll_conf.fine_max_step = CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE; - - if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) { -#define NVM_DFLL_COARSE_POS 58 -#define NVM_DFLL_COARSE_SIZE 6 -#define NVM_DFLL_FINE_POS 64 -#define NVM_DFLL_FINE_SIZE 10 - uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_DFLL_COARSE_POS / 32)) - >> (NVM_DFLL_COARSE_POS % 32)) - & ((1 << NVM_DFLL_COARSE_SIZE) - 1); - if (coarse == 0x3f) { - coarse = 0x1f; - } - uint32_t fine =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_DFLL_FINE_POS / 32)) - >> (NVM_DFLL_FINE_POS % 32)) - & ((1 << NVM_DFLL_FINE_SIZE) - 1); - if (fine == 0x3ff) { - fine = 0x1ff; - } - dfll_conf.coarse_value = coarse; - dfll_conf.fine_value = fine; - - dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE; - dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK; - dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP; - dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE; - - dfll_conf.multiply_factor = 48000; - } - - system_clock_source_dfll_set_config(&dfll_conf); -#endif - - - /* OSC8M */ - struct system_clock_source_osc8m_config osc8m_conf; - system_clock_source_osc8m_get_config_defaults(&osc8m_conf); - - osc8m_conf.prescaler = CONF_CLOCK_OSC8M_PRESCALER; - osc8m_conf.on_demand = CONF_CLOCK_OSC8M_ON_DEMAND; - osc8m_conf.run_in_standby = CONF_CLOCK_OSC8M_RUN_IN_STANDBY; - - system_clock_source_osc8m_set_config(&osc8m_conf); - system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC8M); - - - /* GCLK */ -#if CONF_CLOCK_CONFIGURE_GCLK == true - system_gclk_init(); - - /* Configure all GCLK generators except for the main generator, which - * is configured later after all other clock systems are set up */ - MREPEAT(8, _CONF_CLOCK_GCLK_CONFIG_NONMAIN, ~); - -# if CONF_CLOCK_DFLL_ENABLE == true - /* Enable DFLL reference clock if in closed loop mode */ - if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { - struct system_gclk_chan_config dfll_gclk_chan_conf; - - system_gclk_chan_get_config_defaults(&dfll_gclk_chan_conf); - dfll_gclk_chan_conf.source_generator = CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR; - system_gclk_chan_set_config(SYSCTRL_GCLK_ID_DFLL48, &dfll_gclk_chan_conf); - system_gclk_chan_enable(SYSCTRL_GCLK_ID_DFLL48); - } -# endif -#endif - - - /* DFLL Enable (Open and Closed Loop) */ -#if CONF_CLOCK_DFLL_ENABLE == true - system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL); - while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL)); - if (CONF_CLOCK_DFLL_ON_DEMAND) { - SYSCTRL->DFLLCTRL.bit.ONDEMAND = 1; - } -#endif - - /* DPLL */ -#ifdef FEATURE_SYSTEM_CLOCK_DPLL -# if (CONF_CLOCK_DPLL_ENABLE == true) - - /* Enable DPLL reference clock */ - if (CONF_CLOCK_DPLL_REFERENCE_CLOCK == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF0) { - /* XOSC32K should have been enabled for DPLL_REF0 */ - Assert(CONF_CLOCK_XOSC32K_ENABLE); - } - - struct system_clock_source_dpll_config dpll_config; - system_clock_source_dpll_get_config_defaults(&dpll_config); - - dpll_config.on_demand = false; - dpll_config.run_in_standby = CONF_CLOCK_DPLL_RUN_IN_STANDBY; - dpll_config.lock_bypass = CONF_CLOCK_DPLL_LOCK_BYPASS; - dpll_config.wake_up_fast = CONF_CLOCK_DPLL_WAKE_UP_FAST; - dpll_config.low_power_enable = CONF_CLOCK_DPLL_LOW_POWER_ENABLE; - - dpll_config.filter = CONF_CLOCK_DPLL_FILTER; - - dpll_config.reference_clock = CONF_CLOCK_DPLL_REFERENCE_CLOCK; - dpll_config.reference_frequency = CONF_CLOCK_DPLL_REFERENCE_FREQUENCY; - dpll_config.reference_divider = CONF_CLOCK_DPLL_REFEREMCE_DIVIDER; - dpll_config.output_frequency = CONF_CLOCK_DPLL_OUTPUT_FREQUENCY; - - system_clock_source_dpll_set_config(&dpll_config); - system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DPLL); - while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL)); - if (CONF_CLOCK_DPLL_ON_DEMAND) { - SYSCTRL->DPLLCTRLA.bit.ONDEMAND = 1; - } - -# endif -#endif - - /* CPU and BUS clocks */ - system_cpu_clock_set_divider(CONF_CLOCK_CPU_DIVIDER); - - system_apb_clock_set_divider(SYSTEM_CLOCK_APB_APBA, CONF_CLOCK_APBA_DIVIDER); - system_apb_clock_set_divider(SYSTEM_CLOCK_APB_APBB, CONF_CLOCK_APBB_DIVIDER); - - /* GCLK 0 */ -#if CONF_CLOCK_CONFIGURE_GCLK == true - /* Configure the main GCLK last as it might depend on other generators */ - _CONF_CLOCK_GCLK_CONFIG(0, ~); -#endif -}