A PLL Mystery
November 4, 2010 Leave a comment
In a previous post I built a phase-locked loop (PLL) in which parts of the loop was implemented by a microcontroller. Some microcontrollers (MCUs) have an on-board PLL for generating their CPU clock. In particular, can we generate frequencies that are spaced fairly closely, say 8kHz apart? Many MCUs have PLLs that can generate frequencies that are about 1MHz apart. But how about closer spacing?
When I received an mbed kit with an LPC1768 MCU, I discovered something interesting in the user manual of the ‘1768. It has a PLL that generates the CPU clock. The reference clock for the PLL can be either a high-frequency crystal oscillator (12MHz on the mbed), or a 32kHz crystal oscillator. In principle, this might allow the generation of closely-spaced frequencies. You can even divide the 32kHz clock down first, to generate frequencies that are, say, 8192Hz apart.
Reading the manual more carefully revealed that the PLL effectively has two modes. In both modes, the PLL output frequency is
Fout = (2 × M × Fin) / N
The output must be between 275 and 550MHz. It must be then divided to produce a CPU frequency of 100MHz or less. The value N is an integer between 1 and 32. The value M is also an integer. It can assume any value between 6 and 512, plus 65 specific values between 4272 and 24170. When Fin=32kHz, only the 65 large M’s are relevant; smaller M do not allow Fout to reach the minimum value of 275MHz.
Why 65 specific values rather than any 15-bit value? I could not think of a reason. If arbitrary values work, then I would be able to generate closely-spaced CPU frequencies. For example, by using Fin=32kHz and N=1, values of M between 4197 and 8390 generate valid output frequencies, spaced 64kHz apart. Division by 6 to bring the PLL’s output frequencies below 100Mhz leads to CPU frequencies of 46MHz and 92MHz, spaced 11kHz apart. To obtain lower CPU frequencies we can divide by more than 6, say by 12, which will lead to even finer spacing.
Does it work? No. I wrote a program to test this. What I discovered is that the PLL works fine with the 65 values of M that are specified in the user manual, but not with other values. I am really stumped by this. The user manual indeed says that other values won’t work, but I can’t figure out why. The 65 valid values don’t have a common divisor; they seem to be arbitrary. Too bad. If somebody knows what’s the PLL structure that allows only these 65 values to work, let me know; I’m curious.
A few words about the mbed kit. It is an interesting concept, designed to make it as easy as possible to get started with embedded programming. The kit is a printed-circuit board that is designed to plug into a breadboard. The board contains a microcontroller, some associated components (a 32kHz crystal and a 12MHz oscillator, for example), and a custom interface chip. The interface chip has a USB interface and is programmed to appear to the USB host as a storage device. You copy a binary file containing an LPC1768 program to the storage device. The next time you press the reset button, the interface chip downloads the program to the ‘1768 though a JTAG interface. This setup allows this to download programs to the microcontroller without installing any driver on your PC; this is pretty cool. The mbed website contains an on-line compiler. You author your program in a web browser. When you are done, you click on a button and the web site compiles the program and the browser downloads the binary program. So you don’t even need to install a compiler on your PC. Again, pretty cool.
Thanks to Pete Cooper who ported some of the mbed support code to gcc, I was also able to compile programs for the mbed on my laptop (using Code Sourcery’s free G++ Lite Edition build of gcc and it’s tools).