时钟分频器:
(1)偶数分频(占空比50%)
(2)奇数分频(占空比50%)
(3)非整数分频(占空比非50%)
(1)偶数分频(假设分频 N=6)
使用计数器创造偶数分频
RTL文件如下:
module pll6 #(parameter N=6)(
input clk,
input rst_n,
output clk_6);
reg [3:0] countl;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
countl<=0;
else if (countl<=N-2)
countl<=countl+1'b1;
else
countl<=0;
end
assign clk_6=(countl<=N/2-1'b1)?1:0;
endmodule
tb文件如下:
module tb();
reg clk;
reg rst_n;
wire clk_6;
parameter period=20;//50Mhz
pll6 u1(
.clk(clk),
.rst_n(rst_n),
.clk_6(clk_6));
initial
begin
clk=0;
rst(32'd60);
forever #(period/2) clk=~clk;
end
task rst(
input[31:0] rst_time);
begin
rst_n=0;
#rst_time rst_n=1;
end
endtask
endmodule
(2)奇数分频
1、也可以使用与偶数分频相同的方法,但是无法产生50%占空比的输出(7分频)
2、产生具有50%占空比的奇数分频时钟最简单的方式是以输出频率的一半生成两个正交相位时钟(两个时钟之间有90度相位差),然后将两个波形异或得到输出时钟(以N=3为例)
(1)产生两个6分频且相位差有90度的时钟(一个使用上升沿产生6分频信号,一个使用下降沿产生6分频信号)
(2)对两个时钟进行异或处理,产生3分频目标时钟
重点:
(1)上升沿在计数值为0时翻转
(2)下降沿在计数值为(N+1)/2时翻转
这样就可以产生两个正交相位时钟,之后异或即可。
RTL代码如下:
module pll_3#(parameter N=3)(
input clk,
input rst_n,
output pll_3);
reg [3:0] cnt1;
reg pll6_1;
reg pll6_2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt1<=4'h0;
else if(cnt1==N-1)
cnt1<=4'h0;
else
cnt1<=cnt1+1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
pll6_1<=1'b0;
else if(cnt1==0)
pll6_1<=~pll6_1;
end
always@(negedge clk or negedge rst_n)
begin
if(!rst_n)
pll6_2<=1'b0;
else if(cnt1==N-1)
pll6_2<=~pll6_2;
end
assign pll_3=pll6_1^pll6_2;
endmodule
tb文件如下:
module tb();
reg clk;
reg rst_n;
wire pll_3;
parameter period=20;//50Mhz
pll_3 u1(
.clk(clk),
.rst_n(rst_n),
.pll_3(pll_3));
initial
begin
clk=0;
rst(32'd60);
forever #(period/2) clk=~clk;
end
task rst(
input[31:0] rst_time);
begin
rst_n=0;
#rst_time rst_n=1;
end
endtask
endmodule
(3)非整数分频(非50%占空比)
1、产生(N=1.5)的分频时钟
注意:3处同样产生上升沿。
借鉴之前的3分频代码:
module pll_3#(parameter N=3)(
input clk,
input rst_n,
output reg pll_1);
reg [3:0] cnt1;
wire pll_3;
wire clk1;
reg pll6_1;
reg pll6_2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt1<=4'h0;
else if(cnt1==N-1)
cnt1<=4'h0;
else
cnt1<=cnt1+1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
pll6_1<=1'b0;
else if(cnt1==0)
pll6_1<=~pll6_1;
end
always@(negedge clk or negedge rst_n)
begin
if(!rst_n)
pll6_2<=1'b0;
else if(cnt1==N-1)
pll6_2<=~pll6_2;
end
assign pll_3=pll6_1^pll6_2;
assign clk1=pll_3?clk:~clk;
always@(posedge clk1)
begin
if(!rst_n)
pll_1<=1'b0;
else
pll_1<=pll_1^1'b1;
end
endmodule
tb文件如下:
module tb();
reg clk;
reg rst_n;
wire pll_1;
parameter period=20;//50Mhz
pll_3 u1(
.clk(clk),
.rst_n(rst_n),
.pll_1(pll_1));
initial
begin
clk=0;
rst(32'd60);
forever #(period/2) clk=~clk;
end
task rst(
input[31:0] rst_time);
begin
rst_n=0;
#rst_time rst_n=1;
end
endtask
endmodule
很明显,这种方法可能会由于多路器的输出不能马上改变,导致在输出时钟上产生毛刺(即3处产生毛刺),随着参考时钟频率增加,这种情况可能越高。
2、使用移位寄存器产生4.5倍分频的实现(非50%占空比),对非整数分频电路进行优化,使输出时钟不含毛刺
(1)使用复位值为000000001的9位移位寄存器,在时钟上升沿使移位寄存器循环左移一位。
(2)产生4.5倍分频的第一个脉冲,将在半周期移位第1位并将之与第1位与第2位进行或操作(占空比40%)
(3)产生4.5倍分频的第二个脉冲,第5位和第6位在半周期时移动并与第6位进行或操作
RTL代码:
module pll_4_5(
input clk,
input rst_n,
output pll_4_5);
reg [9:1] shift_reg;
wire cnt1;
wire cnt2;
reg cnt1_180;
reg cnt5_180;
reg cnt6_180;
wire cnt6;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
shift_reg<=9'b0000_00001;
else
shift_reg<={shift_reg[8:1],shift_reg[9]};
end
assign cnt1=shift_reg[1];
assign cnt2=shift_reg[2];
assign cnt6=shift_reg[6];
always@(negedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt1_180<=1'b0;
cnt5_180<=1'b0;
cnt6_180<=1'b0;
end
else
begin
cnt1_180<=shift_reg[1];
cnt5_180<=shift_reg[5];
cnt6_180<=shift_reg[6];
end
end
assign pll_4_5=(cnt1|cnt1_180|cnt2)|(cnt5_180|cnt6_180|cnt6);
endmodule
tb文件如下:
module tb();
reg clk;
reg rst_n;
wire pll_4_5;
parameter period=20;//50Mhz
pll_4_5 u1(
.clk(clk),
.rst_n(rst_n),
.pll_4_5(pll_4_5));
initial
begin
clk=0;
rst(32'd60);
forever #(period/2) clk=~clk;
end
task rst(
input[31:0] rst_time);
begin
rst_n=0;
#rst_time rst_n=1;
end
endtask
endmodule
3、基于LUT的组合反馈的电路,并且产生不含毛刺的时钟
(例如N=1.5,基于查找表实现)(利用A,B作为寄存器的输出正好差一个周期,利用与非门产生一个时钟周期的正脉冲,在产生两个时钟周期的0)