adjust root folder
This commit is contained in:
@@ -0,0 +1,513 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Chip-specific oscillator management functions
|
||||
*
|
||||
* Copyright (c) 2010-2012 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
|
||||
*
|
||||
*/
|
||||
#ifndef XMEGA_OSC_H_INCLUDED
|
||||
#define XMEGA_OSC_H_INCLUDED
|
||||
|
||||
#include <compiler.h>
|
||||
#include <board.h>
|
||||
|
||||
/**
|
||||
* \weakgroup osc_group
|
||||
*
|
||||
* \section osc_group_errata Errata
|
||||
* - Auto-calibration does not work on XMEGA A1 revision H and
|
||||
* earlier.
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! \name Oscillator identifiers
|
||||
//@{
|
||||
//! 2 MHz Internal RC Oscillator
|
||||
#define OSC_ID_RC2MHZ OSC_RC2MEN_bm
|
||||
//! 32 MHz Internal RC Oscillator
|
||||
#define OSC_ID_RC32MHZ OSC_RC32MEN_bm
|
||||
//! 32 KHz Internal RC Oscillator
|
||||
#define OSC_ID_RC32KHZ OSC_RC32KEN_bm
|
||||
//! External Oscillator
|
||||
#define OSC_ID_XOSC OSC_XOSCEN_bm
|
||||
#if XMEGA_E
|
||||
//! 8 MHz Internal RC Oscillator
|
||||
# define OSC_ID_RC8MHZ OSC_RC8MEN_bm
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Reference from USB Start Of Frame
|
||||
* \note This cannot be enabled or disabled, but can be used as a reference for
|
||||
* the autocalibration (DFLL).
|
||||
*/
|
||||
#define OSC_ID_USBSOF 0xff
|
||||
//@}
|
||||
|
||||
//! \name External oscillator types
|
||||
//@{
|
||||
#define XOSC_TYPE_EXTERNAL 0 //!< External clock signal
|
||||
#define XOSC_TYPE_32KHZ 2 //!< 32.768 kHz resonator on TOSC
|
||||
#define XOSC_TYPE_XTAL 3 //!< 0.4 to 16 MHz resonator on XTAL
|
||||
//@}
|
||||
|
||||
/**
|
||||
* \def CONFIG_XOSC_32KHZ_LPM
|
||||
* \brief Define for enabling Low Power Mode for 32 kHz external oscillator.
|
||||
*/
|
||||
#ifdef __DOXYGEN__
|
||||
# define CONFIG_XOSC_32KHZ_LPM
|
||||
#endif /* __DOXYGEN__ */
|
||||
|
||||
/**
|
||||
* \def CONFIG_XOSC_STARTUP
|
||||
* \brief Board-dependent value that determines the number of start-up cycles
|
||||
* for external resonators, based on BOARD_XOSC_STARTUP_US. This is written to
|
||||
* the two MSB of the XOSCSEL field of OSC.XOSCCTRL.
|
||||
*
|
||||
* \note This is automatically computed from BOARD_XOSC_HZ and
|
||||
* BOARD_XOSC_STARTUP_US if it is not manually set.
|
||||
*/
|
||||
|
||||
//! \name XTAL resonator start-up cycles
|
||||
//@{
|
||||
#define XOSC_STARTUP_256 0 //!< 256 cycle start-up time
|
||||
#define XOSC_STARTUP_1024 1 //!< 1 k cycle start-up time
|
||||
#define XOSC_STARTUP_16384 2 //!< 16 k cycle start-up time
|
||||
//@}
|
||||
|
||||
/**
|
||||
* \def CONFIG_XOSC_RANGE
|
||||
* \brief Board-dependent value that sets the frequency range of the external
|
||||
* oscillator. This is written to the FRQRANGE field of OSC.XOSCCTRL.
|
||||
*
|
||||
* \note This is automatically computed from BOARD_XOSC_HZ if it is not manually
|
||||
* set.
|
||||
*/
|
||||
|
||||
//! \name XTAL resonator frequency range
|
||||
//@{
|
||||
//! 0.4 to 2 MHz frequency range
|
||||
#define XOSC_RANGE_04TO2 OSC_FRQRANGE_04TO2_gc
|
||||
//! 2 to 9 MHz frequency range
|
||||
#define XOSC_RANGE_2TO9 OSC_FRQRANGE_2TO9_gc
|
||||
//! 9 to 12 MHz frequency range
|
||||
#define XOSC_RANGE_9TO12 OSC_FRQRANGE_9TO12_gc
|
||||
//! 12 to 16 MHz frequency range
|
||||
#define XOSC_RANGE_12TO16 OSC_FRQRANGE_12TO16_gc
|
||||
//@}
|
||||
|
||||
/**
|
||||
* \def XOSC_STARTUP_TIMEOUT
|
||||
* \brief Number of us to wait for XOSC to start
|
||||
*
|
||||
* This is the number of slow clock cycles corresponding to
|
||||
* OSC0_STARTUP_VALUE with an additional 25% safety margin. If the
|
||||
* oscillator isn't running when this timeout has expired, it is assumed
|
||||
* to have failed to start.
|
||||
*/
|
||||
|
||||
// If application intends to use XOSC.
|
||||
#ifdef BOARD_XOSC_HZ
|
||||
// Get start-up config for XOSC, if not manually set.
|
||||
# ifndef CONFIG_XOSC_STARTUP
|
||||
# ifndef BOARD_XOSC_STARTUP_US
|
||||
# error BOARD_XOSC_STARTUP_US must be configured.
|
||||
# else
|
||||
//! \internal Number of start-up cycles for the board's XOSC.
|
||||
# define BOARD_XOSC_STARTUP_CYCLES \
|
||||
(BOARD_XOSC_HZ / 1000000 * BOARD_XOSC_STARTUP_US)
|
||||
|
||||
# if (BOARD_XOSC_TYPE == XOSC_TYPE_XTAL)
|
||||
# if (BOARD_XOSC_STARTUP_CYCLES > 16384)
|
||||
# error BOARD_XOSC_STARTUP_US is too high for current BOARD_XOSC_HZ.
|
||||
|
||||
# elif (BOARD_XOSC_STARTUP_CYCLES > 1024)
|
||||
# define CONFIG_XOSC_STARTUP XOSC_STARTUP_16384
|
||||
# define XOSC_STARTUP_TIMEOUT (16384*(1000000/BOARD_XOSC_HZ))
|
||||
|
||||
# elif (BOARD_XOSC_STARTUP_CYCLES > 256)
|
||||
# define CONFIG_XOSC_STARTUP XOSC_STARTUP_1024
|
||||
# define XOSC_STARTUP_TIMEOUT (1024*(1000000/BOARD_XOSC_HZ))
|
||||
|
||||
# else
|
||||
# define CONFIG_XOSC_STARTUP XOSC_STARTUP_256
|
||||
# define XOSC_STARTUP_TIMEOUT (256*(1000000/BOARD_XOSC_HZ))
|
||||
# endif
|
||||
# else /* BOARD_XOSC_TYPE == XOSC_TYPE_XTAL */
|
||||
# define CONFIG_XOSC_STARTUP 0
|
||||
# endif
|
||||
# endif /* BOARD_XOSC_STARTUP_US */
|
||||
# endif /* CONFIG_XOSC_STARTUP */
|
||||
|
||||
// Get frequency range setting for XOSC, if not manually set.
|
||||
# ifndef CONFIG_XOSC_RANGE
|
||||
# if (BOARD_XOSC_TYPE == XOSC_TYPE_XTAL)
|
||||
# if (BOARD_XOSC_HZ < 400000)
|
||||
# error BOARD_XOSC_HZ is below minimum frequency of 400 kHz.
|
||||
|
||||
# elif (BOARD_XOSC_HZ < 2000000)
|
||||
# define CONFIG_XOSC_RANGE XOSC_RANGE_04TO2
|
||||
|
||||
# elif (BOARD_XOSC_HZ < 9000000)
|
||||
# define CONFIG_XOSC_RANGE XOSC_RANGE_2TO9
|
||||
|
||||
# elif (BOARD_XOSC_HZ < 12000000)
|
||||
# define CONFIG_XOSC_RANGE XOSC_RANGE_9TO12
|
||||
|
||||
# elif (BOARD_XOSC_HZ <= 16000000)
|
||||
# define CONFIG_XOSC_RANGE XOSC_RANGE_12TO16
|
||||
|
||||
# else
|
||||
# error BOARD_XOSC_HZ is above maximum frequency of 16 MHz.
|
||||
# endif
|
||||
# else /* BOARD_XOSC_TYPE == XOSC_TYPE_XTAL */
|
||||
# define CONFIG_XOSC_RANGE 0
|
||||
# endif
|
||||
# endif /* CONFIG_XOSC_RANGE */
|
||||
#endif /* BOARD_XOSC_HZ */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \brief Enable internal oscillator \a id
|
||||
*
|
||||
* Do not call this function directly. Use osc_enable() instead.
|
||||
*/
|
||||
static inline void
|
||||
osc_enable_internal (uint8_t id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
|
||||
Assert (id != OSC_ID_USBSOF);
|
||||
|
||||
flags = cpu_irq_save ();
|
||||
OSC.CTRL |= id;
|
||||
#if (XMEGA_E && CONFIG_SYSCLK_RC8MHZ_LPM)
|
||||
if (id == OSC_ID_RC8MHZ)
|
||||
{
|
||||
OSC.CTRL |= OSC_RC8MLPM_bm;
|
||||
}
|
||||
#endif
|
||||
cpu_irq_restore (flags);
|
||||
}
|
||||
|
||||
#if defined(BOARD_XOSC_HZ) || defined(__DOXYGEN__)
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \brief Enable external oscillator \a id
|
||||
*
|
||||
* Do not call this function directly. Use osc_enable() instead. Also
|
||||
* note that this function is only available if the board actually has
|
||||
* an external oscillator crystal.
|
||||
*/
|
||||
static inline void
|
||||
osc_enable_external (uint8_t id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
|
||||
Assert (id == OSC_ID_XOSC);
|
||||
|
||||
#ifndef CONFIG_XOSC_32KHZ_LPM
|
||||
# if (XMEGA_E && (BOARD_XOSC_TYPE == XOSC_TYPE_EXTERNAL) && defined(CONFIG_XOSC_EXTERNAL_PC4))
|
||||
OSC.XOSCCTRL = OSC_XOSCSEL4_bm;
|
||||
# else
|
||||
OSC.XOSCCTRL = BOARD_XOSC_TYPE | (CONFIG_XOSC_STARTUP << 2) |
|
||||
CONFIG_XOSC_RANGE;
|
||||
# endif
|
||||
#else
|
||||
OSC.XOSCCTRL = BOARD_XOSC_TYPE | (CONFIG_XOSC_STARTUP << 2) |
|
||||
CONFIG_XOSC_RANGE | OSC_X32KLPM_bm;
|
||||
#endif /* CONFIG_XOSC_32KHZ_LPM */
|
||||
|
||||
flags = cpu_irq_save ();
|
||||
OSC.CTRL |= id;
|
||||
cpu_irq_restore (flags);
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void
|
||||
osc_enable_external (uint8_t id)
|
||||
{
|
||||
Assert (false); // No external oscillator on the selected board
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
osc_disable (uint8_t id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
|
||||
Assert (id != OSC_ID_USBSOF);
|
||||
|
||||
flags = cpu_irq_save ();
|
||||
OSC.CTRL &= ~id;
|
||||
cpu_irq_restore (flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
osc_enable (uint8_t id)
|
||||
{
|
||||
if (id != OSC_ID_XOSC)
|
||||
{
|
||||
osc_enable_internal (id);
|
||||
}
|
||||
else
|
||||
{
|
||||
osc_enable_external (id);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
osc_is_ready (uint8_t id)
|
||||
{
|
||||
Assert (id != OSC_ID_USBSOF);
|
||||
|
||||
return OSC.STATUS & id;
|
||||
}
|
||||
|
||||
//! \name XMEGA-Specific Oscillator Features
|
||||
//@{
|
||||
|
||||
/**
|
||||
* \brief Enable DFLL-based automatic calibration of an internal
|
||||
* oscillator.
|
||||
*
|
||||
* The XMEGA features two Digital Frequency Locked Loops (DFLLs) which
|
||||
* can be used to improve the accuracy of the 2 MHz and 32 MHz internal
|
||||
* RC oscillators. The DFLL compares the oscillator frequency with a
|
||||
* more accurate reference clock to do automatic run-time calibration of
|
||||
* the oscillator.
|
||||
*
|
||||
* This function enables auto-calibration for either the 2 MHz or 32 MHz
|
||||
* internal oscillator using either the 32.768 kHz calibrated internal
|
||||
* oscillator or an external crystal oscillator as a reference. If the
|
||||
* latter option is used, the crystal must be connected to the TOSC pins
|
||||
* and run at 32.768 kHz.
|
||||
*
|
||||
* \param id The ID of the oscillator for which to enable
|
||||
* auto-calibration:
|
||||
* \arg \c OSC_ID_RC2MHZ or \c OSC_ID_RC32MHZ.
|
||||
* \param ref_id The ID of the oscillator to use as a reference:
|
||||
* \arg \c OSC_ID_RC32KHZ or \c OSC_ID_XOSC for internal or external 32 kHz
|
||||
* reference, respectively.
|
||||
* \arg \c OSC_ID_USBSOF for 32 MHz only when USB is available and running.
|
||||
*/
|
||||
static inline void
|
||||
osc_enable_autocalibration (uint8_t id, uint8_t ref_id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
|
||||
flags = cpu_irq_save ();
|
||||
switch (id)
|
||||
{
|
||||
case OSC_ID_RC2MHZ:
|
||||
#if !XMEGA_E
|
||||
Assert ((ref_id == OSC_ID_RC32KHZ) || (ref_id == OSC_ID_XOSC));
|
||||
if (ref_id == OSC_ID_XOSC)
|
||||
{
|
||||
osc_enable (OSC_ID_RC32KHZ);
|
||||
OSC.DFLLCTRL |= OSC_RC2MCREF_bm;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSC.DFLLCTRL &= ~(OSC_RC2MCREF_bm);
|
||||
}
|
||||
DFLLRC2M.CTRL |= DFLL_ENABLE_bm;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OSC_ID_RC32MHZ:
|
||||
#if XMEGA_AU || XMEGA_B || XMEGA_C || XMEGA_E
|
||||
Assert ((ref_id == OSC_ID_RC32KHZ)
|
||||
|| (ref_id == OSC_ID_XOSC) || (ref_id == OSC_ID_USBSOF));
|
||||
|
||||
OSC.DFLLCTRL &= ~(OSC_RC32MCREF_gm);
|
||||
|
||||
if (ref_id == OSC_ID_XOSC)
|
||||
{
|
||||
osc_enable (OSC_ID_RC32KHZ);
|
||||
OSC.DFLLCTRL |= OSC_RC32MCREF_XOSC32K_gc;
|
||||
}
|
||||
else if (ref_id == OSC_ID_RC32KHZ)
|
||||
{
|
||||
OSC.DFLLCTRL |= OSC_RC32MCREF_RC32K_gc;
|
||||
}
|
||||
# if !XMEGA_E
|
||||
else if (ref_id == OSC_ID_USBSOF)
|
||||
{
|
||||
/*
|
||||
* Calibrate 32MRC at 48MHz using USB SOF
|
||||
* 48MHz / 1kHz = 0xBB80
|
||||
*/
|
||||
DFLLRC32M.COMP1 = 0x80;
|
||||
DFLLRC32M.COMP2 = 0xBB;
|
||||
OSC.DFLLCTRL |= OSC_RC32MCREF_USBSOF_gc;
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
Assert ((ref_id == OSC_ID_RC32KHZ) || (ref_id == OSC_ID_XOSC));
|
||||
|
||||
if (ref_id == OSC_ID_XOSC)
|
||||
{
|
||||
osc_enable (OSC_ID_RC32KHZ);
|
||||
OSC.DFLLCTRL |= OSC_RC32MCREF_bm;
|
||||
}
|
||||
else if (ref_id == OSC_ID_RC32KHZ)
|
||||
{
|
||||
OSC.DFLLCTRL &= ~(OSC_RC32MCREF_bm);
|
||||
}
|
||||
#endif
|
||||
DFLLRC32M.CTRL |= DFLL_ENABLE_bm;
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert (false);
|
||||
break;
|
||||
}
|
||||
cpu_irq_restore (flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable DFLL-based automatic calibration of an internal
|
||||
* oscillator.
|
||||
*
|
||||
* \see osc_enable_autocalibration
|
||||
*
|
||||
* \param id The ID of the oscillator for which to disable
|
||||
* auto-calibration:
|
||||
* \arg \c OSC_ID_RC2MHZ or \c OSC_ID_RC32MHZ.
|
||||
*/
|
||||
static inline void
|
||||
osc_disable_autocalibration (uint8_t id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case OSC_ID_RC2MHZ:
|
||||
#if !XMEGA_E
|
||||
DFLLRC2M.CTRL = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OSC_ID_RC32MHZ:
|
||||
DFLLRC32M.CTRL = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Load a specific calibration value for the specified oscillator.
|
||||
*
|
||||
* \param id The ID of the oscillator for which to disable
|
||||
* auto-calibration:
|
||||
* \arg \c OSC_ID_RC2MHZ or \c OSC_ID_RC32MHZ.
|
||||
* \param calib The specific calibration value required:
|
||||
*
|
||||
*/
|
||||
static inline void
|
||||
osc_user_calibration (uint8_t id, uint16_t calib)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case OSC_ID_RC2MHZ:
|
||||
#if !XMEGA_E
|
||||
DFLLRC2M.CALA = LSB (calib);
|
||||
DFLLRC2M.CALB = MSB (calib);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OSC_ID_RC32MHZ:
|
||||
DFLLRC32M.CALA = LSB (calib);
|
||||
DFLLRC32M.CALB = MSB (calib);
|
||||
break;
|
||||
|
||||
#if XMEGA_E
|
||||
case OSC_ID_RC8MHZ:
|
||||
OSC.RC8MCAL = LSB (calib);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Assert (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
static inline uint32_t
|
||||
osc_get_rate (uint8_t id)
|
||||
{
|
||||
Assert (id != OSC_ID_USBSOF);
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case OSC_ID_RC2MHZ:
|
||||
return 2000000UL;
|
||||
|
||||
case OSC_ID_RC32MHZ:
|
||||
#ifdef CONFIG_OSC_RC32_CAL
|
||||
return CONFIG_OSC_RC32_CAL;
|
||||
#else
|
||||
return 32000000UL;
|
||||
#endif
|
||||
|
||||
case OSC_ID_RC32KHZ:
|
||||
return 32768UL;
|
||||
|
||||
#ifdef BOARD_XOSC_HZ
|
||||
case OSC_ID_XOSC:
|
||||
return BOARD_XOSC_HZ;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Assert (false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
//! @}
|
||||
|
||||
#endif /* XMEGA_OSC_H_INCLUDED */
|
||||
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Chip-specific PLL management functions
|
||||
*
|
||||
* Copyright (c) 2010-2013 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
|
||||
*
|
||||
*/
|
||||
#ifndef XMEGA_PLL_H_INCLUDED
|
||||
#define XMEGA_PLL_H_INCLUDED
|
||||
|
||||
#include <compiler.h>
|
||||
|
||||
/**
|
||||
* \weakgroup pll_group
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define NR_PLLS 1
|
||||
#define PLL_MIN_HZ 10000000UL
|
||||
#define PLL_MAX_HZ 200000000UL
|
||||
#define PLL_NR_OPTIONS 0
|
||||
|
||||
enum pll_source
|
||||
{
|
||||
//! 2 MHz Internal RC Oscillator
|
||||
PLL_SRC_RC2MHZ = OSC_PLLSRC_RC2M_gc,
|
||||
//! 32 MHz Internal RC Oscillator
|
||||
PLL_SRC_RC32MHZ = OSC_PLLSRC_RC32M_gc,
|
||||
//! External Clock Source
|
||||
PLL_SRC_XOSC = OSC_PLLSRC_XOSC_gc,
|
||||
};
|
||||
|
||||
#define pll_get_default_rate(pll_id) \
|
||||
pll_get_default_rate_priv(CONFIG_PLL##pll_id##_SOURCE, \
|
||||
CONFIG_PLL##pll_id##_MUL, \
|
||||
CONFIG_PLL##pll_id##_DIV)
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \brief Return clock rate for specified PLL settings.
|
||||
*
|
||||
* \note Due to the hardware implementation of the PLL, \a div must be 4 if the
|
||||
* 32 MHz RC oscillator is used as reference and 1 otherwise. The reference must
|
||||
* be above 440 kHz, and the output between 10 and 200 MHz.
|
||||
*
|
||||
* \param src ID of the PLL's reference source oscillator.
|
||||
* \param mul Multiplier for the PLL.
|
||||
* \param div Divisor for the PLL.
|
||||
*
|
||||
* \retval Output clock rate from PLL.
|
||||
*/
|
||||
static inline uint32_t
|
||||
pll_get_default_rate_priv (enum pll_source src,
|
||||
unsigned int mul, unsigned int div)
|
||||
{
|
||||
uint32_t rate;
|
||||
|
||||
switch (src)
|
||||
{
|
||||
case PLL_SRC_RC2MHZ:
|
||||
rate = 2000000UL;
|
||||
Assert (div == 1);
|
||||
break;
|
||||
|
||||
case PLL_SRC_RC32MHZ:
|
||||
#ifdef CONFIG_OSC_RC32_CAL //32MHz oscillator is calibrated to another frequency
|
||||
rate = CONFIG_OSC_RC32_CAL / 4;
|
||||
#else
|
||||
rate = 8000000UL;
|
||||
#endif
|
||||
Assert (div == 4);
|
||||
break;
|
||||
|
||||
case PLL_SRC_XOSC:
|
||||
rate = osc_get_rate (OSC_ID_XOSC);
|
||||
Assert (div == 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Assert (rate >= 440000UL);
|
||||
|
||||
rate *= mul;
|
||||
|
||||
Assert (rate >= PLL_MIN_HZ);
|
||||
Assert (rate <= PLL_MAX_HZ);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
struct pll_config
|
||||
{
|
||||
uint8_t ctrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* \note The XMEGA PLL hardware uses hard-wired input dividers, so the
|
||||
* user must ensure that \a div is set as follows:
|
||||
* - If \a src is PLL_SRC_32MHZ, \a div must be set to 4.
|
||||
* - Otherwise, \a div must be set to 1.
|
||||
*/
|
||||
static inline void
|
||||
pll_config_init (struct pll_config *cfg, enum pll_source src,
|
||||
unsigned int div, unsigned int mul)
|
||||
{
|
||||
Assert (mul >= 1 && mul <= 31);
|
||||
|
||||
if (src == PLL_SRC_RC32MHZ)
|
||||
{
|
||||
Assert (div == 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert (div == 1);
|
||||
}
|
||||
|
||||
/* Initialize the configuration */
|
||||
cfg->ctrl = src | (mul << OSC_PLLFAC_gp);
|
||||
}
|
||||
|
||||
#define pll_config_defaults(cfg, pll_id) \
|
||||
pll_config_init(cfg, \
|
||||
CONFIG_PLL##pll_id##_SOURCE, \
|
||||
CONFIG_PLL##pll_id##_DIV, \
|
||||
CONFIG_PLL##pll_id##_MUL)
|
||||
|
||||
static inline void
|
||||
pll_config_read (struct pll_config *cfg, unsigned int pll_id)
|
||||
{
|
||||
Assert (pll_id < NR_PLLS);
|
||||
|
||||
cfg->ctrl = OSC.PLLCTRL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pll_config_write (const struct pll_config *cfg, unsigned int pll_id)
|
||||
{
|
||||
Assert (pll_id < NR_PLLS);
|
||||
|
||||
OSC.PLLCTRL = cfg->ctrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note If a different PLL reference oscillator than those enabled by
|
||||
* \ref sysclk_init() is used, the user must ensure that the desired reference
|
||||
* is enabled prior to calling this function.
|
||||
*/
|
||||
static inline void
|
||||
pll_enable (const struct pll_config *cfg, unsigned int pll_id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
|
||||
Assert (pll_id < NR_PLLS);
|
||||
|
||||
flags = cpu_irq_save ();
|
||||
pll_config_write (cfg, pll_id);
|
||||
OSC.CTRL |= OSC_PLLEN_bm;
|
||||
cpu_irq_restore (flags);
|
||||
}
|
||||
|
||||
/*! \note This will not automatically disable the reference oscillator that is
|
||||
* configured for the PLL.
|
||||
*/
|
||||
static inline void
|
||||
pll_disable (unsigned int pll_id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
|
||||
Assert (pll_id < NR_PLLS);
|
||||
|
||||
flags = cpu_irq_save ();
|
||||
OSC.CTRL &= ~OSC_PLLEN_bm;
|
||||
cpu_irq_restore (flags);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pll_is_locked (unsigned int pll_id)
|
||||
{
|
||||
Assert (pll_id < NR_PLLS);
|
||||
|
||||
return OSC.STATUS & OSC_PLLRDY_bm;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pll_enable_source (enum pll_source src)
|
||||
{
|
||||
switch (src)
|
||||
{
|
||||
case PLL_SRC_RC2MHZ:
|
||||
break;
|
||||
|
||||
case PLL_SRC_RC32MHZ:
|
||||
if (!osc_is_ready (OSC_ID_RC32MHZ))
|
||||
{
|
||||
osc_enable (OSC_ID_RC32MHZ);
|
||||
osc_wait_ready (OSC_ID_RC32MHZ);
|
||||
#ifdef CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC
|
||||
if (CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC != OSC_ID_USBSOF)
|
||||
{
|
||||
osc_enable (CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
osc_wait_ready (CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
}
|
||||
osc_enable_autocalibration (OSC_ID_RC32MHZ,
|
||||
CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case PLL_SRC_XOSC:
|
||||
if (!osc_is_ready (OSC_ID_XOSC))
|
||||
{
|
||||
osc_enable (OSC_ID_XOSC);
|
||||
osc_wait_ready (OSC_ID_XOSC);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Assert (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
pll_enable_config_defaults (unsigned int pll_id)
|
||||
{
|
||||
struct pll_config pllcfg;
|
||||
|
||||
if (pll_is_locked (pll_id))
|
||||
{
|
||||
return; // Pll already running
|
||||
}
|
||||
switch (pll_id)
|
||||
{
|
||||
#ifdef CONFIG_PLL0_SOURCE
|
||||
case 0:
|
||||
pll_enable_source (CONFIG_PLL0_SOURCE);
|
||||
pll_config_init (&pllcfg,
|
||||
CONFIG_PLL0_SOURCE, CONFIG_PLL0_DIV, CONFIG_PLL0_MUL);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Assert (false);
|
||||
break;
|
||||
}
|
||||
pll_enable (&pllcfg, pll_id);
|
||||
while (!pll_is_locked (pll_id));
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
#endif /* XMEGA_PLL_H_INCLUDED */
|
||||
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Chip-specific system clock management functions
|
||||
*
|
||||
* Copyright (c) 2010-2013 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
|
||||
#include <sysclk.h>
|
||||
#include <osc.h>
|
||||
#include <pll.h>
|
||||
|
||||
#if XMEGA_AU || XMEGA_B || XMEGA_C
|
||||
# include <nvm.h>
|
||||
#endif
|
||||
|
||||
|
||||
void sysclk_init(void)
|
||||
{
|
||||
uint8_t *reg = (uint8_t *) & PR.PRGEN;
|
||||
uint8_t i;
|
||||
#ifdef CONFIG_OSC_RC32_CAL
|
||||
uint16_t cal;
|
||||
/* avoid Cppcheck Warning */
|
||||
UNUSED(cal);
|
||||
#endif
|
||||
bool need_rc2mhz = false;
|
||||
|
||||
/* Turn off all peripheral clocks that can be turned off. */
|
||||
for (i = 0; i <= SYSCLK_PORT_F; i++) {
|
||||
*(reg++) = 0xff;
|
||||
}
|
||||
|
||||
/* Set up system clock prescalers if different from defaults */
|
||||
if ((CONFIG_SYSCLK_PSADIV != SYSCLK_PSADIV_1)
|
||||
|| (CONFIG_SYSCLK_PSBCDIV != SYSCLK_PSBCDIV_1_1)) {
|
||||
sysclk_set_prescalers(CONFIG_SYSCLK_PSADIV, CONFIG_SYSCLK_PSBCDIV);
|
||||
}
|
||||
#if (CONFIG_OSC_RC32_CAL==48000000UL)
|
||||
MSB(cal) =
|
||||
nvm_read_production_signature_row
|
||||
(nvm_get_production_signature_row_offset(USBRCOSC));
|
||||
LSB(cal) =
|
||||
nvm_read_production_signature_row
|
||||
(nvm_get_production_signature_row_offset(USBRCOSCA));
|
||||
/*
|
||||
* If a device has an uncalibrated value in the
|
||||
* production signature row (early sample part), load a
|
||||
* sane default calibration value.
|
||||
*/
|
||||
if (cal == 0xFFFF) {
|
||||
cal = 0x2340;
|
||||
}
|
||||
osc_user_calibration(OSC_ID_RC32MHZ, cal);
|
||||
#endif
|
||||
/*
|
||||
* Switch to the selected initial system clock source, unless
|
||||
* the default internal 2 MHz oscillator is selected.
|
||||
*/
|
||||
if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_RC2MHZ) {
|
||||
need_rc2mhz = true;
|
||||
} else {
|
||||
switch (CONFIG_SYSCLK_SOURCE) {
|
||||
case SYSCLK_SRC_RC32MHZ:
|
||||
osc_enable(OSC_ID_RC32MHZ);
|
||||
osc_wait_ready(OSC_ID_RC32MHZ);
|
||||
#ifdef CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC
|
||||
if (CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC != OSC_ID_USBSOF) {
|
||||
osc_enable(CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
osc_wait_ready(CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
}
|
||||
osc_enable_autocalibration(OSC_ID_RC32MHZ,
|
||||
CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SYSCLK_SRC_RC32KHZ:
|
||||
osc_enable(OSC_ID_RC32KHZ);
|
||||
osc_wait_ready(OSC_ID_RC32KHZ);
|
||||
break;
|
||||
|
||||
case SYSCLK_SRC_XOSC:
|
||||
osc_enable(OSC_ID_XOSC);
|
||||
osc_wait_ready(OSC_ID_XOSC);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PLL0_SOURCE
|
||||
case SYSCLK_SRC_PLL:
|
||||
if (CONFIG_PLL0_SOURCE == PLL_SRC_RC2MHZ) {
|
||||
need_rc2mhz = true;
|
||||
}
|
||||
pll_enable_config_defaults(0);
|
||||
break;
|
||||
#endif
|
||||
#if XMEGA_E
|
||||
case SYSCLK_SRC_RC8MHZ:
|
||||
osc_enable(OSC_ID_RC8MHZ);
|
||||
osc_wait_ready(OSC_ID_RC8MHZ);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
//unhandled_case(CONFIG_SYSCLK_SOURCE);
|
||||
return;
|
||||
}
|
||||
|
||||
ccp_write_io((uint8_t *) & CLK.CTRL, CONFIG_SYSCLK_SOURCE);
|
||||
Assert(CLK.CTRL == CONFIG_SYSCLK_SOURCE);
|
||||
}
|
||||
|
||||
if (need_rc2mhz) {
|
||||
#ifdef CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC
|
||||
osc_enable(CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC);
|
||||
osc_wait_ready(CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC);
|
||||
osc_enable_autocalibration(OSC_ID_RC2MHZ,
|
||||
CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC);
|
||||
#endif
|
||||
} else {
|
||||
osc_disable(OSC_ID_RC2MHZ);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RTC_SOURCE
|
||||
sysclk_rtcsrc_enable(CONFIG_RTC_SOURCE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sysclk_enable_module(enum sysclk_port_id port,
|
||||
uint8_t id)
|
||||
{
|
||||
irqflags_t flags = cpu_irq_save();
|
||||
|
||||
*((uint8_t *) & PR.PRGEN + port) &= ~id;
|
||||
|
||||
cpu_irq_restore(flags);
|
||||
}
|
||||
|
||||
void sysclk_disable_module(enum sysclk_port_id port,
|
||||
uint8_t id)
|
||||
{
|
||||
irqflags_t flags = cpu_irq_save();
|
||||
|
||||
*((uint8_t *) & PR.PRGEN + port) |= id;
|
||||
|
||||
cpu_irq_restore(flags);
|
||||
}
|
||||
|
||||
#if XMEGA_AU || XMEGA_B || XMEGA_C || defined(__DOXYGEN__)
|
||||
|
||||
/**
|
||||
* \brief Enable clock for the USB module
|
||||
*
|
||||
* \pre CONFIG_USBCLK_SOURCE must be defined.
|
||||
*
|
||||
* \param frequency The required USB clock frequency in MHz:
|
||||
* \arg \c 6 for 6 MHz
|
||||
* \arg \c 48 for 48 MHz
|
||||
*/
|
||||
void sysclk_enable_usb(uint8_t frequency)
|
||||
{
|
||||
uint8_t prescaler;
|
||||
|
||||
Assert((frequency == 6) || (frequency == 48));
|
||||
|
||||
/*
|
||||
* Enable or disable prescaler depending on if the USB frequency is 6
|
||||
* MHz or 48 MHz. Only 6 MHz USB frequency requires prescaling.
|
||||
*/
|
||||
if (frequency == 6) {
|
||||
prescaler = CLK_USBPSDIV_8_gc;
|
||||
} else {
|
||||
prescaler = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch to the system clock selected by the user.
|
||||
*/
|
||||
switch (CONFIG_USBCLK_SOURCE) {
|
||||
case USBCLK_SRC_RCOSC:
|
||||
if (!osc_is_ready(OSC_ID_RC32MHZ)) {
|
||||
osc_enable(OSC_ID_RC32MHZ);
|
||||
osc_wait_ready(OSC_ID_RC32MHZ);
|
||||
#ifdef CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC
|
||||
if (CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC != OSC_ID_USBSOF) {
|
||||
osc_enable(CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
osc_wait_ready(CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
}
|
||||
osc_enable_autocalibration(OSC_ID_RC32MHZ,
|
||||
CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC);
|
||||
#endif
|
||||
}
|
||||
ccp_write_io((uint8_t *) & CLK.USBCTRL, (prescaler)
|
||||
| CLK_USBSRC_RC32M_gc | CLK_USBSEN_bm);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PLL0_SOURCE
|
||||
case USBCLK_SRC_PLL:
|
||||
pll_enable_config_defaults(0);
|
||||
ccp_write_io((uint8_t *) & CLK.USBCTRL, (prescaler)
|
||||
| CLK_USBSRC_PLL_gc | CLK_USBSEN_bm);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_USB);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable clock for the USB module
|
||||
*/
|
||||
void sysclk_disable_usb(void)
|
||||
{
|
||||
sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_USB);
|
||||
ccp_write_io((uint8_t *) & CLK.USBCTRL, 0);
|
||||
}
|
||||
#endif // XMEGA_AU || XMEGA_B || XMEGA_C
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user