pll_5410x.h 12.8 KB
Newer Older
hillcode's avatar
hillcode 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
/*
 * @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.<br>
 *
 * 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).
 *
 * <b>How to use this driver</b><br>
   @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.<br>
 *
 * 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.<br>
 *
 * 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.<br>
 */
#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.<br>
 * 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_ */