Analog PLL Design and Simulation by Verilog HDL


1. Block Diagram

2. Transfer Function



3. Web-Calculator
To calculate appropriate constant C1/C2/R1, following web-calculator is convenient.
http://geocities.com/fudinggepll/pllfilterprogram.html

In the site you can get value of C1/C2/R2 as follows.

4. Transfer Function to State Space Model

Since Veritak needs state-space model, following script (MATLAB) is used.

C2=17e-12 
C1=82e-12
R1=4667
R1C1=R1*C1;
C1_C2=C1+C2;
C1C2R1=C1*C2*R1;
b=[R1C1 1];
a=[C1C2R1 C1_C2 0];
[A,B,C,D] = tf2ss(b,a)
a2=[C1C2R1 C1_C2 0 0];
kv=200e6;
ki=260e-6;
N=32;
Gain=kv*ki/N;
W=logspace(4,9);
freqs(b*Gain,a2,W)
save 'F:\verilog\PLL\loop_filter.txt' A B C D -ascii -double


In comparison, let's try additional two cases, less phase margin of 15degree and much phase margin 75degree.
Open-loop frequency response will be as follows.

Degree 45



Degree 15



Degree 75


5. Analog Simulation

Here is a source code written by Verilog-2001

//May.6.2005 
//Analog PLL demo
`define CYCLE (1.0/13.56/2*1e6 )
`timescale 1ps/1ps

module pll_test;
        reg ref_clock=0;

        always #(`CYCLE) ref_clock=~ref_clock;


pll_module #(.File_Name("loop_filter.txt")) PLLl_1MHz (ref_clock);
pll_module #(.File_Name("loop_filter1MHz_much_phase.txt")) PLLl_1M_Much(ref_clock);
pll_module #(.File_Name("loop_filter1MHz_less_phase.txt")) PLLl_1M_Less(ref_clock);


                                                
endmodule

module pll_module #(parameter File_Name="loop_filter.txt") (input ref_clock);
        wire v_clock,d_clock;
        wire [1:0] iout;

        pfd pll1(.ref_clock(ref_clock),
                         .d_clock(d_clock),
                         .iout(iout));
        loop_filter_and_vco  #(.File_Name(File_Name)) lvco(.iout(iout),.v_clock(v_clock));
        divider #(.DRatio(16)) div(.v_clock(v_clock),.d_clock(d_clock));

endmodule

module divider  #(parameter integer DRatio=32) 
                           (    input v_clock,
                                output reg d_clock=0);
                
                integer counter=0;

                always @(posedge v_clock) begin
                        if (counter==DRatio-1) counter <=0;
                        else counter <=counter+1;                       
                end

                always @(posedge v_clock) begin
                        if (counter ==DRatio-1) d_clock<=~d_clock;
                end

endmodule

module  loop_filter_and_vco #(parameter File_Name="loop_filter.txt")
                                                 ( input signed [1:0] iout,
                                                   output  v_clock);
        
        localparam real Igain=-(-260e-6);//A
        localparam real Igminus=260e-6;
        localparam integer cycle=100;//ps
        localparam real Vco_Gain=200*1e6;//Hz/V
        localparam real Center_Frequency=200e6;//433.92e6;//Hz

        real I;
        real read_array[0:10];// Input vector for rungekutta
        real write_array[0:10];//Output vector from rugekutta
        real vco_in;
        real omega,delta_theta;
        real theta,delta_theta;
        real vco_waveform;

        always @(*) I=Igain*iout;
        
        
        always #(cycle) begin

              read_array[0]=I;// 
              $runge_kutta(File_Name,1);//Loop Filter V/I
                vco_in=write_array[0];//Get Loop Filter voltage 
                omega=2.0*(Center_Frequency+vco_in*Vco_Gain)*$M_PI;
                delta_theta=cycle*1e-12*omega;//
                theta=theta+delta_theta;
                vco_waveform=$sin(theta);//
        end
        
        assign v_clock=vco_waveform>=0 ? 1:0;
        
        initial begin
                        
                $runge_kutta(File_Name,0,read_array,write_array);//rugekutta Initialization
                #(8200*1000) $finish;
        end

endmodule

module pfd( input ref_clock,
                        input d_clock,
                        output reg signed [1:0] iout);

        integer state=0;
                always @(posedge ref_clock) state=state+1;
                always @(posedge d_clock) state=state-1;

                always @(*) begin
                                if (state>0) state=1;
                                else if (state<0) state=-1;

                                if (state>0) iout=1;
                                else if (state<0) iout=-1;
                                else    iout=0;

                end



endmodule
                        


In control theory, 45 degree of phase margin is ideal for proper settling time. That is confirmed in analog simulation by verilog-HDL.


Download verilog-source and Veritak Project File (10KB)