Introduction
PLL stands for Phase Locked Loop and is used to generate clock pulse given a reference clock input which is generally from a crystal oscillator(or XTAL). Configuring and using PLL in lpc124x MCUs is pretty simple and straight forward.
Lpc214x MCUs have 2 PLL blocks viz. PPL0 and PLL1. PLL0 is used to generate the System Clock which goes to CPU and on-chip peripherals while PPL1 is strictly for USB. PLL interrupts are only available for PLL0 and not for PLL1. Input clock to both the PLLs must be between 10Mhz to 25Mhz strictly. This input clock is multiplied with a suitable multiplier and scaled accordingly. But here we have a upper limit of 60Mhz which is the maximum frequency of operation for lpc214x MCUs. PLLs also contain CCOs i.e current controlled oscillators which we are not much concerned about … atleast in the case of lpc214x MCUs. CCOs operate in range of 156Mhz to 320Mhz and there is also a divider to force CCOs to remain in their range.
Basics
Lets define some symbols which are used in Datasheet and also which I’ll be using in this tutorial :
FOSC | => frequency from the crystal oscillator(XTAL)/external clock |
FCCO | => frequency of the PLL Current Controlled Oscillator(CCO) |
CCLK | => PLL output frequency (CPU Clock) |
M | => PLL Multiplier value from the MSEL bits in the PLLCFG register |
P | => PLL Divider value from the PSEL bits in the PLLCFG register |
PCLK | => Peripheral Clock which is derived from CCLK |
[Table 1]
- CCLK = M x FOSC
-
=or=
- CCLK = FCCO / (2 x P)
CCO output clock is given by:
- FCCO = CCLK x 2 x P
-
=or=
- FCCO = FOSC x M x 2 x P
Note from Datasheet:
- FOSC is in the range of 10 MHz to 25 MHz.
- CCLK is in the range of 10 MHz to Fmax (the maximum allowed frequency for the microcontroller – determined by the system microcontroller is embedded in).
- FCCO is in the range of 156 MHz to 320 MHz.
Setting-up and using PLL
Here we’ll be focusing on PLL0. We’ll see PLL1 some other day since its not required at this moment. Explaining the internal working of PLLs and CCOs in detail is not in the scope of this tutorial. Here we are just concerned about its usage rather than knowing its internals. To play with PLLs we are given a Multiplier and a Divider which decide the output frequency/clock form PLL block. But we must play cautiously with PLLs since the CPU and other MCU peripherals operate on the clock provided buy it. So if PLL is deliberately or accidentally miss-configured the MCU may go nuts! Miss configuring it deliberately is the sole responsibility of the user and not us ;P Now .. to handle the accident part .. we have a got a FEED Sequence which needs to be issued whenever we wanna configure PPL. You can visualize this by imagining PLL to be enclosed in a safe or a locker. To access PLL we need to have a key to open the safe in order to use or configure it. The key here is the ‘Feed Sequence’. Feed Sequence is nothing but assignment of 2 particular ‘fixed’ values to a register related to the PLL block. This register is called ‘PLL0FEED’. And those fixed values are 0xAA and 0x55 are ‘in order’!. Hence the code for feed sequence must be :
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
Now , lets see the other PLL Registers we can use:
2)PLLxCGF: The multiplier and divider values are stored in this register. The 1st 5 bits (called MSEL) are used to store the Multiplier(M). Next 2 bits i.e 5,6 (called PSEL) are used to store the value of the Divider(P).
3)PLLxSTAT: This is a read only register and contains current status of PLL enable , connect , M and P values. You can read more about the bits in datasheet – page #37. We are more interested in the 10th bit of PLLxSTAT since it contains the lock status. When we setup and enable the PLL it takes a while for PLL to latch on the target frequency. After PLL has latched or locked to target frequency this bit becomes 1. Only after this we can connect PLL to the CPU. Hence , we need to wait for PLL to lock on to target frequency.
- Setup PLL
- Apply Feed Sequence
- Wait for PLL to lock and then Connect PLL
- Apply Feed Sequence
Note that we have to apply Feed Sequence strictly as mentioned above.
Calculating PLL0 Settings
- Select the CPU Frequency. This selection may be based many factors and end application. On Chip peripheral devices may be running on a lower clock than the processor.
- Choose an oscillator frequency (FOSC). CCLK must be the whole (non-fractional) multiple of FOSC. Which leaves us with a few values of Xtal for the selected CPU frequency (CCLK).
- Calculate the value of M to configure the MSEL bits. M = CCLK / FOSC. M must be in the range of 1 to 32. The value written to the MSEL bits in PLLCFG is M – 1.
- Find a value for P to configure the PSEL bits, such that FCCO is within its defined frequency limits. FCCO is calculated using the equation given above. P must have one of the values 1, 2, 4, or 8.
Values of PSEL for P are :
P | Value(binary) in PSEL Bit(5,6) |
1 | 00 |
2 | 01 |
4 | 10 |
8 | 11 |
[Table 2]
Now , Since there is no point in running the MCU at lower speeds than 60Mhz (except in some situations) ill put a table giving values for M and P for different crystal frequencies i.e FOSC.
How did I get that ? Here’s how : Since we want FCCO in range 156Mhz to 320Mhz first substitute FCCO = 156 and we get P = 1.3. Now substituting the maximum value for FCCO i.e 320Mhz we get P = 2.67. Now , P must be an integer between 1.3 and 2.67. So we will use P=2.
FOSC | M | Value in MSEL (M-1) | P | Value in PSEL | Final Value in PLL0CFG |
5Mhz | 12 | 11 = [0xB] | 2 | 01 | 0x2B |
10Mhz | 6 | 5 = [0x5] | 2 | 01 | 0x25 |
12Mhz | 5 | 4 = [0x4] | 2 | 01 | 0x24 |
15Mhz | 4 | 3 = [0x3] | 2 | 01 | 0x23 |
20Mhz | 3 | 2 = [0x2] | 2 | 01 | 0x22 |
[Table 3]
Setting-up Peripheral Clock (PCLK)
The Peripheral Clock i.e. PCLK is derived from CPU Clock i.e. CCLK. The APB Divider decides the operating frequency of PCLK. The input to APB Divider is CCLK and output is PCLK.
By Default PCLK runs at 1/4th the speed of CCLK. To control APB Divider we have a register called VPBDIV. The value in VPBDIV controls the division of CCLK to generate PCLK as shown below:
VPBDIV=0x00; | APB bus clock (PCLK) is one fourth of the processor clock (CCLK) |
VPBDIV=0x01; | APB bus clock (PCLK) is the same as the processor clock (CCLK) |
VPBDIV=0x02; | APB bus clock (PCLK) is one half of the processor clock (CCLK) |
VPBDIV=0x03; | Reserved. If this value is written to the APBDIV register, it has no effect (the previous setting is retained). |
Example
Now , lets make it more simple and write a code to run MCU @ 60Mhz (CCLK,PCLK) when input clock from Crystal is 12Mhz (which is.. in most cases). If your development board has crystal of another frequency , then in that case , you need to change the values for multiplier(M) and divider(P) accordingly as per the equations.
/*
(c) Umang Gajera - www.ocfreaks.com
This e.g. shows how to set up , initialize
and connect PLL0 to get CCLK & PCLK @ 60Mhz
Assumption : Input freq of 12MHZ from Crystal.
*/
#define PLOCK 0x400 //10th bit = 1
#include <lpc214x.h>
void setupPLL0(void);
void feedSeq(void);
void connectPLL0(void);
int main(void)
{
setupPLL0();
feedSeq(); //sequence for locking PLL to desired freq.
connectPLL0();
feedSeq(); //sequence for connecting the PLL as system clock
//SysClock is now ticking @ 60Mhz!
VPBDIV = 0x01; // PCLK is same as CCLK i.e 60Mhz
while(1);
//return 0;
}
void setupPLL0(void)
{
PLL0CON = 0x01; // PPLE=1 & PPLC=0 so it will be enabled
// but not connected after FEED sequence
PLL0CFG = 0x24; // set the multipler to 5 (i.e actually 4)
// i.e 12x5 = 60 Mhz (M - 1 = 4)!!!
// Set P=2 since we want FCCO in range!!!
// So , Assign PSEL =01 in PLL0CFG as per the table.
}
void feedSeq(void)
{
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
}
void connectPLL0(void)
{
// check whether PLL has locked on to the desired freq by reading the lock bit
// in the PPL0STAT register
while( !( PLL0STAT & PLOCK ));
// now enable(again) and connect
PLL0CON = 0x03;
}