/*
* @brief LPC5410X PLL driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __PLL_5410X_H_
#define __PLL_5410X_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup PLL_5410X CHIP: LPC5410X PLL Driver
* @ingroup CHIP_5410X_DRIVERS
* The PLL in the LPC5410x is flexible, but can be complex to use. This driver
* provides functions to help setup and use the PLL in it's various supported
* modes.
*
* This driver does not alter PLL clock source or system clocks outside the
* PLL (like the main clock source) that may be referenced from the PLL. It
* may optionally setup system voltages, wait for PLL lock, and power cycle
* the PLL during setup based on setup flags.
*
* The driver works by first generating a PLL setup structure from a desired
* PLL configuration structure. The PLL setup structure is then passed to the
* PLL setup function to setup the PLL. In a user spplication, the PLL setup
* structure can be pre-populated with PLL setup data to avoid using the PLL
* configuration structure (or multiple PLL setup structures can be used to
* more dynamically control PLL output rate).
*
* How to use this driver
@verbatim
// Setup PLL configuration
PLL_CONFIG_T pllConfig = {
75000000, // desiredRate = 75MHz
0, // InputRate = 0Hz (not used)
0 // No flags, function will determine best setup to get closest rate
};
// Get closest PLL setup to get the desired configuration
PLL_SETUP_T pllSetup;
uint32_t actualPllRate;
PLL_ERROR_T pllError;
pllError = Chip_Clock_SetupPLLData(&pllConfig, &pllSetup, &actualPllRate);
if (pllError != PLL_ERROR_SUCCESS) {
printf("PLL setup error #%x\r\n", (uint32_t) pllError);
while (1);
}
else {
printf("PLL config successful, actual config rate = %uHz\r\n", actualPllRate);
}
// Make sure main system clock is not using PLL, as the PLL setup
// function will power off and optionally power on the PLL
Chip_Clock_SetMainClockSource(SYSCON_MAINCLKSRC_IRC);
// Setup PLL source
Chip_Clock_SetSystemPLLSource(SYSCON_PLLCLKSRC_IRC);
// Now to apply the configuration to the PLL
pllSetup.flags = PLL_SETUPFLAG_WAITLOCK;
Chip_Clock_SetupSystemPLLPrec(&pllSetup);
// Switch main system clock to PLL
Chip_Clock_SetMainClockSource(SYSCON_MAINCLKSRC_PLLOUT);
@endverbatim
*
* @{
*/
/**
* Clock sources for system PLLs
*/
typedef enum CHIP_SYSCON_PLLCLKSRC {
SYSCON_PLLCLKSRC_IRC = 0, /*!< Internal oscillator */
SYSCON_PLLCLKSRC_CLKIN, /*!< External clock input pin */
SYSCON_PLLCLKSRC_WDTOSC, /*!< WDT oscillator */
SYSCON_PLLCLKSRC_RTC, /*!< RTC 32KHz oscillator */
} CHIP_SYSCON_PLLCLKSRC_T;
/**
* @brief Set System PLL clock source
* @param src : Clock source for system PLL
* @return Nothing
* @note The PLL should be pwoered down prior to changing the source.
*/
STATIC INLINE void Chip_Clock_SetSystemPLLSource(CHIP_SYSCON_PLLCLKSRC_T src)
{
LPC_SYSCON->SYSPLLCLKSEL = (uint32_t) src;
}
/**
* @brief Return System PLL input clock rate
* @return System PLL input clock rate
*/
uint32_t Chip_Clock_GetSystemPLLInClockRate(void);
/**
* @brief Return System PLL output clock rate
* @param recompute : Forces a PLL rate recomputation if true
* @return System PLL output clock rate
* @note The PLL rate is cached in the driver in a variable as
* the rate computation function can take some time to perform. It
* is recommended to use 'false' with the 'recompute' parameter.
*/
uint32_t Chip_Clock_GetSystemPLLOutClockRate(bool recompute);
/**
* @brief Enables and disables PLL bypass mode
* @brief bypass : true to bypass PLL (PLL output = PLL input, false to disable bypass
* @return System PLL output clock rate
*/
void Chip_Clock_SetBypassPLL(bool bypass);
/**
* @brief Check if PLL is locked or not
* @return true if the PLL is locked, false if not locked
*/
STATIC INLINE bool Chip_Clock_IsSystemPLLLocked(void)
{
return (bool) ((LPC_SYSCON->SYSPLLSTAT & 1) != 0);
}
/** @brief PLL configuration structure flags for 'flags' field
* These flags control how the PLL configuration function sets up the PLL setup structure.
*
* When the PLL_CONFIGFLAG_USEINRATE flag is selected, the 'InputRate' field in the
* configuration structure must be assigned with the expected PLL frequency. If the
* PLL_CONFIGFLAG_USEINRATE is not used, 'InputRate' is ignored in the configuration
* function and the driver will determine the PLL rate from the currently selected
* PLL source. This flag might be used to configure the PLL input clock more accurately
* when using the WDT oscillator or a more dyanmic CLKIN source.
*
* When the PLL_CONFIGFLAG_FORCENOFRACT flag is selected, the PLL hardware for the
* automatic bandwidth selection, Spread Spectrum (SS) support, and fractional M-divider
* are not used.
*/
#define PLL_CONFIGFLAG_USEINRATE (1 << 0) /*!< Flag to use InputRate in PLL configuration structure for setup */
#define PLL_CONFIGFLAG_FORCENOFRACT (1 << 2) /*!< Force non-fractional output mode, PLL output will not use the fractional, automatic bandwidth, or SS hardware */
/** @brief PLL Spread Spectrum (SS) Programmable modulation frequency
* See (MF) field in the SYSPLLSSCTRL1 register in the UM.
*/
typedef enum {
SS_MF_512 = (0 << 20), /*!< Nss = 512 (fm ˜ 3.9 - 7.8 kHz) */
SS_MF_384 = (1 << 20), /*!< Nss ˜= 384 (fm ˜ 5.2 - 10.4 kHz) */
SS_MF_256 = (2 << 20), /*!< Nss = 256 (fm ˜ 7.8 - 15.6 kHz) */
SS_MF_128 = (3 << 20), /*!< Nss = 128 (fm ˜ 15.6 - 31.3 kHz) */
SS_MF_64 = (4 << 20), /*!< Nss = 64 (fm ˜ 32.3 - 64.5 kHz) */
SS_MF_32 = (5 << 20), /*!< Nss = 32 (fm ˜ 62.5- 125 kHz) */
SS_MF_24 = (6 << 20), /*!< Nss ˜= 24 (fm ˜ 83.3- 166.6 kHz) */
SS_MF_16 = (7 << 20) /*!< Nss = 16 (fm ˜ 125- 250 kHz) */
} SS_PROGMODFM_T;
/** @brief PLL Spread Spectrum (SS) Programmable frequency modulation depth
* See (MR) field in the SYSPLLSSCTRL1 register in the UM.
*/
typedef enum {
SS_MR_K0 = (0 << 23), /*!< k = 0 (no spread spectrum) */
SS_MR_K1 = (1 << 23), /*!< k = 1 */
SS_MR_K1_5 = (2 << 23), /*!< k = 1.5 */
SS_MR_K2 = (3 << 23), /*!< k = 2 */
SS_MR_K3 = (4 << 23), /*!< k = 3 */
SS_MR_K4 = (5 << 23), /*!< k = 4 */
SS_MR_K6 = (6 << 23), /*!< k = 6 */
SS_MR_K8 = (7 << 23) /*!< k = 8 */
} SS_PROGMODDP_T;
/** @brief PLL Spread Spectrum (SS) Modulation waveform control
* See (MC) field in the SYSPLLSSCTRL1 register in the UM.
* Compensation for low pass filtering of the PLL to get a triangular
* modulation at the output of the PLL, giving a flat frequency spectrum.
*/
typedef enum {
SS_MC_NOC = (0 << 26), /*!< no compensation */
SS_MC_RECC = (2 << 26), /*!< recommended setting */
SS_MC_MAXC = (3 << 26), /*!< max. compensation */
} SS_MODWVCTRL_T;
/** @brief PLL configuration structure
* This structure can be used to configure the settings for a PLL
* setup structure. Fill in the desired configuration for the PLL
* and call the PLL setup function to fill in a PLL setup structure.
*/
typedef struct {
uint32_t desiredRate; /*!< Desired PLL rate in Hz */
uint32_t InputRate; /*!< PLL input clock in Hz, only used if PLL_CONFIGFLAG_USEINRATE flag is set */
uint32_t flags; /*!< PLL configuration flags, Or'ed value of PLL_CONFIGFLAG_* definitions */
SS_PROGMODFM_T ss_mf; /*!< SS Programmable modulation frequency, only applicable when not using PLL_CONFIGFLAG_FORCENOFRACT flag */
SS_PROGMODDP_T ss_mr; /*!< SS Programmable frequency modulation depth, only applicable when not using PLL_CONFIGFLAG_FORCENOFRACT flag */
SS_MODWVCTRL_T ss_mc; /*!< SS Modulation waveform control, only applicable when not using PLL_CONFIGFLAG_FORCENOFRACT flag */
bool mfDither; /*!< false for fixed modulation frequency or true for dithering, only applicable when not using PLL_CONFIGFLAG_FORCENOFRACT flag */
} PLL_CONFIG_T;
/** @brief PLL setup structure flags for 'flags' field
* These flags control how the PLL setup function sets up the PLL
*/
#define PLL_SETUPFLAG_POWERUP (1 << 0) /*!< Setup will power on the PLL after setup */
#define PLL_SETUPFLAG_WAITLOCK (1 << 1) /*!< Setup will wait for PLL lock, implies the PLL will be pwoered on */
#define PLL_SETUPFLAG_ADGVOLT (1 << 2) /*!< Optimize system voltage for the new PLL rate */
/** @brief PLL setup structure
* This structure can be used to pre-build a PLL setup configuration
* at run-time and quickly set the PLL to the configuration. It can be
* populated with the PLL setup function. If powering up or waiting
* for PLL lock, the PLL input clock source should be configured prior
* to PLL setup.
*/
typedef struct {
uint32_t flags; /*!< PLL setup flags, Or'ed value of PLL_SETUPFLAG_* definitions */
uint32_t SYSPLLCTRL; /*!< PLL control register */
uint32_t SYSPLLNDEC; /*!< PLL NDEC register */
uint32_t SYSPLLPDEC; /*!< PLL PDEC register */
uint32_t SYSPLLSSCTRL[2]; /*!< PLL SSCTL registers */
} PLL_SETUP_T;
/** @brief PLL status definitions
*/
typedef enum {
PLL_ERROR_SUCCESS = 0, /*!< PLL operation was successful */
PLL_ERROR_OUTPUT_TOO_LOW, /*!< PLL output rate request was too low */
PLL_ERROR_OUTPUT_TOO_HIGH, /*!< PLL output rate request was too high */
PLL_ERROR_INPUT_TOO_LOW, /*!< PLL input rate is too low */
PLL_ERROR_INPUT_TOO_HIGH, /*!< PLL input rate is too high */
PLL_ERROR_OUTSIDE_INTLIMIT /*!< Requested output rate isn't possible */
} PLL_ERROR_T;
/**
* @brief Return System PLL output clock rate from setup structure
* @param pSetup : Pointer to a PLL setup structure
* @return System PLL output clock rate the setup structure will generate
*/
uint32_t Chip_Clock_GetSystemPLLOutFromSetup(PLL_SETUP_T *pSetup);
/**
* @brief Set PLL output based on the passed PLL setup data
* @param pControl : Pointer to populated PLL control structure to generate setup with
* @param pSetup : Pointer to PLL setup structure to be filled
* @return PLL_ERROR_SUCCESS on success, or PLL setup error code
* @note Actual frequency for setup may vary from the desired frequency based on the
* accuracy of input clocks, rounding, non-fractional PLL mode, etc.
*/
PLL_ERROR_T Chip_Clock_SetupPLLData(PLL_CONFIG_T *pControl, PLL_SETUP_T *pSetup);
/**
* @brief Set PLL output from PLL setup structure (precise frequency)
* @param pSetup : Pointer to populated PLL setup structure
* @return PLL_ERROR_SUCCESS on success, or PLL setup error code
* @note This function will power off the PLL, setup the PLL with the
* new setup data, and then optionally powerup the PLL, wait for PLL lock,
* and adjust system voltages to the new PLL rate. The function will not
* alter any source clocks (ie, main systen clock) that may use the PLL,
* so these should be setup prior to and after exiting the function.
*/
PLL_ERROR_T Chip_Clock_SetupSystemPLLPrec(PLL_SETUP_T *pSetup);
/**
* @brief Set PLL output based on the multiplier and input frequency
* @param multiply_by : multiplier
* @param input_freq : Clock input frequency of the PLL
* @return Nothing
* @note Unlike the Chip_Clock_SetupSystemPLLPrec() function, this
* function does not disable or enable PLL power, wait for PLL lock,
* or adjust system voltages. These must be done in the application.
* The function will not alter any source clocks (ie, main systen clock)
* that may use the PLL, so these should be setup prior to and after
* exiting the function.
*/
void Chip_Clock_SetupSystemPLL(uint32_t multiply_by, uint32_t input_freq);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __PLL_5410X_H_ */