A common FPGA chip, like the Cyclone-series from Intel (formerly Altera), include PLL-blocks that can be used to generate a high frequency clock, referenced to a crystal oscillator at lower frequency. The high frequency oscillator of the PLL block is probably a ring oscillator, consisting of a lot of inverters in cascade, connected in to out, in order to get an oscillation at several hundred MHz that is the subject to phase-lock and subsequent frequency division. (See the data sheet for the chip TLC2933 which is likely very similar to the PLL implemented in the Intel FPGAs. And here is a nice ring-oscillator with discrete gates. )
For most applications this is great, but in some cases the frequency resolution is not good enough. And, which is of more importance, for some applications the jitter / phase noise of the internal PLL is not as good as what one would want. Those applications could be RF / analog / mixed signal related, like when clocking a high speed ADC.
However, it is possible to use an external voltage controlled oscillator (VCO) and some other analog parts while implementing the digital blocks of a PLL as logic in the FPGA:
The frequency dividers needed for main and reference path are readily synthesized as counters that are reset at some arbitrary division number. And a phase-frequency detector (PFD) with two flip-flops and an AND-gate for reset is also simple to implement:
library ieee; use ieee.std_logic_1164.ALL; use ieee.std_logic_unsigned.ALL; use ieee.numeric_std.ALL; entity pfd is port (fvco : in std_logic; fref : in std_logic; up : inout std_logic; down : inout std_logic; reset_out : out std_logic; reset_in : in std_logic ); end pfd; architecture pfd_arch of pfd is signal q_up, q_down : std_logic; begin reset_out <= q_up and q_down; up <= '0' when q_up = '1' else 'Z'; -- neg polarity down <= '1' when q_down = '1' else 'Z'; -- neg polarity --up <= '1' when q_up = '1' else 'Z'; -- pos polarity --down <= '0' when q_down = '1' else 'Z'; -- pos polarity ff1 : process(fvco,reset_in) begin if reset_in = '1' then q_down <= '0'; elsif fvco'event and fvco = '1' then q_down <= '1'; end if; end process; ff2 : process(fref,reset_in) begin if reset_in = '1' then q_up <= '0'; elsif fref'event and fref = '1' then q_up <= '1'; end if; end process; end pfd_arch;
The purpose of the delay in the reset path is to eliminate the “dead-zone” problem. This arises in the lock-state where the very small phase error will result in pulses of so short duration that they don’t even get out of the chip. This then mutes the PFD at small phase errors, i.e. it creates a dead zone. With a delay in the reset path there is a minimum time where both the up and the down impulse is present so that any difference of the duration of these also can propagate through. An asynchronous delay is not easily synthesized in an FPGA but the VHDL code above solves this problem by providing a reset path out from and then into the module. These signals are routed to physical pins of the device and hence guarantee a small but still substantial delay.
Note in the code above that the up and down outputs are configured as “inout” and switched between input/tri-state (‘Z’) and high/low level. This effectively forms a balanced charge pump when they see an active loop filter:
At lock state, the voltage at the negative terminal of the opamp is fixed to half the 3.3V rail voltage. The two resistors at the FPGA pins shall be of equal size, say 1kOhm. A high or low level driven on any of these pins then pump a charge of 1.65V/1kOhm = 1.65 mA into the opamp integrator.
This picture below, from a spectrum analyzer, shows two superimposed traces of a signal at 65 MHz. The one with the higher noise floor is the FPGA internal PLL-block. Note that it has quite a lot of noise at high offsets from the carrier. The other trace is from the design described in this post/article. Here the wide offset noise lies below the spectrum analyzer noise floor. The two spikes are reference spurrs at 500 kHz offset, that should be possible to get rid of with a little more effort put into the loop filter, on a carefully designed PCB layout (see the ugly proto below).
The close in noise is another matter, which is hard to analyze with just a spectrum analyzer, and is highly dependant on the Q in the VCO-resonator (and hence the tunable frequency range), as well as the used active device, cleanliness of the voltage supply etc.
Here is a semi-complete schematic and a pic of the prototype, using a cheap Cyclone IV experiment board. (Phase noise of the internal PLL has also been measured to similar levels on Cyclone II and Cyclone 10LP.)
Note that the VCO frequency is driven into the FPGA through a 74AUC1GU04 inverter buffer. This is critical since the FPGA needs a proper square wave for its edge triggered logic.