blob: faca56d387172bc277d5d0eca4b5092c9ea0821b [file] [log] [blame]
/**
* \file
*
* \brief Chip-specific oscillator management functions
*
* Copyright (c) 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 CHIP_OSC_H_INCLUDED
#define CHIP_OSC_H_INCLUDED
#include <board.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \weakgroup osc_group
* @{
*/
//! \name Oscillator identifiers
//@{
#define OSC_ID_OSC0 0 //!< External Oscillator 0
#define OSC_ID_OSC32 1 //!< External 32 kHz oscillator
#define OSC_ID_RC32K 2 //!< Internal 32 kHz RC oscillator
#define OSC_ID_RC80M 3 //!< Internal 80 MHz RC oscillator
#define OSC_ID_RCFAST 4 //!< Internal 4-8-12 MHz RCFAST oscillator
#define OSC_ID_RC1M 5 //!< Internal 1 MHz RC oscillator
#define OSC_ID_RCSYS 6 //!< Internal System RC oscillator
//@}
//! \name OSC0 mode values
//@{
//! External clock connected to XIN
#define OSC_MODE_EXTERNAL 0
//! Crystal connected to XIN/XOUT
#define OSC_MODE_XTAL SCIF_OSCCTRL0_MODE
//@}
//! \name OSC32 mode values
//@{
//! External clock connected to XIN32
#define OSC32_MODE_EXTERNAL BSCIF_OSCCTRL32_MODE(0)
//! Crystal connected to XIN32/XOUT32
#define OSC32_MODE_XTAL BSCIF_OSCCTRL32_MODE(1)
//! Crystal connected to XIN32/XOUT32 in high current mode
#define OSC32_MODE_XTAL_HC BSCIF_OSCCTRL32_MODE(4)
//@}
//! \name OSC0 startup values
//@{
//! 0 cycles
#define OSC_STARTUP_0 SCIF_OSCCTRL0_STARTUP(0)
//! 64 cycles (560 us)
#define OSC_STARTUP_64 SCIF_OSCCTRL0_STARTUP(1)
//! 128 cycles (1.1 ms)
#define OSC_STARTUP_128 SCIF_OSCCTRL0_STARTUP(2)
//! 2048 cycles (18 ms)
#define OSC_STARTUP_2048 SCIF_OSCCTRL0_STARTUP(3)
//! 4096 cycles (36 ms)
#define OSC_STARTUP_4096 SCIF_OSCCTRL0_STARTUP(4)
//! 8192 cycles (71 ms)
#define OSC_STARTUP_8192 SCIF_OSCCTRL0_STARTUP(5)
//! 16384 cycles (143 ms)
#define OSC_STARTUP_16384 SCIF_OSCCTRL0_STARTUP(6)
//! 32768 cycles (285 ms)
#define OSC_STARTUP_32768 SCIF_OSCCTRL0_STARTUP(7)
//@}
//! \name OSC32 startup values
//@{
//! 0 cycles
#define OSC32_STARTUP_0 BSCIF_OSCCTRL32_STARTUP(0)
//! 128 cycles (1.1 ms)
#define OSC32_STARTUP_128 BSCIF_OSCCTRL32_STARTUP(1)
//! 8192 cycles (72.3 ms)
#define OSC32_STARTUP_8192 BSCIF_OSCCTRL32_STARTUP(2)
//! 16384 cycles (143 ms)
#define OSC32_STARTUP_16384 BSCIF_OSCCTRL32_STARTUP(3)
//! 65536 cycles (570 ms)
#define OSC32_STARTUP_65536 BSCIF_OSCCTRL32_STARTUP(4)
//! 131072 cycles (1.1 s)
#define OSC32_STARTUP_131072 BSCIF_OSCCTRL32_STARTUP(5)
//! 262144 cycles (2.3 s)
#define OSC32_STARTUP_262144 BSCIF_OSCCTRL32_STARTUP(6)
//! 524288 cycles (4.6 s)
#define OSC32_STARTUP_524288 BSCIF_OSCCTRL32_STARTUP(7)
//@}
/**
* \def OSC0_STARTUP_TIMEOUT
* \brief Number of slow clock cycles to wait for OSC0 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.
*/
/**
* \def OSC0_MODE_VALUE
* \brief Board-dependent value written to the MODE bitfield of
* PM_OSCCTRL(0)
*/
/**
* \def OSC0_STARTUP_VALUE
* \brief Board-dependent value written to the STARTUP bitfield of
* PM_OSCCTRL(0)
*/
#if defined(BOARD_OSC0_STARTUP_US)
# if BOARD_OSC0_STARTUP_US == 0
# define OSC0_STARTUP_VALUE OSC_STARTUP_0
# define OSC0_STARTUP_TIMEOUT 8
# elif BOARD_OSC0_STARTUP_US <= 557
# define OSC0_STARTUP_VALUE OSC_STARTUP_64
# define OSC0_STARTUP_TIMEOUT 80
# elif BOARD_OSC0_STARTUP_US <= 1100
# define OSC0_STARTUP_VALUE OSC_STARTUP_128
# define OSC0_STARTUP_TIMEOUT 160
# elif BOARD_OSC0_STARTUP_US <= 18000
# define OSC0_STARTUP_VALUE OSC_STARTUP_2048
# define OSC0_STARTUP_TIMEOUT 2560
# elif BOARD_OSC0_STARTUP_US <= 36000
# define OSC0_STARTUP_VALUE OSC_STARTUP_4096
# define OSC0_STARTUP_TIMEOUT 5120
# elif BOARD_OSC0_STARTUP_US <= 71000
# define OSC0_STARTUP_VALUE OSC_STARTUP_8192
# define OSC0_STARTUP_TIMEOUT 10240
# elif BOARD_OSC0_STARTUP_US <= 143000
# define OSC0_STARTUP_VALUE OSC_STARTUP_16384
# define OSC0_STARTUP_TIMEOUT 20480
# elif BOARD_OSC0_STARTUP_US <= 285000
# define OSC0_STARTUP_VALUE OSC_STARTUP_32768
# define OSC0_STARTUP_TIMEOUT 40960
# else
# error BOARD_OSC0_STARTUP_US is too high
# endif
# if BOARD_OSC0_IS_XTAL == true
# define OSC0_MODE_VALUE OSC_MODE_XTAL
# if BOARD_OSC0_HZ < 2000000
# define OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(0)
# elif BOARD_OSC0_HZ < 4000000
# define OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(1)
# elif BOARD_OSC0_HZ < 8000000
# define OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(2)
# elif BOARD_OSC0_HZ < 16000000
# define OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(3)
# else
# define OSC0_GAIN_VALUE ((0x1u << 4) | SCIF_OSCCTRL0_GAIN(0))
# endif
# else
# define OSC0_MODE_VALUE OSC_MODE_EXTERNAL
# endif
#else
# if defined(BOARD_OSC0_HZ)
# error BOARD_OSC0_STARTUP_US must be defined by the board code
# endif
# ifdef __DOXYGEN__
# define OSC0_STARTUP_VALUE UNDEFINED
# define OSC0_STARTUP_TIMEOUT UNDEFINED
# define OSC0_MODE_VALUE UNDEFINED
# endif
#endif
#if defined(BOARD_OSC32_STARTUP_US)
# if BOARD_OSC32_STARTUP_US == 0
# define OSC32_STARTUP_VALUE OSC32_STARTUP_0
# elif BOARD_OSC32_STARTUP_US <= 1100
# define OSC32_STARTUP_VALUE OSC32_STARTUP_128
# elif BOARD_OSC32_STARTUP_US <= 72300
# define OSC32_STARTUP_VALUE OSC32_STARTUP_8192
# elif BOARD_OSC32_STARTUP_US <= 143000
# define OSC32_STARTUP_VALUE OSC32_STARTUP_16384
# elif BOARD_OSC32_STARTUP_US <= 570000
# define OSC32_STARTUP_VALUE OSC32_STARTUP_65536
# elif BOARD_OSC32_STARTUP_US <= 1100000
# define OSC32_STARTUP_VALUE OSC32_STARTUP_131072
# elif BOARD_OSC32_STARTUP_US <= 2300000
# define OSC32_STARTUP_VALUE OSC32_STARTUP_262144
# elif BOARD_OSC32_STARTUP_US <= 4600000
# define OSC32_STARTUP_VALUE OSC32_STARTUP_524288
# else
# error BOARD_OSC32_STARTUP_US is too high
# endif
# if BOARD_OSC32_IS_XTAL == true
# define OSC32_MODE_VALUE OSC32_MODE_XTAL
# else
# define OSC32_MODE_VALUE OSC32_MODE_EXTERNAL
# endif
#else
# if defined(BOARD_OSC32_HZ)
# error BOARD_OSC32_STARTUP_US must be defined by the board code
# endif
# ifdef __DOXYGEN__
# define OSC32_STARTUP_VALUE UNDEFINED
# define OSC32_STARTUP_TIMEOUT UNDEFINED
# define OSC32_MODE_VALUE UNDEFINED
# endif
#endif
// Use 4 MHz frequency range for RCFAST oscillator if config was empty.
#ifndef CONFIG_RCFAST_FRANGE
#define CONFIG_RCFAST_FRANGE 0
#endif
/**
* \name Board-specific configuration parameters
* The following definitions must be provided by the board code for all
* working oscillators on the board.
*/
//@{
/**
* \def BOARD_OSC0_HZ
* \brief Clock frequency of OSC0 in Hz
*/
/**
* \def BOARD_OSC0_STARTUP_US
* \brief Startup time of OSC0 in microseconds
*/
/**
* \def BOARD_OSC0_IS_XTAL
* \brief OSC0 uses a crystal, not an external clock
*/
/**
* \def BOARD_OSC32_HZ
* \brief Clock frequency of OSC32 in Hz
*/
/**
* \def BOARD_OSC32_STARTUP_US
* \brief Startup time of OSC32 in microseconds
*/
/**
* \def BOARD_OSC32_IS_XTAL
* \brief OSC32 uses a crystal, not an external clock
*/
/**
* \def BOARD_OSC32_SELCURR
* \brief Crystal current selection for OSC32
*
* If not defined, the recommended value (300nA) are used.
*/
#ifndef BOARD_OSC32_SELCURR
# define BOARD_OSC32_SELCURR BSCIF_OSCCTRL32_SELCURR(10)
#endif
/**
* \name RC oscillator frequency limits
* The frequency of the internal RC oscillators may drift a bit as a
* result of temperature changes. These definitions provide upper and
* lower limits which may be used to calculate upper and lower limits of
* timeouts, derived clock frequencies, etc.
*/
//@{
//! Nominal frequency of RCSYS in Hz
#define OSC_RCSYS_NOMINAL_HZ 115000
//! Minimum frequency of RCSYS in Hz
#define OSC_RCSYS_MIN_HZ 100000
//! Maximum frequency of RCSYS in Hz
#define OSC_RCSYS_MAX_HZ 120000
//! Nominal frequency of RC32K in Hz
#define OSC_RC32K_NOMINAL_HZ 32768
//! Minimum frequency of RC32K in Hz
#define OSC_RC32K_MIN_HZ 20000
//! Maximum frequency of RC32K in Hz
#define OSC_RC32K_MAX_HZ 44000
//! Nominal frequency of RC80M in Hz
#define OSC_RC80M_NOMINAL_HZ 80000000
//! Nominal frequency of RCFAST4M in Hz
#define OSC_RCFAST4M_NOMINAL_HZ 4000000
//! Nominal frequency of RCFAST8M in Hz
#define OSC_RCFAST8M_NOMINAL_HZ 8000000
//! Nominal frequency of RCFAST12M in Hz
#define OSC_RCFAST12M_NOMINAL_HZ 12000000
//! Nominal frequency of RC1M in Hz
#define OSC_RC1M_NOMINAL_HZ 1000000
//@}
#ifndef __ASSEMBLY__
#include <compiler.h>
extern void osc_priv_enable_osc0(void);
extern void osc_priv_disable_osc0(void);
extern void osc_priv_enable_osc32(void);
extern void osc_priv_disable_osc32(void);
extern void osc_priv_enable_rc32k(void);
extern void osc_priv_disable_rc32k(void);
extern void osc_priv_enable_rc80m(void);
extern void osc_priv_disable_rc80m(void);
extern void osc_priv_enable_rcfast(void);
extern void osc_priv_disable_rcfast(void);
extern void osc_priv_enable_rc1m(void);
extern void osc_priv_disable_rc1m(void);
static inline void osc_enable(uint8_t id)
{
switch (id) {
#ifdef BOARD_OSC0_HZ
case OSC_ID_OSC0:
osc_priv_enable_osc0();
break;
#endif
#ifdef BOARD_OSC32_HZ
case OSC_ID_OSC32:
osc_priv_enable_osc32();
break;
#endif
case OSC_ID_RC32K:
osc_priv_enable_rc32k();
break;
case OSC_ID_RC80M:
osc_priv_enable_rc80m();
break;
case OSC_ID_RCFAST:
osc_priv_enable_rcfast();
break;
case OSC_ID_RC1M:
osc_priv_enable_rc1m();
break;
case OSC_ID_RCSYS:
/* RCSYS is always running */
break;
default:
/* unhandled_case(id); */
break;
}
}
static inline void osc_disable(uint8_t id)
{
switch (id) {
#ifdef BOARD_OSC0_HZ
case OSC_ID_OSC0:
osc_priv_disable_osc0();
break;
#endif
#ifdef BOARD_OSC32_HZ
case OSC_ID_OSC32:
osc_priv_disable_osc32();
break;
#endif
case OSC_ID_RC32K:
osc_priv_disable_rc32k();
break;
case OSC_ID_RC80M:
osc_priv_disable_rc80m();
break;
case OSC_ID_RCFAST:
osc_priv_disable_rcfast();
break;
case OSC_ID_RC1M:
osc_priv_disable_rc1m();
break;
case OSC_ID_RCSYS:
/* RCSYS is always running */
break;
default:
/* unhandled_case(id); */
break;
}
}
static inline bool osc_is_ready(uint8_t id)
{
switch (id) {
#ifdef BOARD_OSC0_HZ
case OSC_ID_OSC0:
return !!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_OSC0RDY);
#endif
#ifdef BOARD_OSC32_HZ
case OSC_ID_OSC32:
return !!(BSCIF->BSCIF_PCLKSR & BSCIF_PCLKSR_OSC32RDY);
#endif
case OSC_ID_RC32K:
return !!(BSCIF->BSCIF_RC32KCR & (BSCIF_RC32KCR_EN));
case OSC_ID_RC80M:
return !!(SCIF->SCIF_RC80MCR & (SCIF_RC80MCR_EN));
case OSC_ID_RCFAST:
return !!(SCIF->SCIF_RCFASTCFG & (SCIF_RCFASTCFG_EN));
case OSC_ID_RC1M:
return !!(BSCIF->BSCIF_RC1MCR & (BSCIF_RC1MCR_CLKOE));
case OSC_ID_RCSYS:
/* RCSYS is always ready */
return true;
default:
/* unhandled_case(id); */
return false;
}
}
static inline uint32_t osc_get_rate(uint8_t id)
{
switch (id) {
#ifdef BOARD_OSC0_HZ
case OSC_ID_OSC0:
return BOARD_OSC0_HZ;
#endif
#ifdef BOARD_OSC32_HZ
case OSC_ID_OSC32:
return BOARD_OSC32_HZ;
#endif
case OSC_ID_RC32K:
return OSC_RC32K_NOMINAL_HZ;
case OSC_ID_RC80M:
return OSC_RC80M_NOMINAL_HZ;
case OSC_ID_RCFAST:
if (CONFIG_RCFAST_FRANGE == 2) {
return OSC_RCFAST12M_NOMINAL_HZ;
} else if (CONFIG_RCFAST_FRANGE == 1) {
return OSC_RCFAST8M_NOMINAL_HZ;
} else {
return OSC_RCFAST4M_NOMINAL_HZ;
}
case OSC_ID_RC1M:
return OSC_RC1M_NOMINAL_HZ;
case OSC_ID_RCSYS:
return OSC_RCSYS_NOMINAL_HZ;
default:
/* unhandled_case(id); */
return 0;
}
}
#endif /* !__ASSEMBLY__ */
//! @}
#ifdef __cplusplus
}
#endif
#endif /* CHIP_OSC_H_INCLUDED */