目录
分频器是FPGA中常用的设计之一,在FPGA设计中担任重要的角色(时钟对于FPGA电路系统的重要性不言而喻!)。尽管大多数设计中会广泛采用厂家集成的锁相环PLL资源进行分频,倍频和相移(每个厂商Xilinx/Alter等其开发套件会提供各自的IP),但对对时钟要求不高的基本设计还是需要通过自行设计分频相移,可节省锁相环资源。
提到分频,对于初学者可定就会想到利用一个计数器才基时钟下计数,通过翻转获得想要的时钟。这样的方法的确可以实现偶数分频,但是实现奇数分频的话,一个计数器可能不够,一般需要两个计数器。
1.偶数分频
偶数分频较奇数分频更为常见,通过一个计数器就完全可以实现了。如需要N分频(N为偶数,则N/2为整数),可通过一个计数器在待分频时钟的触发下循环奇数。当计数器从0奇数至N/2 -1时,输出时钟翻转。
Verilog实现:
module even(
clk_in ,
rst_n ,
clk_out
);
input clk_in;
input rst_n;
output reg clk_out;
parameter N=6; //定义分频参数
reg [3:0] cnt;
always @(posedge clk_in or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= 4'b0000 ;
clk_out <= 1'b0 ;
end
else if(cnt==(N/2-1))
begin
clk_out <= ~clk_out;
cnt <= 4'b0000;
end
else
cnt<=cnt+1;
end
endmodule
2. 奇数分频
首先看一下3分频的时序图:
从时序图上可以看出,对于奇数分频,就是分别利用主时钟的上升沿触发生成一个时钟,然后用下降沿触发生成一组时钟,然后将两个时钟信号进行或运算得到奇数分频的结果。
如果N是奇数,那么N/2非整数了(N-1/2为整数),那么该如何实现呢?
实现方法为:
Step1: 双沿计数器计数;
使用2个计数器:cnt_up和cnt_down,分别在时钟的上升沿触发计数器cnt_up和cnt_down。
Step2:生成两个控制信号Clk_up和Clk_down;
cnt_up计数到(N-1)/2-1电平翻转信号Clk_up,再计数到N-1电平翻转信号Clk_up,同时cnt_down计数到(N-1)/2-1电平翻转信号Clk_down,再计数到N-1电平翻转信号Clk_down。
Step3: 求出分频后时钟;
如果Clk_up和Clk_down信号与Clk_out的关系与Clk_up和Clk_down信号中高低电平比有关(占空比):
(1)如果高 / 低电平比例为N-1/2 : N-1/2 + 1 ,则分频时钟 clk_div = clk_up || clk_down (如图 1 所示)。
(2)如果高 / 低电平比例为 N-1/2 +1 :N/2 ,则分频时钟 clk_div = clk_up && clk_down(如图 2 所示)。
module div3(
clk ,
rst_n ,
clk_out
);
input clk , rst_n;
output clk_out ;
//=======================================================================\
//**************************Internal Signals******************************
//=======================================================================/
reg [3:0] cnt_p , cnt_n; //clk上升沿(下降沿)触发生成的计数器cnt_p(cnt_n)
reg clk_p , clk_n; //clk上升沿(下降沿)触发生成的时钟clk_p(clk_n)
parameter N=5 ; //分频参数
//===========================================================================\
//*****************************main code************************************
//==========================================================================/
//cnt_p 0-4
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt_p <= 4'd0;
else if(cnt_p == N-1)
cnt_p <= 0;
else
cnt_p <= cnt_p + 1'b1;
end
//cnt_n 0-4
always @(negedge clk or negedge rst_n) begin
if(!rst_n)
cnt_n <= 4'd0;
else if(cnt_n == (N-1))
cnt_n <= 0;
else
cnt_n <= cnt_n + 1'b1;
end
//clk_p
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_p <= 1;
else if(cnt_p == (N-1)/2-1)
clk_p <= ~clk_p;
else if(cnt_p == (N-1))
clk_p <= ~clk_p;
end
//clk_p
always @(negedge clk or negedge rst_n) begin
if(!rst_n)
clk_n<=1;
else if(cnt_n==(N-1)/2-1)
clk_n<=~clk_n;
else if(cnt_n==(N-1))
clk_n<=~clk_n;
end
assign clk_out=clk_n|clk_p;
endmodule
3.半整数分频
半整数分频,本次以2.5分频为例子。这个主要是利用时钟的上升沿和下降沿进行计数。