在 FPGA 芯片内部集成了 PLL(phase-locked loop,锁相环),可以倍频分频,产生其它时钟类型。PLL 是 FPGA 中的重要资源,因为一个复杂的 FPGA 系统需要不同频率、相位的时钟信号,一个 FPGA 芯片中 PLL 的数量是衡量 FPGA 芯片能力的重要指标。
Ultrascale+ 系列的 FPGA 使用了专用的全局(Global)和区域(Regional)IO和时钟资源来管理设计中各种时钟需求。Clock Management Tiles(CMT) 提供了时钟合成(Clock frequency synthesis)、倾斜校正(deskew)、过滤抖动(jitter filtering)功能。
每个 CMT 包含一个 MMCM(Mixed-mode clock manager,混合模式时钟管理器,根据一定的相位和频率产生不同的时钟信号) 和一个 PLL(可以从一个输入信号产生多个时钟信号,不能进行时钟倾斜校正,不具备高级相位调整、倍频器和分频器可调范围较小),CMT 的输入可以是 BUFR、IBUFG、BUFG、GT、BUFH、本地布线,输出需要接到 BUFG、BUFH 后再使用。
更多的时钟资源帮助文档:https://docs.xilinx.com/v/u/en-US/ug472_7Series_Clocking
使用 Xilinx 提供的 PLL IP 核产生不同频率的时钟。
在 Project Manager 界面下的 IP Catalog。
双击 Clocking Wizard
。
默认的时钟约束名称是 clk_wiz_0,在 Clocking Options 中,输入的时钟频率为 200MHz,并选择 Differential clock capable pin。
在 Output Clocks 界面里选择 clk_out1~clk_out4 四个时钟的输出,频率分别为 200MHz、100MHz、50MHz、25MHz,这里还可以设置时钟输出的相位,点击 OK 完成。
在弹出的对话框中点击 Generate 按钮生成 PLL IP 的设计文件。
选择 IP Sources 页,然后双击打开 clk_wiz_0.veo 文件 —— 提供了该 IP 的实例化模板。我们需要编写一个顶层设计文件来实例化这个 PLL IP,编写 pll_test.v 代码。
PLL的复位是高电平有效,复位一直为高电平,PLL 就不会工作。
创建 pll_test.v。
`timescale 1ns / 1ps
module pll_test(
input sys_clk_p, //system clock 200Mhz on board
input sys_clk_n, //system clock 200Mhz on board
input rst_n, //reset ,low active
output clk_out //pll clock output
);
wire locked;
clk_wiz_0 clk_wiz_0_inst
(
// Clock out ports
.clk_out1(), // output clk_out1
.clk_out2(), // output clk_out2
.clk_out3(), // output clk_out3
.clk_out4(clk_out), // output clk_out4
// Status and control signals
.reset(~rst_n), // input reset
.locked(locked), // output locked
// Clock in ports
.clk_in1_p(sys_clk_p), // input clk_in1_p
.clk_in1_n(sys_clk_n)); // input clk_in1_n
endmodule
程序中先用实例化 clk_wiz_0, 把差分 200MHz 时钟信号输入到 clk_wiz_0 的 clk_in1_p 和 clk_in1_n,把 clk_out4 的输出付给 clk_out。例化的目的是在上一级模块中调用例化的模块完成代码功能,在 Verilog 里例化信号的格式如下:模块名必须和要例化的模块名一致,比如程序中的 clk_wiz_0,包括模块信号名也必须一致,比如 clk_in1,clk_out1,clk_out2 …。连接信号为 TOP 程序(保存后,pll_test 自动成为了 top 文件,clk_wiz_0 成为 pll_test 文件的子模块)跟模块之间传递的信号,模块与模块之间的连接信号不能相互冲突。
添加 xdc 管脚约束文件 pll.xdc:
##################Compress Bitstream############################
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_SSTL12 [get_ports sys_clk_p]
create_clock -period 5.000 -name sys_clk_p -waveform {0.000 2.500} [get_ports sys_clk_p]
set_property PACKAGE_PIN AF12 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property PACKAGE_PIN AG11 [get_ports clk_out]
set_property IOSTANDARD LVCMOS33 [get_ports clk_out]
编写仿真文件 vtf_pll_test.v:
`timescale 1ns / 1ps
//
// Module Name: vtf_pll_test
//
module vtf_pll_test;
// Inputs
reg sys_clk_p;
wire sys_clk_n;
reg rst_n;
// Outputs
wire clk_out;
// Instantiate the Unit Under Test (UUT)
pll_test uut (
.sys_clk_p(sys_clk_p),
.sys_clk_n(sys_clk_n),
.rst_n(rst_n),
.clk_out(clk_out)
);
initial begin
// Initialize Inputs
sys_clk_p = 0;
rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
end
always #2.5 sys_clk_p = ~ sys_clk_p; //5ns一个周期,产生200MHz时钟源
assign sys_clk_n = ~ sys_clk_p;
endmodule
编译工程,然后将 bit 文件下载到 FPGA 开发板上,使用示波器测量输出时钟的波形。
如果想输出其它频率的波形,可以修改时钟的输出为 clk_wiz_0 的 clk_out2 或 clk_out3 或 clk_out4,也可以修改 clk_wiz_0 为想要的频率。由于时钟的输出是通过 PLL 对输入时钟信号的倍频和分频系数得到的,所以并不是所有的时钟频率都可以用 PLL 能够精确产生,PLL 会自动计算实际输出接近的时钟频率。