/** * \file * * \brief DFLL management * * Copyright (c) 2010-2015 Atmel Corporation. All rights reserved. * * \asf_license_start * * \page License * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * * 4. This software may only be redistributed and used in connection with an * Atmel microcontroller product. * * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * \asf_license_stop * */ /* * Support and FAQ: visit Atmel Support */ #ifndef CLK_DFLL_H_INCLUDED #define CLK_DFLL_H_INCLUDED #include #include "conf_clock.h" #if UC3L # include "uc3l/dfll.h" #elif SAM4L # include "sam4l/dfll.h" #else # error Unsupported chip type #endif /** * \ingroup clk_group * \defgroup dfll_group DFLL Management * * A Digital Frequency Locked Loop can be used to generate a highly * accurate frequency from a slower-running reference clock, in much the * same way as a PLL. DFLLs typically have shorter startup times and * less jitter. They can also be used in open-loop mode to generate a * less accurate frequency without the use of a reference clock. * * There may be significant variations between platforms in the support * for certain features. * * \par Example: Setting up DFLL0 with default parameters and dithering enabled * * The following example shows how to configure and enable DFLL0 in * closed-loop mode using the default parameters specified through * configuration symbols. * \code dfll_enable_config_defaults(0); \endcode * * To configure and enable DFLL0 in closed-loop mode using the default * parameters and to enable specific feature like dithering for better accuracy, * you can use this initialization process. * \code struct dfll_config dfllcfg; dfll_enable_source(CONFIG_DFLL0_SOURCE); dfll_config_defaults(&dfllcfg, 0); dfll_config_enable_dithering(&dfllcfg); dfll_enable(&dfllcfg, 0); dfll_wait_for_accurate_lock(0); \endcode * * When the last function call returns, DFLL0 is running at a frequency * which matches the default configuration as accurately as possible. * Any additional alterations to the default configuration can be added * at the same place as the call to dfll_config_enable_dithering(), but * note that the DFLL will never achieve "accurate" lock if dithering is * disabled. * * @{ */ //! \name Chip-specific DFLL characteristics //@{ /** * \def NR_DFLLS * \brief Number of on-chip DFLLs. */ /** * \def DFLL_MIN_HZ * \brief Minimum frequency that the DFLL can generate. */ /** * \def DFLL_MAX_HZ * \brief Maximum frequency that the DFLL can generate. */ //@} /** * \typedef dfll_refclk_t * \brief Type used for identifying a reference clock source for the DFLL. */ //! \name DFLL Configuration //@{ /** * \struct dfll_config * \brief Hardware-specific representation of DFLL configuration. * * This structure contains one or more device-specific values * representing the current DFLL configuration. The contents of this * structure is typically different from platform to platform, and the * user should not access any fields except through the DFLL * configuration API. */ /** * \fn void dfll_config_init_open_loop_mode(struct dfll_config *cfg) * \brief Configure the DFLL configuration \a cfg for open-loop mode. * * \param cfg The DFLL configuration to be initialized. */ /** * \fn void dfll_config_init_closed_loop_mode(struct dfll_config *cfg, * dfll_refclk_t refclk, uint16_t div, uint16_t mul) * \brief Configure the DFLL configuration \a cfg for closed-loop mode. * * \param cfg The DFLL configuration to be initialized. * \param refclk The reference clock source. * \param div Reference clock divider. * \param mul Multiplier (integer part only). */ /** * \def dfll_config_defaults(cfg, dfll_id) * \brief Initialize DFLL configuration using default parameters. * * After this function returns, \a cfg will contain a configuration * which will make the DFLL run at (CONFIG_DFLLx_MUL / CONFIG_DFLLx_DIV) * times the frequency of CONFIG_DFLLx_SOURCE. The default configuration * will always use closed-loop mode with no fractional multiplier. * * \param cfg The DFLL configuration to be initialized. * \param dfll_id Use defaults for this DFLL. */ /** * \def dfll_get_default_rate(dfll_id) * \brief Return the default rate in Hz of \a dfll_id. */ /** * \fn void dfll_config_set_fractional_multiplier(struct dfll_config *cfg, * uint16_t mul_i, uint16_t mul_f) * \brief Set a fractional multiplier. * * This function has no effect in open-loop mode, and is only available * on devices which support fractional multipliers. * * The fractional part of the multiplier is assumed to be 16 bits. The * low-level driver will make sure to shift this value to match the * hardware if necessary. * * \param cfg The DFLL configuration to be modified. * \param mul_i Integer part of multiplier. * \param mul_f Fractional part of multiplier. */ /** * \fn void dfll_config_enable_dithering(struct dfll_config *cfg) * \brief Enable dithering for more accurate frequency generation. * * The fine LSB input to the VCO is dithered to achieve fractional * approximation to the correct multiplication ratio. * * \param cfg The DFLL configuration to be modified. */ /** * \fn void dfll_config_disable_dithering(struct dfll_config *cfg) * \brief Disable dithering. * * \see dfll_config_enable_dithering() * * \param cfg The DFLL configuration to be modified. */ /** * \fn void dfll_config_set_initial_tuning(struct dfll_config *cfg, * uint16_t coarse, uint16_t fine) * \brief Set initial VCO tuning. * * In open loop mode, this will determine the frequency of the output. * * In closed loop mode, this will provide an initial estimate of the VCO * tuning. While the DFLL will automatically adjust these values to * match the desired output frequency, careful selection of initial * values might reduce the time to achieve coarse and fine lock. * * \param cfg The DFLL configuration to be modified. * \param coarse Coarse tuning of the frequency generator. * \param fine Fine tuning of the frequency generator. */ /** * \fn void dfll_config_set_max_step(struct dfll_config *cfg, * uint16_t coarse, uint16_t fine) * \brief Set the maximum VCO tuning step size. * * This function has no effect in open-loop mode. * * By default, both of these values are set to 50% of their respective * maximums. It is not recommended to set the values any higher than * this, but setting them lower might reduce the frequency overshoot at * the expense of longer time to achieve coarse and/or fine lock. * * \param cfg The DFLL configuration to be modified * \param coarse The maximum step size of the coarse VCO tuning. * \param fine The maximum step size of the fine VCO tuning. */ /** * \fn void dfll_config_enable_ssg(struct dfll_config *cfg, * uint16_t amplitude, uint16_t step_size) * \brief Enable Spread Spectrum Generator. * * \param cfg The DFLL configuration to be modified. * \param amplitude The amplitude of the spread spectrum. * \param step_size The step size of the spread spectrum. */ /** * \fn void dfll_config_disable_ssg(struct dfll_config *cfg) * \brief Disable Spread Spectrum Generator. * * \param cfg The DFLL configuration to be modified. */ //@} //! \name Interaction with the DFLL hardware //@{ /** * \fn void dfll_enable_open_loop(const struct dfll_config *cfg, * unsigned int dfll_id) * \brief Activate the configuration \a cfg and enable DFLL \a dfll_id * in open-loop mode. * * \pre The configuration in \a cfg must represent an open-loop * configuration. * * \param cfg The configuration to be activated. * \param dfll_id The ID of the DFLL to be enabled. */ /** * \fn void dfll_enable_closed_loop(const struct dfll_config *cfg, * unsigned int dfll_id) * \brief Activate the configuration \a cfg and enable DFLL \a dfll_id * in closed-loop mode. * * \pre The configuration in \a cfg must represent a closed-loop * configuration. * * \param cfg The configuration to be activated. * \param dfll_id The ID of the DFLL to be enabled. */ /** * \fn void dfll_disable_open_loop(unsigned int dfll_id) * \brief Disable the DFLL identified by \a dfll_id. * * \pre The DFLL must have been enabled in open loop mode. * * \param dfll_id The ID of the DFLL to be disabled. */ /** * \fn void dfll_disable_closed_loop(unsigned int dfll_id) * \brief Disable the DFLL identified by \a dfll_id. * * \pre The DFLL must have been enabled in closed loop mode. * * \param dfll_id The ID of the DFLL to be disabled. */ /** * \fn bool dfll_is_coarse_locked(unsigned int dfll_id) * \brief Determine whether or not a DFLL has achieved coarse lock. * * \param dfll_id The ID of the DFLL to check. * * \retval true The DFLL has determined the final value of the coarse * VCO tuning value. * \retval false The DFLL has not yet determined the coarse VCO tuning * value, or has not been enabled. */ /** * \fn bool dfll_is_fine_locked(unsigned int dfll_id) * \brief Determine whether or not a DFLL has achieved fine lock. * * \param dfll_id The ID of the DFLL to check. * * \retval true The DFLL has determined the final value of the fine VCO * tuning value. * \retval false The DFLL has not yet determined the fine VCO tuning * value, or has not been enabled. */ /** * \fn bool dfll_is_accurate_locked(unsigned int dfll_id) * \brief Determine whether or not a DFLL has achieved accurate lock. * * \param dfll_id The ID of the DFLL to check. * * \retval true The DFLL has determined the final dithering duty cycle. * \retval false The DFLL has not yet determined the dithering duty * cycle, or has not been enabled with dithering enabled. */ /** * \fn void dfll_enable_source(enum dfll_refclk_t src) * \brief Enable the source of the dfll. * The source is enabled, if the source is not already running. * * \param dfll_source src The ID of the DFLL source to enable. */ /** * \fn void dfll_enable_config_defaults(unsigned int dfll_id) * \brief Enable the dfll with the default configuration. * DFLL is enabled, if the DFLL is not already locked. * * \param dfll_id The ID of the DFLL to enable. */ /** * \brief Wait for the DFLL identified by \a dfll_id to achieve coarse * lock. * * \param dfll_id The ID of the DFLL to wait for. * * \retval STATUS_OK The DFLL has achieved coarse lock. * \retval ERR_TIMEOUT Timed out waiting for lock. */ static inline int dfll_wait_for_coarse_lock(unsigned int dfll_id) { /* TODO: Add timeout mechanism */ while (!dfll_is_coarse_locked(dfll_id)) { /* Do nothing */ } return 0; } /** * \brief Wait for the DFLL identified by \a dfll_id to achieve fine * lock. * * \param dfll_id The ID of the DFLL to wait for. * * \retval STATUS_OK The DFLL has achieved fine lock. * \retval ERR_TIMEOUT Timed out waiting for lock. */ static inline int dfll_wait_for_fine_lock(unsigned int dfll_id) { /* TODO: Add timeout mechanism */ while (!dfll_is_fine_locked(dfll_id)) { /* Do nothing */ } return 0; } /** * \brief Wait for the DFLL identified by \a dfll_id to achieve accurate * lock. * * \param dfll_id The ID of the DFLL to wait for. * * \retval STATUS_OK The DFLL has achieved accurate lock. * \retval ERR_TIMEOUT Timed out waiting for lock. */ static inline int dfll_wait_for_accurate_lock(unsigned int dfll_id) { /* TODO: Add timeout mechanism */ while (!dfll_is_accurate_locked(dfll_id)) { /* Do nothing */ } return 0; } //@} //! @} #endif /* CLK_DFLL_H_INCLUDED */