实验框图与波形图
当实现一个N分频的模块(N为偶数),当复位信号无效时,每个时钟上升沿到来时,计数器cnt便开始计数(注意,计数器0也占用一个时钟周期),数值依次累加1,直到计数器cnt等于N/2-1时,对输出信号取反,便实现了一个基础的偶分频模块功能。
module divider_six
(
input wire sys_clk,
input wire sys_rst_n,
output reg clk_out
);
reg [2:0] cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=2'd0;
else if (cnt==2'd2)
cnt<=2'd0;
else cnt<=cnt+2'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
clk_out<=1'd0;
else if(cnt==2'd2)
clk_out<=~clk_out;
else clk_out<=clk_out;
endmodule
按照偶分频的思想,当计数器到一半取反时,会发现计数器为2.5并且向下取整为2,这将导致分频后的时钟不能保持50%的占空比。
步骤1:
增加两个变量clk_out1与clk_out2,当sys_clk上升沿并且cnt为2的时候,拉高clk_out1,当cnt为4时拉低信号clk_out1,其余时刻保持不变。同时当sys_clk下降沿时重复操作,得到clk_out2。
步骤2:
对采集到的clk_out1与clk_out2进行或操作,便可以得到占空比为50%的clk_out3,实现实验目标。
module divider_five
(
input wire sys_clk,
input wire sys_rst_n,
output wire clk_out
);
reg [3:0] cnt;
reg clk_out1;
reg clk_out2;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
clk_out1<=1'd0;
else if(cnt==3'd2)
clk_out1<=~clk_out1;
else if(cnt==3'd4)
clk_out1<=~clk_out1;
else clk_out1<=clk_out1;
always@(negedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
clk_out2<=1'd0;
else if(cnt==3'd2)
clk_out2<=~clk_out2;
else if(cnt==3'd4)
clk_out2<=~clk_out2;
else clk_out2<=clk_out2;
assign clk_out=(clk_out1|clk_out2);//这里的输出信号采用组合逻辑赋值,就不会延迟一个时钟周期
endmodule
当要实现一个N分频的模块,我们可以直接让计数器cnt计数到N-1,在系统时钟上升沿拉高一个周期的高电平,此时得到的就算降频后的信号。
//divider_six
module divider_six
(
input wire sys_clk,
input wire sys_rst_n,
output reg clk_flag
);
reg [2:0] cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=3'd0;
else if (cnt==3'd5)
cnt<=3'd0;
else cnt<=cnt+3'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
clk_flag<=1'b0;
else if(cnt==3'd4)
clk_flag<=1'b1;
else clk_flag<=1'b0;
endmodule
//divider_five
module divider_five
(
input wire sys_clk,
input wire sys_rst_n,
output reg clk_flag
);
reg [3:0] cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=3'd0;
else if(cnt==3'd4)
cnt<=3'd0;
else cnt<=cnt+3'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
clk_flag<=1'b0;
else if(cnt==3'd3)
clk_flag<=1'b1;
else clk_flag<=1'b0;
endmodule
可以看到无论是奇分频还是偶分频此时输出都是一个标志信号,而且编写格式相同并且不用考虑占空比的问题。
分频调用,直接使用输出信号作为后续模块时钟
//分频调用
always@(posedge clk_out or negedge sys_rst_n)
if(sys_rst_n==1'b0)
a<=1'b0;
else a<=a+1'b1;
降频调用,使用系统时钟,当标志信号来临时后续信号才产生变化
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
a<=1'b0;
else if(clk_flag==1'b1)
a<=a+1'b1;
第二种方式的信号是在系统时候的控制下,相对于第一种对时钟控制更为严格。
在高速系统设计中,尽量采用降频方式,其中涉及到了全局时钟树的概念,简单来说,降频可以保证更低的时钟偏移skew和抖动jitter。其中所谓的时钟偏移,指的是从同一时钟源发出的时钟脉冲,通过不同的路径到达每个触发器的时间不同而产生的偏差称为时钟偏移。
总之:降频优于分频方式。