奇、偶、半整数 分频(除频器)- verilog
0赞
奇、偶、半整数 分频(除频器)- verilog
对于时钟比较多的设计,单纯的用PLL分频、倍频,恐怕难以达到设计的要求,比如SPI、I2C的典型时钟分别1MHz、100KHz。在FPGA内部用全局时钟分频则相对比较实用,可移植性好。下面针对奇数分频、偶数分频、半分频分别做介绍。
参考阅读
http://www.cnblogs.com/oomusou/archive/2008/07/31/verilog_clock_divider.html
http://blog.chinaaet.com/detail/37309
http://www.cnblogs.com/crazybingo/archive/2011/07/26/2117162.html
1、偶数分频
偶数分频相对比较简单--占空比50%,
verilog代码:
//1 偶分频
//偶分频比较简单,假设为N分频,只需计数到N/2-1,然后时钟翻转、计数清零,如此循环就可以得到N(偶)分频。代码如下。
//可以通过改变参量N的值和计数变量cnt的位宽实现任意偶分频。
module fp_even(clk_out,clk_in,rst);
input clk_in;
input rst;
output clk_out;
reg [1:0] cnt;
reg clk_out;
parameter N=6;
always @ (posedge clk_in or negedge rst)
begin
if(!rst)
cnt <= 0;
else if(cnt==N/2-1)
cnt<=0;
else
cnt <= cnt + 1;
end
always @ (posedge clk_in or negedge rst)
begin
if(!rst)
clk_out <= 0;
else if(cnt==N/2-1)
clk_out <= !clk_out;
else
clk_out <= clk_out;
end
endmodule
其硬件结构为一个计数器+比较器(清零)、一个比较器+逻辑取反的非门、触发器。
针对代码中的6分频,分析如下:
计数器计数0 1 2 3 4 5 其中0 1 2为低电平,3 4 5为高电平,达到6分频的目的。
testbench
`timescale 1 ns/ 1 ns module fp_even_vlg_tst(); reg clk_in; reg rst; // wires wire clk_out; // assign statements (if any) fp_even i1 ( // port map - connection between master ports and signals/registers .clk_in(clk_in), .clk_out(clk_out), .rst(rst) ); initial begin clk_in=0; forever #5 clk_in = ~clk_in; end initial begin rst=0; #100; rst=1; #1000; $stop; end endmodule
RTL仿真波形图
2、奇数分频
奇数分频--占空比50%,
verilog代码:
//2 奇分频
// 实现奇数(N)分频,分别用上升沿计数到(N-1)/2,再计数到N-1;用下降沿计数到(N-1)/2,再计数到N-1,得到两个波形,然后把它们相或即可得到N分频。代码如下:
module fp_odd(clk_out,clk_p,clk_n,clk_in,rst);
input clk_in,rst;
output clk_out;
output clk_p;
output clk_n;
reg [2:0] cnt_p,cnt_n;
reg clk_p,clk_n;
parameter N=5;
always@(posedge clk_in or negedge rst)
begin
if(!rst)
cnt_p <= 0;
else if(cnt_p==N-1)
cnt_p <=0;
else
cnt_p <= cnt_p + 1;
end
always@(posedge clk_in or negedge rst)
begin
if(!rst)
clk_p <= 0;
else if(cnt_p==(N-1)/2)
//clk_p <= !clk_p;
clk_p <= 1'b1;
else if(cnt_p==N-1)
//clk_p <= !clk_p;
clk_p <= 1'b0;
end
always@(negedge clk_in or negedge rst)
begin
if(!rst)
cnt_n <= 0;
else if(cnt_n==N-1)
cnt_n <=0;
else
cnt_n <= cnt_n + 1;
end
always@(negedge clk_in or negedge rst)
begin
if(!rst)
clk_n <= 0;
else if(cnt_n==(N-1)/2)
//clk_n <= !clk_n;
clk_n <= 1'b1;
else if(cnt_n==N-1)
//clk_n <= !clk_n;
clk_n <= 1'b0;
end
assign clk_out = clk_p | clk_n;
endmodule
其硬件结构为计数器+比较器+触发器+逻辑门。
针对代码中的5分频,分析如下:
posedge下分频,低电平的数目比高电平多一个时钟周期,比如5分频计数器计数0 1 2 3 4 其中0 1 2为低电平,3 4 为高电平。
同理,negedge下分频,低电平的数目比高电平多一个时钟周期,比如5分频计数器计数0 1 2 3 4 其中0 1 2为低电平,3 4 为高电平。
最后将两个时钟相'或'
testbench:
`timescale 1 ns/ 1 ns module fp_odd_vlg_tst(); reg clk_in; reg rst; // wires wire clk_out; wire clk_p; wire clk_n; // assign statements (if any) fp_odd i1 ( // port map - connection between master ports and signals/registers .clk_in(clk_in), .clk_n(clk_n), .clk_out(clk_out), .clk_p(clk_p), .rst(rst) ); initial begin clk_in=0; forever #5 clk_in = ~clk_in; end initial begin rst=0; #100; rst=1; #1000; $stop; end endmoduleRTL 仿真波形
3、半整数分频
半整数分频--占空比50%,
verilog代码:
//半整数分频器
//
//假设一个10Mhz的时钟信号,想要得到4Mhz的频率,分频系数为2.5。
//
/*该分频器设计方法:设计一个模3计数器,再设计一个脉冲扣除电路,每来3个时钟周期时,扣除半个周期,
即可实现分频系数为2.5的半整数分频。采用类似方法,可实现任意半整数的分频器。
如下图所示,采用异或门和2分频模块设计出脉冲扣除电路,脉冲扣除是输入频率和2分频输出相异或的结果。
*/
////http://blog.chinaaet.com/detail/37309
`timescale 1ns/1ns
module FDIV2_5
(
clk,
rst_n,
mod_cnt,
clk_out
);
input clk;
input rst_n;
output clk_out;
output mod_cnt;
wire clk;
wire rst_n;
wire clk_out;
reg [3:0] mod_cnt;
wire clk_out1;
//xor xor1(OUT,IN1,IN2);
//assign = out = IN1^IN2;
//xor xor1(clk_out1,clk,fb_clk);
reg fb_clk;
assign clk_out1 = clk ^ fb_clk;
localparam N=2; //2.5 模N计数器
reg clk_out2;
always@(posedge clk_out1 or negedge rst_n)
begin
if(!rst_n)
mod_cnt<=0;
else if(mod_cnt==N)
mod_cnt<=0;
else
mod_cnt<=mod_cnt+1'b1;
end
always@(posedge clk_out1 or negedge rst_n)
begin
if(!rst_n)
begin
// mod_cnt<=0;
clk_out2<=1'b0;
end
else if(mod_cnt==N)
begin
// mod_cnt<=0;
clk_out2<=1'b1;
end
else
begin
// mod_cnt<=mod_cnt+1'b1;
clk_out2<=1'b0;
end
end
always@(posedge clk_out2 or negedge rst_n)
begin
if(!rst_n)
fb_clk<=1'b0;
else
fb_clk<=~fb_clk;
end
wire clk_out_r;
assign clk_out_r=(mod_cnt==1) ? 1'b0:1'b1;
//assign clk_out=clk_out2 | clk_out_r;
assign clk_out=clk_out2;
endmodule
其硬件单元为 异或门、计数器、触发器、比较器、非门。
针对代码中的2.5分频,分析如下:
首先利用输入激励clk异或门产生clk_out1,clk_out1作为下一级分频器的激励产生clk_out2,clk_out2作为非门and触发器的激励产生fd_clk,最后输出clk_out2(clk_out)。
testbench:
`timescale 1 ns/ 1 ps
module FDIV2_5_vlg_tst();
// constants
reg clk;
reg rst_n;
// wires
wire clk_out;
wire [3:0] mod_cnt;
// assign statements (if any)
FDIV2_5 i1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.clk_out(clk_out),
.mod_cnt(mod_cnt),
.rst_n(rst_n)
);
initial
begin
clk=1;
forever #5 clk = ~clk;
end
initial
begin
rst_n=0;
#100;
rst_n=1;
#1000;
$stop;
end
endmodule
RTL仿真波形图:
4、最后带你们回味一下大牛的任意分频:
连接http://www.cnblogs.com/crazybingo/archive/2011/07/26/2117162.html
verilog代码:
/*************************************************** * Module Name : clk_generator * Engineer : Crazy Bingo * Target Device : EP2C8Q208C8 * Tool versions : Quartus II 9.1SP1 * Create Date : 2011-6-25 * Revision : v1.0 * Description : **************************************************/ /************************************************* fc = 50MHz 50*10^6 fo = fc*K/(2^32) N=(2^32) 32bit couter K = fo*(2^32)/fc = fo*(2^32)/(50*10^6) **************************************************/ module all_fre_div ( input clk, //50MHz input rst_n, //clock reset output reg clk_out ); parameter FREQ_WORD = 32'h8000_0000; //2分频 占空比50% //-------------------------------------- reg [31:0] max_value; //N 32Bit always@(posedge clk or negedge rst_n) begin if(!rst_n) max_value <= 1'b0; else max_value <= max_value + FREQ_WORD; // K end //-------------------------------------- always@(posedge clk or negedge rst_n) begin if(!rst_n) clk_out <= 1'b0; else begin if(max_value < 32'h7FFF_FFFF) //100Hz clk_out <= 1'b0; else clk_out <= 1'b1; end end endmodule
详细了解请根据上面对应链接看便知。
永远忠诚于梦想 -- 小伟。
