锁相环(Phase Locked Loop,PLL),一种反馈控制电路,对时钟网络进行系统级的时钟管理和偏移控制,具有时钟倍频、分频、相位偏移和可编程占空比的功能。
Xilinx 7系列器件中的时钟资源包含了时钟管理单元CMT,每个CMT由一个MMCM和一个PLL组成。xc7z010芯片内部有两个CMT,为设备提供系统时钟管理和高速I/O通信。
参考时钟输入:
(1)IBUFG(CC):具有时钟能力的 IO 输入
(2)BUFR:区域时钟
(3)BUFG:全局时钟
(4)GT:收发器输出时钟
(5)BUFH:行时钟
(6)Local Routing:本地布线(不推荐使用本地布线来驱动时钟资源)
MMCM包含PLL的功能,主要用于驱动器件逻辑(CLB、DSP、RAM等)的时钟;PLL主要用于为内存接口生成所需的时钟信号。
D:前置分频计数器
PFD:相位频率检测器
CP:电荷泵
LF:环路滤波器
VCO:压控振荡器
M:反馈乘法器计数器
O1-O6:后置分频计数器
Fout = Fin*M / (D*O)
Xilinx提供了用于实现时钟功能的IP核Clocking Wizard,该IP核能够根据用户的时钟需求自动配置器件内部的CMT及时钟资源。
使用Zynq开发板输出四个不同时钟频率或相位的时钟,并在Vivado中进行仿真以验证结果,最后生成bite流文件并将下载到开发板上。
在弹出的“Genarate Output Products”窗口中直接点击“Generate”即可。
在下图的文件clk_wiz.veo是由IP核自动生成的只读的verilog例化模板文件。在例化时钟IP核模块的时钟时可以直接从此处复制。
编写代码利用时钟IP核输出的时钟点亮LED,使其同步周期点亮和熄灭。
top.v
module top(
input clk_50m,
input rst_n,
output clk_led1,
output clk_led2,
output clk_led3,
output clk_led4
);
wire clk_out1;
wire clk_out2;
wire clk_out3;
wire clk_out4;
wire locked;
clk_wiz_0 ins_clk_wiz
(
// Clock out ports
.clk_out1(clk_out1), // output clk_out1 100MHz
.clk_out2(clk_out2), // output clk_out2 100MHz 180deg
.clk_out3(clk_out3), // output clk_out3 50MHz
.clk_out4(clk_out4), // output clk_out4 25MHz
// Status and control signals
.reset(~rst_n), // input reset
.locked(locked), // output locked
// Clock in ports
.clk_in1(clk_50m)
);
divid_clk
#(
.N(32'd500) //32'd50000000
)
ins_divid_clk_1
(
.clk_init(clk_out1),
.rst_n(rst_n),
.valid(locked),
.clk_out(clk_led1)
);
divid_clk
#(
.N(32'd500) //32'd50000000
)
ins_divid_clk_2
(
.clk_init(clk_out2),
.rst_n(rst_n),
.valid(locked),
.clk_out(clk_led2)
);
divid_clk
#(
.N(32'd250)
)
ins_divid_clk_3
(
.clk_init(clk_out3),
.rst_n(rst_n),
.valid(locked),
.clk_out(clk_led3)
);
divid_clk
#(
.N(32'd125)
)
ins_divid_clk_4
(
.clk_init(clk_out4),
.rst_n(rst_n),
.valid(locked),
.clk_out(clk_led4)
);
endmodule
divid_clk.v
module divid_clk(
input clk_init,
input rst_n,
input valid,
output reg clk_out
);
parameter N = 32'd25000000;
reg [31:0] counter;
always@(posedge clk_init or negedge rst_n or negedge valid) begin
if(!rst_n) begin
counter <= 32'd1;
end
else if(!valid) begin
counter <= 32'd1;
end
else begin
if(counter == N) begin
counter <= 32'd1;
end
else begin
counter <= counter + 32'd1;
end
end
end
always@(posedge clk_init or negedge rst_n or negedge valid) begin
if(!rst_n) begin
clk_out <= 1'b0;
end
else if(!valid) begin
clk_out <= 1'b0;
end
else begin
if(counter == N) begin
clk_out <= ~clk_out;
end
end
end
endmodule
top_tb.v
`timescale 1ns / 1ps
module top_tb();
reg clk_50m;
reg rst_n;
wire clk_led1;
wire clk_led2;
wire clk_led3;
wire clk_led4;
top ins_top(
.clk_50m(clk_50m),
.rst_n(rst_n),
.clk_led1(clk_led1),
.clk_led2(clk_led2),
.clk_led3(clk_led3),
.clk_led4(clk_led4)
);
initial begin
rst_n = 0;
clk_50m = 1;
#15 rst_n = 1;
end
always #10 clk_50m = ~clk_50m;
endmodule