Thursday, November 25, 2010

Using the PLL on LPC17xx

The Phase Locked Loop is a peripheral on the LPC17xx that can be used to obtain various frequencies from the frequency sources available. It can multiply and divide the reference frequency to obtain a wide range of CPU frequencies. This tutorial describes how PLL0 can be used.

The need: Most 8-bit controllers, the Atmega series in particular run at frequencies below 25 Mhz for which crystals are readily available. But beyond 30 Mhz, it is exceedingly hard to manufacture crystals. LPC17xx devices can work upto 100 Mhz. To obtain such frequencies, a PLL is needed. A low frequency crystal oscillator is used to provide an accurate and stable reference frequency and this is fed to the PLL which can do wonders and produce a wide range of frequencies.

From the programmer's point of view, the PLL0 (there are 2 PLL's) looks like this. CCLK refers to the clock frequency at which the CPU runs.
Most often, a 12 Mhz crystal is used. This is because the USB PLL needs to generate 48 Mhz for USB Clock and 12 Mhz , 16 Mhz, and 24 Mhz are the most convenient alternatives.

For the purpose of illustration, lets say we want the CPU to run at 85.90908Mhz. How do we go about computing M,N and CCLKSEL ?

Step 1: We find Fcco - the frequency at which the current controlled oscillator of the PLL runs has to be in the range 275 to 550Mhz.

85.90908 x 1 = 85.90908 Mhz . This cant be used as Fcco as its out of range
85.90908 x 2 = 171.8181 Mhz . This cant be used as Fcco as its out of range
85.90908 x 3 = 257.7272 Mhz . This cant be used as Fcco as its out of range
85.90908 x 4 = 343.63632 Mhz . Bingo ! We can use this as Fcco and set CCLKSEL so as to divide Fcco by 4 to give CCLK.

Higher values, i.e.. x5 , x6 also work. But these aren't our first choice because lower Fcco lowers power consumption. If we cant produce this Fcco from Fin(described in step 2) accurately enough, then some higher value of Fcco has to be tried.

Step 2: Now that we've settled on Fcco. We need to find M and N to get Fcco from Fin. This can be tedious and to make things easy, NXP has provided this wonderful spreadsheet .This will allow us to rapidly choose the best M and N. Enter Fin , the target Fcco chosen above and the divide override to the value selected above (4). A list of possible M and N values with the error corresponding to each is computed and listed. Select the M & N pair which has the lowest error.

If the accuracy is not good enough, then go back to step 1 and try some other Fcco. Repeat this till you get a good enough CPU Clock. If you cant get it for any Fcco, then you may have to consider using a different crystal.

Now that we've computed Post Divider , M and N. We subtract one to obtain M-1 , N-1 and CCLKSEL = Post divider - 1.
Open system_LPC17xx.c and change the values accordingly.

For this example , M -1  = 315 - 1 = 0x13A
N - 1= 22 - 1 = 0x15
CCLKSEL = 4 - 1 = 3 = 0x03
Illustration of modification to be made to System_LPC17xx.c

If you need a decimal to hex converter, here is one.
The starter code is here. To get the latest files on tutorials, go here.

More examples are in the NXP LPC17xx manual.Its described in chapter 4 : Clocking and Power Control( Page 43 ). A lot more options, like choosing the frequency source are available and may be explored if needed.

PLL1 works similar to PLL0 but is more restricted in functionality. If you happen to be running the CPU at a multiple of 48Mhz, then you dont need PLL1 and can derive USB Clock from the CPU clock directly. This saves power.Look the register description and examples in the manual to see how this can be done.

I've not explained the manner in which registers (PLLFEED , PLLCON etc..) have to be written because the start-up code in system_LPC17xx.c does the job for us. Just change the values of the constants as shown in the figure above and the effect will have taken place. All the clock, PLL settings are set before entering the main() function.

12 comments:

  1. How I can test my CPU at which frequency it is running? Or where I can find this?

    ReplyDelete
  2. In system_LPC17xx.c, the values of the registers that control the PLL are presented conveniently using the #define macro.

    If you're looking for run-time freq determination, then reading these registers( see the pic above ) will help.

    Knowing the XTAL freq, u can determine the CPU freq.

    ReplyDelete
  3. I was having some problem getting PLL0 to the desired frequency (coincidentally the same frequency in your example!). I quickly found my error of not subtracting one from the divisors. And by then, I had discovered the clock system peripheral debug window in my Keil uVision debugger. Well, no matter how many times I checked, the debugger value kept reporting a strange CCLK frequency, nothing close to what I expected.

    Finally, I did a sanity check and actually measured some pulse widths, and found out that my CCLK was exactly correct, just the debugger window was wrong! I downloaded a Keil update, and now everything agrees... whew...

    I'm thinking about trying Fcb x32, (instead of x24) and using the LPC1769 processor. Any thoughts?

    ReplyDelete
  4. for some reason, I can't post on your blog using my google account - I get stuck in an infinite loop of entering my login information.

    ReplyDelete
  5. You must be Chris.

    I'm not sure why you cant comment with your account. If there's something I can do about it, let me know.

    If you find it more comfortable, we could continue this discussion in some forum.

    I had tried Fcb x32 ( 114 something MHz ) on LPC1768 ( OC'ed) and the results were quite decent.

    Well, it really depends on how you are trying to do things. If you're (ab)using SPI and giving out only chroma, then you get more colors( 16 versus 12 pure colors) at x32 but the same crappy resolution ( 160x240 ).

    If you're using DMA to blast luma to GPIO, the resolution will increase. At x24, the max I got was 256x240 which is the same as NES and SNES. At x32, 320x240 can be obtained.

    During my experiments, I found that with timer triggered DMA transfers to GPIO, the GPDMA needed a minimum of 15-16 CPU cycles to write to the GPIO port. So, the maximum pixel rate you get this way is CCLK / 16.

    320x240 may seem better, but the chroma is severely limited in NTSC and you're not going to see much difference with 256x240. In addition to that, rendering 320 pixels translates to more computations. So the increased CCLK only balances that out.

    Speaking from a more practical view point, the mbed has LPC1768 in it. So, a lot more people can try out NTSC, possibly with your technique and perhaps with your code if you work on LPC1768.

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Thanks a lot for the explanation, the theory and calculations are very well understood by me. However, practical implementation has to be started yet. Will get back to you once I need some help!

    ReplyDelete
  8. Thanks for it, Really nice description

    ReplyDelete
  9. Thank you very much for this article! I've been trying to wrap my head around the user manual PLL0 section and twisting my brain in knots. This is so much simpler to understand. And now I know how to properly use the spreadsheet. Thanks again!!

    ReplyDelete
  10. Thanks a lot. I changed from LPC1114 and had another horror reading NXP pdf again. Worst documentation ever. Thank you for your work.

    ReplyDelete
  11. Thank you for the explanation and excel sheet.

    I am writing code for UART referring to some examples. In the examples, there is continuous reference to "SystemCoreClock". I searched all the 'Include' files but invain.
    Kindly suggest.
    Also suggest which register should be read to determine the value of cpu clock directly.

    Regards,
    Dhaval

    ReplyDelete
    Replies
    1. It's defined as uint32_t SystemCoreClock = __CORE_CLK;

      In a line just above the fucntion void SystemCoreClockUpdate (void)

      in file, system_lpc17xx.c , it is a variable storing the CPU clock .

      Delete