1、代码实现的分频时钟
假如 clk_out 输出信号是我们想要的分频后的信号,然后很多人会直接把这个信号当作新的低频时钟来使用,并实现了自己想要的功能。虽然最终实现的功能是成功的,但往往忽略了一些隐患的存在,这种做法所衍生的潜在问题在低速系统中不易察觉,而在高速系统中就很容易出现问题。
因为我们通过这种方式分频得到的时钟虽然表面上是对系统时钟进行了分频产生了一个新的低频时钟,但实际上和真正的时钟信号还是有很大区别的。因为 在 FPGA 中凡是时钟信号都要连接到全局时钟网络上,全局时钟网络也称为全局时钟树, 是 FPGA 厂商专为时钟路径而特殊设计的,它能够使时钟信号到达每个寄存器的时间都尽可能相同,以保证更低的时钟偏斜(Skew)和抖动(Jitter)。而我们用这种分频的方式产生的 clk_out 信号并没有连接到全局时钟网络上,sys_clk 则是由外部晶振直接通过管脚连接到了 FPGA 的专用时钟管脚上,自然就会连接到全局时钟网络上,所以在 sys_clk 时钟工作下的信号要比在 clk_out 时钟工作下的信号更容易在高速系统中保持稳定
这时我们可以产生一个用于标记 6 分频的 clk_flag 标志信号,这样每两 clk_flag 脉 冲之间的频率就是对 sys_clk 时钟信号的 6 分频,但是计数器计数的个数我们需增加一些,需要从 0~5 共 6 个数,否则不能实现 6 分频的功能。和上一部分代码对比可以发现,相当于把 clk_out 的上升沿信号变成了 clk_flag 的脉冲电平信号,为后级模块实现相同的降频效果。
//使用clk_out 作为时钟信号工作的情况
always@(posedge clk_out or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
B<=2'b0;
else
B <= B + 1'b1;
//使用sys_clk作为时钟信号工作的情况
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
B <= 2'b0;
else if(clk_flag == 1'b1)
B <= B+ 1'b1;
2、pll锁相环实现分频
PLL(Phase Locked Loop,即锁相环)是最常用的 IP 核之一,其性能强大,可以对输入到 FPGA 的时钟信号进行任意分频、倍频、相位调整、占空比调整,从而输出一个期望时钟,实际上,即使不想改变输入到 FPGA 时钟的任何参数,也常常会使用 PLL,因为经过 PLL 后的时钟在抖动(Jitter)方面的性能更好一些。Altera 中的 PLL 是模拟锁相环,和 数字锁相环不同的是模拟锁相环的优点是输出的稳定度高、相位连续可调、延时连续可调;缺点是当温度过高或者电磁辐射过强时会失锁(普通环境下不考虑该问题)。
sys_clk=50MHZ,进行分频得到clk_out1=200MHZ, clk_out2=50MHZ,
系统时钟为50MHZ,但同样可以通过PLL锁相环处理降低时钟抖动Jitter得到clk_out2=50MHZ传到下一级模块使用
// clk_out1___200.000______0.000______50.0______131.575____164.985
// clk_out2___50.000______0.000______50.0______162.035____164.985
//
//----------------------------------------------------------------------------
// Input Clock Freq (MHz) Input Jitter (UI)
//----------------------------------------------------------------------------
// __primary______________50____________0.010
`timescale 1ps/1ps
module clk_wiz_0
(
// Clock out ports
output clk_out1,
output clk_out2,
// Status and control signals
input reset,
output locked,
// Clock in ports
input clk_in1
);
clk_wiz_0_clk_wiz inst
(
// Clock out ports
.clk_out1(clk_out1),
.clk_out2(clk_out2),
// Status and control signals
.reset(reset),
.locked(locked),
// Clock in ports
.clk_in1(clk_in1)
);
endmodule