转载自https://blog.csdn.net/moon9999/article/details/75020355/
偶分频模块设计较为简单,首先确定分频系数M和计数器值N:
M = 时 钟 输 入 频 率 时 钟 输 出 频 率 M = \frac{时钟输入频率}{时钟输出频率} M=时钟输出频率时钟输入频率 N = M 2 N = \frac{M}{2} N=2M
若输入时钟是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
奇分频需要通过两个时钟共同得到,首先得到分频系数M和计数器值N:
M = 时 钟 输 入 频 率 时 钟 输 出 频 率 M = \frac{时钟输入频率}{时钟输出频率} M=时钟输出频率时钟输入频率 N = M − 1 2 N = \frac{M-1}{2} N=2M−1
如输入时钟为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
在verilog程序设计中,我们往往要对一个频率进行任意分频,而且占空比也有一定的要求这样的话,对于程序有一定的要求。
现在在前面两个实验的基础上做一个简单的总结,实现对一个频率的任意占空比的任意分频。
比如: FPGA系统时钟是50M Hz,而我们要产生的频率是880Hz,那么,我们需要对系统时钟进行分频。很容易想到用计数的方式来分频:50000000/880 = 56818。
显然这个数字不是2的整幂次方,那么我们可以设定一个参数,让它到56818的时候重新计数就可以实现了。程序如下:
1 //rtl
2 module div(
3 clk,
4 rst_n,
5 clk_div
6 );
7 input clk,rst_n;
8 output clk_div;
9 reg clk_div;
10
11 reg [15:0] counter;
12
13 always @(posedge clk or negedge rst_n)
14 if(!rst_n)
15 counter <= 0;
16 else if(counter==56817)
17 counter <= 0;
18 else
19 counter <= counter+1;
20
21 assign clk_div = counter[15];
22 endmodule
分频的应用很广泛,一般的做法是先用高频时钟计数,然后使用计数器的某一位输出作为工作时钟进行其他的逻辑设计,上面的程序就是一个体现。
下面我们来算一下它的占空比:
我们清楚地知道,这个输出波形在counter为0到32767(2的14次方)的时候为低,在32768到56817的时候为高,占空比为40%多一些,如果我们需要占空比为50%,那么我们需要再设定一个参数,使它为56817的一半,使达到它的时候波形翻转,就可以实现结果了。
程序如下:28408=56818/2-1,计数到28408就清零,翻转,其余的计数期间,保持不变。
设计代码:
1 //rtl
2 module div(
3 clk,
4 rst_n,
5 clk_div
6 );
7 input clk,rst_n;
8 output clk_div;
9 reg clk_div;
10 reg [14:0] counter;
11 always @(posedge clk or negedge rst_n)
12 if(!rst_n)
13 counter <= 0;
14 else if(counter==28408)
15 counter <= 0;
16 else
17 counter <= counter+1;
18
19 always @(posedge clk or negedge rst_n)
20 if(!rst_n)
21 clk_div <= 0;
22 else if(counter==28408)
23 clk_div <= ~clk_div;
24 endmodule
继续让我们来看如何实现任意占空比,比如还是由50M分频产生880Hz,而分频得到的信号的占空比为30%。
56818×30%=17045
设计代码:
1 //rtl
2 module div(
3 clk,
4 rst_n,
5 clk_div,
6 counter
7 );
8 input clk,rst_n;
9 output clk_div;
10 reg clk_div;
11 output [15:0] counter;
12 reg [15:0] counter;
13
14 always @(posedge clk)
15 if(!rst_n)
16 counter <= 0;
17 else if(counter==56817)
18 counter <= 0;
19 else counter <= counter+1;
20
21 always @(posedge clk)
22 if(!rst_n)
23 clk_div <= 0;
24 else if(counter<17045)
25 clk_div <= 1;
26 else
27 clk_div <= 0;
28 endmodule