Verilog时钟分频模块设计详解
Verilog时钟分频模块设计详解
时钟分频是数字电路设计中的一个基本且重要的功能,广泛应用于各种电子系统中。本文将详细介绍如何使用Verilog语言实现时钟分频模块,包括偶分频、奇分频以及任意占空比的任意分频。
1 偶分频模块
偶分频模块设计较为简单,首先确定分频系数M和计数器值N:
$$
M = \frac{时钟输入频率}{时钟输出频率}
$$
$$
N = \frac{M}{2}
$$
若输入时钟是50Mhz,输出时钟是1hz,则M=50_000_000,N=25_000_000。
偶分频则意味着M是偶数。
以M=4,N=2为例,希望得到的输出时钟时序如下:
因此只需要将counter以clk_in为时钟驱动计数,当counter = (N-1)时,clk_out翻转即可。
module clock_div(
input clk,
input rst,
output reg clk_out
);
parameter N = 26'd25_000_000 , WIDTH = 25;
reg [WIDTH:0] counter;
always @(posedge clk or negedge rst) begin
if (~rst) begin
counter <= 0;
clk_out <= 0;
end
else if (counter == N-1) begin
clk_out <= ~clk_out;
counter <= 0;
end
else
counter <= counter + 1;
end
endmodule
2 奇分频模块
奇分频需要通过两个时钟共同得到,首先得到分频系数M和计数器值N:
$$
M = \frac{时钟输入频率}{时钟输出频率}
$$
$$
N = \frac{M-1}{2}
$$
如输入时钟为50M,输出时钟为10M,则M=5,N=2。
奇分频则意味着M为奇数。
以M=5,N=2为例,我们希望得到的输出时钟时序如下:
其中clk_out为最终输出时钟,clk_out1和clk_out2为辅助时钟生成。
计数器counter由0计数至(M-1)。
clk_out1在clk_in的上升延跳变,条件是counter==(N-1)或(M-1)。
clk_out2在clk_in的下降延跳变,条件是counter==(N-1)或(M-1)。
之后
clk_out = clk_out1 & clk_out2
即可得到M分频的时钟。
verilog代码如下,其中WIDTH为(N的位宽-1):
module time_adv_odd(
input clk,
input rst,
output clk_out
);
parameter N = 2,WIDTH = 7;
reg [WIDTH:0] counter;
always @(posedge clk or posedge rst) begin
if (rst) begin
// reset
counter <= 0;
end
else if (counter == (N << 1)) begin //M-1处跳变,因为 M - 1 = 2 * N,这里等于4
counter <= 0;
end
else begin
counter <= counter + 1;
end
end
reg clk_out1;
always @(posedge clk or posedge rst) begin //clk_out1在clk_in的上升延跳变
if (rst) begin
// reset
clk_out1 <= 0;
end
else if (counter == N-1) begin //N-1处跳变,这里等于1
clk_out1 <= !clk_out1;
end
else if (counter == (N << 1)) begin //M-1处跳变,这里等于4
clk_out1 <= !clk_out1;
end
end
reg clk_out2;
always @(negedge clk or posedge rst) begin //clk_out2在clk_in的下降延跳变
if (rst) begin
// reset
clk_out2 <= 0;
end
else if (counter == N-1) begin
clk_out2 <= !clk_out2;
end
else if (counter == (N << 1)) begin
clk_out2 <= !clk_out2;
end
end
assign clk_out = clk_out1 & clk_out2;
endmodule
3 任意占空比的任意分频
在verilog程序设计中,我们往往要对一个频率进行任意分频,而且占空比也有一定的要求这样的话,对于程序有一定的要求。
现在在前面两个实验的基础上做一个简单的总结,实现对一个频率的任意占空比的任意分频。
比如: FPGA系统时钟是50M Hz,而我们要产生的频率是880Hz,那么,我们需要对系统时钟进行分频。很容易想到用计数的方式来分频:50000000/880 = 56818。
显然这个数字不是2的整幂次方,那么我们可以设定一个参数,让它到56818的时候重新计数就可以实现了。程序如下:
//rtl
module div(
clk,
rst_n,
clk_div
);
input clk,rst_n;
output clk_div;
reg clk_div;
reg [15:0] counter;
always @(posedge clk or negedge rst_n)
if(!rst_n)
counter <= 0;
else if(counter==56817)
counter <= 0;
else
counter <= counter+1;
assign clk_div = counter[15];
endmodule
分频的应用很广泛,一般的做法是先用高频时钟计数,然后使用计数器的某一位输出作为工作时钟进行其他的逻辑设计,上面的程序就是一个体现。
下面我们来算一下它的占空比:
我们清楚地知道,这个输出波形在counter为0到32767(2的14次方)的时候为低,在32768到56817的时候为高,占空比为40%多一些,如果我们需要占空比为50%,那么我们需要再设定一个参数,使它为56817的一半,使达到它的时候波形翻转,就可以实现结果了。
程序如下:28408=56818/2-1,计数到28408就清零,翻转,其余的计数期间,保持不变。
设计代码:
//rtl
module div(
clk,
rst_n,
clk_div
);
input clk,rst_n;
output clk_div;
reg clk_div;
reg [14:0] counter;
always @(posedge clk or negedge rst_n)
if(!rst_n)
counter <= 0;
else if(counter==28408)
counter <= 0;
else
counter <= counter+1;
always @(posedge clk or negedge rst_n)
if(!rst_n)
clk_div <= 0;
else if(counter==28408)
clk_div <= ~clk_div;
endmodule
继续让我们来看如何实现任意占空比,比如还是由50M分频产生880Hz,而分频得到的信号的占空比为30%。
56818×30%=17045
设计代码:
//rtl
module div(
clk,
rst_n,
clk_div,
counter
);
input clk,rst_n;
output clk_div;
reg clk_div;
output [15:0] counter;
reg [15:0] counter;
always @(posedge clk)
if(!rst_n)
counter <= 0;
else if(counter==56817)
counter <= 0;
else counter <= counter+1;
always @(posedge clk)
if(!rst_n)
clk_div <= 0;
else if(counter<17045)
clk_div <= 1;
else
clk_div <= 0;
endmodule