全数字锁相环25 全数字锁相环FPGA实现的总结在本设计中的⼀阶全数字锁相环使⽤Mentor公司的ModelSim6.0软件进⾏设计的功能仿真以及Altera公司的QuartusII7.2软件时序仿真并且进⾏设计综合,并采⽤Altera的cyclone系列的EP1C6Q240C8 FPGA器件实现。
实验测试结果表明:本设计中DPLL时钟可达到10MHz,性能较⾼;⽽使⽤了256逻辑单元,占⽤资源很少。
下⾯给出详细描述全数字锁相环的⼯作过程。
(1)当环路失锁时,异或门鉴相器⽐较输⼊信号(fin)和输出信号(fout)之间的相位差异,并产⽣K变模可逆计数器的计数⽅向控制信号(dnup);(2) K变模可逆计数器根据计数⽅向控制信号(dnup)调整计数值,dnup为⾼进⾏减计数,并当计数值到达0时,输出借位脉冲信号(borrow);为低进⾏加计数,并当计数值达到预设的K模值时,输出进位脉冲信号(carryo);(3)脉冲加减电路则根据进位脉冲信号(carryo)和借位脉冲信号(borrow)在电路输出信号(idout)中进⾏脉冲的增加和扣除操作,来调整输出信号的频率;(4)重复上⾯的调整过程,当环路进⼊锁定状态时,异或门鉴相器的输出se为⼀占空⽐50%的⽅波,⽽K变模可逆计数器则周期性地产⽣进位脉冲输出carryo和借位脉冲输出borrow,导致脉冲加减电路的输出idout周期性的加⼊和扣除半个脉冲。
本次设计中开始遇到了很多困难,开始通过多⽅⾯查找资料并了解全数字锁相环的原理及⽅案,锁相环⼀般都是模拟的居多,关于数字的资料⽐较少,所以查阅资料花了⼤量时间;在确定全数字锁相环设计原理后,开始学习硬件描述语⾔verilog HDL,学习FPGA器件的使⽤,学习Mentor公司的ModelSim6.0软件来作功能仿真以及⽤Altera公司的QuartusII7.2软件进⾏时序仿真以及下载配置的等问题。
附录1.数字锁相环的顶层模块module pll_top (fin,fout,se,clk,reset,enable,Kmode,fin_dac,fout_dac);input fin,clk; //clk时钟100ns(10MHZ)input reset,enable; //reset⾼电平复位,enable⾼电平有效input [2:0]Kmode; //滤波计数器的计数模值设定output fout; //fout是锁频锁相输出output [7:0]fin_dac,fout_dac;//fin_dac,fout_dac分别是两个输⼊输出信号经过数模dac的输出output se;wire idout,reset,ca,bo;wire [14:0]N;xormy u1(.a(fin),.b(fout),.y(se));Kcounter u2(.Kclock(clk),.reset(reset),.dnup(se),.enable(enable),.Kmode(Kmode),.carryo(ca),.borrow(bo)); IDCounter u3(.IDclock(clk),.reset(reset),.inc(ca),.dec(bo),.IDout(idout));counter_N u4(.clk(clk), .fin(fin), .reset(reset), .count_N(N));div_N u5(.clkin(idout),.n(N),.reset(reset),.clkout(fout));dac u6(.clk(fin),.dout(fin_dac),.dd());dac u7(.clk(fout),.dout(fout_dac),.dd());endmodule2.异或门鉴相器模块module xormy(a,b,y);//异或门鉴相器input a,b;output y;reg y;always @(a or b)beginy=a^b;endendmodule3.K模计数器模块module KCounter(Kclock,reset,dnup,enable,Kmode,carryo,borrow);input dnup; //鉴相器输出的加减控制信号input enable; //可逆计数器计数允许信号,⾼电平有效input [2:0]Kmode; //计数器模值设置信号output carryo; //进位脉冲输出信号output borrow; //借位脉冲输出信号wire carryo,borrow;reg [8:0]Count; //可逆计数器reg [8:0]Ktop; //预设模值寄存器//根据计数器模值设置信号Kmode来设置预设模值寄存器的值always @(Kmode)begincase(Kmode)3'b001:Ktop<=7;3'b010:Ktop<=15;3'b011:Ktop<=31;3'b100:Ktop<=63;3'b101:Ktop<=127;3'b110:Ktop<=255;3'b111:Ktop<=511;default:Ktop<=15;endcaseend//根据鉴相器输出的加减控制信号dnup进⾏可逆计数器的加减运算always @(posedge Kclock or posedge reset)beginif(reset)Count<=0;else if(enable)beginif(!dnup)beginif(Count==Ktop)Count<=0;elsebeginif(Count==0)Count<=Ktop;elseCount<=Count-1;endendend//输出进位脉冲carry和借位脉冲borrowassign carryo=enable&(!dnup)&(Count==Ktop);assign borrow=enable&dnup&(Count==0);endmodule4.脉冲增减模块module IDCounter (IDclock,reset,inc,dec,IDout);//脉冲增减模块input IDclock,reset,inc,dec;output IDout;reg IDout;reg inc_new,dec_new,inc_pulse,dec_pulse;reg delayed,advanced,Tff;always @(posedge IDclock)beginif(!inc)begininc_new<=1;inc_pulse<=0;endelse if (inc_pulse)begininc_new<=0;inc_pulse<=0;inc_pulse<=1;inc_new<=0;endelsebegininc_pulse<=0;inc_new<=0;endendalways @(posedge IDclock) beginif(!dec)begindec_new<=1;dec_pulse<=0;endelse if (dec_pulse)begindec_new<=0;dec_pulse<=0;endelse if (dec&&dec_new) begindec_pulse<=1; dec_new<=0;endelsebegindec_pulse<=0;dec_new<=0;endendbegin Tff<=0; delayed<=1;advanced<=1; end elsebeginif (inc_pulse)begin advanced<=1;Tff<=!Tff; endelse if(dec_pulse)begin delayed<=1; Tff<=!Tff; endelse if (Tff==0)beginif(!advanced)Tff<=!Tff;else if(advanced)begin Tff<=Tff; advanced<=0; endendelsebeginif (!delayed)Tff<=!Tff;else if(delayed)begin Tff<=Tff;delayed<=0; endendendendalways @(IDclock or Tff)beginif (Tff)IDout=0;elsebeginif(IDclock)IDout=0;elseendendmodule5.N分频参数控制模块module counter_N (clk, fin, reset, count_N);//利⽤clk对fin脉冲的测量并给出N值 input clk, fin, reset;output [14:0] count_N;reg [14:0] count_N;reg [15:0] cnt;reg cnt_en;reg load;wire cnt_clr;always @ (posedge fin )//fin上升沿到的时候,产⽣各种标志以便后⾯控制beginif (reset)begincnt_en=0;load=1;endelsebegincnt_en=~cnt_en;load=~cnt_en;endendassign cnt_clr=~(~fin & load);always @(posedge clk or negedge cnt_clr)beginif (!cnt_clr)cnt=0;else if (cnt_en)cnt=0;elsecnt=cnt+1;endendalways @ (posedge load)begincount_N=cnt/2; //这⾥取fin周期的⼀半endendmodule6.N分频器模块module div_N (clkin,n,reset,clkout); //N分频模块 input clkin,reset;input [14:0] n;output clkout;reg clkout;integer count;always@(posedge clkin)if(reset)beginclkout=0;count=0;endelsebeginif(count>=(n/2)-1)begin clkout<=~clkout;count<=0;endelsecount<=count+1;endendmoduleoutput[7:0] dout;output[7:0] dd;reg [7:0] dout;reg [7:0] dd;reg [7:0] d;reg [5:0] q;always @(posedge clk)beginif (q<63 ) q<=q+1; else q<=0; endalways@( q )begincase(q)00: d<=255; 01: d<=254; 02: d<=252; 03: d<=249; 04: d<=245; 05: d<=239; 06: d<=233; 07: d<=225; 08: d<=217; 09: d<=207; 10: d<=197; 11: d<=186; 12: d<=174; 13: d<=162; 14: d<=150; 15: d<=137; 16: d<=124; 17: d<=112; 18: d<=99; 19: d<=87; 20: d<=75; 21: d<=64; 22: d<=53; 23: d<=43;24: d<=34; 25: d<=26; 26: d<=19; 27: d<=13;28: d<=8; 29: d<=4; 30: d<=1; 31: d<=0;32: d<=0; 33: d<=1; 34: d<=4; 35: d<=8;36: d<=13; 37: d<=19; 38: d<=26; 39: d<=34;40: d<=43; 41: d<=53; 42: d<=64; 43: d<=75;44: d<=87; 45: d<=99; 46: d<=112; 47: d<=124; 48: d<=137; 49: d<=150; 50: d<=162; 51: d<=174; 52: d<=186; 53: d<=197; 54: d<=207; 55: d<=217; 56: d<=225; 57: d<=233; 58: d<=239; 59: d<=245; 60: d<=249; 61: d<=252; 62: d<=254; 63: d<=255; default : d<=0;endcasedd<=d;end。