最近刚刚开始学习CPLD,需要用到数字锁相环,网上找了段代码,修修改改,总感觉工作不是很正常,请有经验的朋友帮忙看下,不吝赐教。
使用的芯片是ALTRA MAX3000系列的EPM3064A 64宏单元 开发环境quartus II 编译下载能得到输出,复位也能受控。中心频率781.25KH
注释都是凭自己的理解添加的,也不知道对不对。
以下是代码:
[mw_shl_code=c,true]/*全数字锁相环verilog源代码*/
module DPLL2 (reset,clk,signal_in,signal_out,signal_out2,syn); //锁相环模块,复位 时钟 信号输入 信号输出 同步
parameter para_K=4; //模K参数
//parameter para_N=8; //模N分频参数
input reset; //复位输入端口
input clk; //时钟输入端口
input signal_in; //信号输入端口
output signal_out; //信号输出端口
output signal_out2; //信号输出反相端口
output syn; //同步信号输出端口
reg signal_out; //信号输出寄存器
reg signal_out2; //信号输出寄存器
reg dpout; //相位差信号寄存器
reg delclk; //减时钟信号寄存器
reg addclk; //加时钟信号寄存器
reg add_del_clkout; //加减时钟信号输出
reg [7:0]up_cnt; //8位二进制上下计数器
reg [7:0]down_cnt; //8位二进制上下计数器
reg [2:0]cnt8; //8分频计数器,加减脉冲分频计数器
reg [8:0]cnt_N; //N分频计数器,系统时钟经8分频(脉冲加减),再经N分频
reg syn; //同步寄存器
reg dpout_delay; //相位差信号延时,相当于上个时钟周期的时候信号输入与输出的异或值,通过判断与本次的异或值来检测上升沿或下降沿
reg [8:0]cnt_dpout_high; //异或值的高电平计数器
reg [8:0]cnt_dpout_low; //异或值的低电平计数器,当同步时输入信号与输出信号差90度,异或后的信号为1/2输入信号周期占空比50%的
//的方波信号,通过比较高电平与低电平的时间来判断是否同步。
/******phase detector*****/ //相位检测
always@(signal_in or signal_out) //信号输入或信号输出
begin
dpout<=signal_in^signal_out; //相位比较值等于信号输入与信号输出异或
end
/******synchronization establish detector*****/ //同步建立检测
always@(posedge clk or negedge reset) //在时钟上升沿或复位下降沿
begin
if(!reset) dpout_delay<='b0; //如果复位为0,输出相位差延迟等于二进制0
else dpout_delay<=dpout; //否则,输出相位比较延迟等于检测到的相位比较值,把异或值延迟一个时钟周期,用于判定异或信号的边沿
end
always@(posedge clk or negedge reset) //在时钟上升沿或复位下降沿
begin
if(!reset) //如果复位
begin
cnt_dpout_high<='b0; cnt_dpout_low<='b0; //异或值的高电平计数器为0,异或值的低电平计数器为0
//如果复位,同步信号清零
end
else if(dpout) //如果本次测试相位差为高电平
if(dpout_delay==0) //如果上次测得相位差为低电平,即异或值的上升沿
cnt_dpout_high<='b0; //异或值的高电平计数器清零,高电平计数开始
else
if(cnt_dpout_high==8'b11111111) cnt_dpout_high<='b0; //如果相位差高计数器等于255,异或值的高电平计数器清零避免数据溢出
else cnt_dpout_high<=cnt_dpout_high+1; //否则异或值的高电平计数器累加一
else if(!dpout) //如果本次次测试得到相位差为低电平
if(dpout_delay==1)
cnt_dpout_low<='b0; //如果上次测得相位差为高电平,异或值的低电平计数器等于0,低电平计数开始
else //否则
if(cnt_dpout_low==8'b11111111) cnt_dpout_low<='b0; //如果异或值的低电平计数器等于255,异或值的低电平计数器清零避免数据溢出
else cnt_dpout_low<=cnt_dpout_low+1; //否则异或值的低电平计数器累加一
end
always@(posedge clk or negedge reset) //自时钟上升沿或复位下降沿
begin
if(!reset) syn<='b0; //如果复位,同步信号清零
else if((dpout&&!dpout_delay)||(!dpout&&dpout_delay)) //如果相位差与上 相位差累计取反 或 相位差取反与上 相位差累计
if(cnt_dpout_high[8:0]-cnt_dpout_low[8:0]<=4) syn<='b1;
//else if(cnt_dpout_low[8:0]-cnt_dpout_high[8:0]<=4) syn<='b1; //如果相位差计数器高减相位差计数器低等于相位差计数器低减相位差计数器高等于4 同步信号等于1
else syn<='b0; //否则同步信号等于0 不同步
end
/****up down couter with mod=K****/ //模K加减计数器
always@(posedge clk or negedge reset) //在时钟上升沿或复位下降沿
begin
if(!reset)
begin //如果低电平复位
delclk<='b0; //减时钟等于0
addclk<='b0; //加时钟等于0
up_cnt<='b00000000; //加减计数器清零
down_cnt<='b0;
end
else //否则
begin
if(!dpout) //如果异或值为低电平
begin
delclk<='b0; //减时钟等于0
if(up_cnt==para_K-1) //如果加减计数器等于4-1,相当于计数器满,超出预设模值
begin
up_cnt<='b00000000; //加减计数器等于0,清零
addclk<='b1; //加时钟等于1,输出进位脉冲
end
else //否则
begin
up_cnt<=up_cnt+1; //加减计数器等于加减计数器加1
addclk<='b0; //加时钟等于0
end
end
else
begin
addclk<='b0; //加时钟等于0
if(down_cnt=='b0) //如果加减计数器等于0
begin
down_cnt<=para_K-1; //加减计数器等于4-1
delclk<='b0; //减时钟等于0
end
else
if(down_cnt==1) //如果加减计数器等于1
begin
delclk<='b1; //减时钟等于1,输出借位脉冲
down_cnt<=down_cnt-1; //加减计数器等于加减计数器减一
end
else
down_cnt<=down_cnt-1; //加减计数器等于加减计数器减
delclk<='b0;
end
end
end
/******add and delete clk*****/ //8分频计数器内进行加减时钟操作
always@(posedge clk or negedge reset) //在时钟上升沿或复位下降沿
begin
if(!reset) //如果复位
begin
cnt8<='b000; //8分频计数器清零
end
else
begin
if(cnt8=='b111) //8分频计数器等于7,相当于计数满。
begin
cnt8<='b000; //8分频计数器等于0,清零
end
else
if(addclk&&!syn) //如果加时钟与不同步
begin
cnt8<=cnt8+2; //8分频计数器等于8分频计数器加2(相当于减了一个脉冲) 1+1+1(+2)+1+1+1=7个CLK时间 频率升高
end
else
if(delclk&&!syn) //如果减时钟与不同步
cnt8<=cnt8; //8分频计数器值保持不变(相当于加一个脉冲)1+1+1+1+1(+1)+1+1=9个CLK时间
else
cnt8<=cnt8+1; //否则8分频计数器等于8分频计数器加一(相当于8分频计数器按正常时钟累加)1+1+1+1+1+1+1+1=8个CLK时间
end
end
always@(cnt8 or reset)
begin
if(!reset) //如果复位
add_del_clkout<='b0; //加减计数器等于0
else
add_del_clkout<=cnt8[2]; //加减计数器等于8计数器(3位)(最大值7)
end
/******counter with mod=N******/ //模N分频计数器(分频数为para—N,时钟源为posedge add_del_clkout,以及负跳变沿复位信号)
always@(posedge add_del_clkout or negedge reset) //在加减计数器上升沿或复位下降沿
begin
if(!reset) //如果复位
begin
cnt_N<='b0000; //分频计数器N等于0
signal_out<='b0; //信号输出等于0(地点平)
signal_out2<='b0;
end
else //否则
begin
if(cnt_N==7) //如果分频计数器等于15,相当于计数到了16(从0开始)
begin
cnt_N<='b0000; //分频计数器清零
signal_out<='b0; //信号输出等于低电平
signal_out2<='b1;
end
else //否则
if(cnt_N==3) //如果分频计数器等于参数16-1除以2,相当于计数到了7,即16的一半。
begin
signal_out<='b1; //信号输出等于高电平
signal_out2<='b0;
cnt_N<=cnt_N+1; //分频计数器累加1
end
else //否则
cnt_N<=cnt_N+1; //分频计数器累加一
end
end
endmodule
//DPLL由 鉴相器 模K加减计数器 脉冲加减电路 同步建立侦察电路 模N分频器 构成.
//整个系统的中心频率(即signal_in和signal_out的码速率的2倍)
//为clk/8/N. 模K加减计数器的K值决定DPLL的精度和同步建立时间,K越大,则同步建立时间长,同步精度高.反之则短,低.
[/mw_shl_code]
|