目录
一、前言
1.1 背景
1.2 PLL结构
二、工程设计
2.1 PLL IP核配置
2.2 设计代码
2.3 测试代码
2.4 仿真结果
2.5 常见问题
若将一个FPGA工程看做一个人体,时钟的重要性丝毫不亚于心脏对于人体的重要性,时钟的每一个周期对于工程都是一次全面的状态更新,因此,时钟的有效使用重要性不言而喻。
以赛灵思7系列的器件为例,在之前的文章Xilinx之7系列时钟资源与时钟架构 中,第三节时钟管理单元 提到了7系列时钟管理单元CMT,CMT包含了MMCM和PLL,PLL的功能为MMCM功能的子集,可实现时钟网络去偏斜,频率合成,去抖动。
根据赛灵思官网用户手册,PLL的结构如下图
PLL主要的组成部分有图中3个红色框:鉴相器PFD,电荷泵CP和低通滤波器LF,压控振荡器VCO。实现的流程为VCO自身输出一个时钟CLKFBOUT反馈到PFD,PFD对输入时钟和反馈时钟的相位进行比较,将比较的相位差传输到CP和LF,LF主要用于滤除高频干扰信号。CP和LF会将结果转换成电压信号,电压信号控制VCO的输出频率。在PLL达到稳定状态后,输出频率FvcoH和输入频率Fclkin满足如下关系。
对于例化PLL的原语有两种:PLLE2_BASE,PLLE2_ADV,PLLE2_ADV的端口更多,功能更丰富。
在Vivado的Language Templates中搜索PLL可查找到7系列的4个型号Atrix,都具有PLLE2_BASE,PLLE2_ADV两种类型,类似的MMCM也有两种BASE和ADV两种类型
以PLLE2_ADV为例,各端口说明如下,其中,CLKOUT0-CLKOUT3支持PLL/MMCM间的级联连接。
下面展示使用原语例化和IP核两种方式使用PLL,用CLKOUT0-CLKOUT3 4路输出示例,其中PLL IP核的配置与例化的PLL相同。
module PLL( CLKIN1,CLKIN2,CLKIN1_ip,CLKIN2_ip,RST,CLKINSEL,CLKOUT0,CLKOUT1,CLKOUT2,CLKOUT3,
CLKOUT0_ip,CLKOUT1_ip,CLKOUT2_ip,CLKOUT3_ip);
input CLKIN1,CLKIN2,CLKIN1_ip,CLKIN2_ip,RST,CLKINSEL;
output CLKOUT0,CLKOUT1,CLKOUT2,CLKOUT3;
output CLKOUT0_ip,CLKOUT1_ip,CLKOUT2_ip,CLKOUT3_ip;
wire n_clkfbout;
//使用PLLE2_ADV原语
PLLE2_ADV #(
.BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW
.CLKFBOUT_MULT(9), //时钟输出乘该值
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360.000-360.000).
// CLKIN_PERIOD: Input clock period in nS to ps resolution (i.e. 33.333 is 30 MHz).
.CLKIN1_PERIOD(10.0), //参考时钟1周期为10ns
.CLKIN2_PERIOD(8.333), //参考时钟2周期为8.333ns
// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divide amount for CLKOUT (1-128)
.CLKOUT0_DIVIDE(1), //第一路输出分频系数为1
.CLKOUT1_DIVIDE(2), //第一路输出分频系数为2
.CLKOUT2_DIVIDE(10), //第一路输出分频系数为10
.CLKOUT3_DIVIDE(20), //第一路输出分频系数为20
// .CLKOUT4_DIVIDE(10),
// .CLKOUT5_DIVIDE(20),
// CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE: Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT0_DUTY_CYCLE(0.5), //第一路输出占空比为0.5
.CLKOUT1_DUTY_CYCLE(0.1), //第一路输出占空比为0.1
.CLKOUT2_DUTY_CYCLE(0.3), //第一路输出占空比为0.3
.CLKOUT3_DUTY_CYCLE(0.7), //第一路输出占空比为0.7
// .CLKOUT4_DUTY_CYCLE(0.4),
// .CLKOUT5_DUTY_CYCLE(0.6),
// CLKOUT0_PHASE - CLKOUT5_PHASE: Phase offset for CLKOUT outputs (-360.000-360.000).
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(0.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(0.0),
.COMPENSATION("ZHOLD"), // ZHOLD, BUF_IN, EXTERNAL, INTERNAL
.DIVCLK_DIVIDE(1), // Master division value (1-56)
// REF_JITTER: Reference input jitter in UI (0.000-0.999).
.REF_JITTER1(0.0),
.REF_JITTER2(0.0),
.STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE")
)
PLLE2_ADV_inst (
// Clock Outputs: 1-bit (each) output: User configurable clock outputs
.CLKOUT0(CLKOUT0), // 1-bit output: CLKOUT0
.CLKOUT1(CLKOUT1), // 1-bit output: CLKOUT1
.CLKOUT2(CLKOUT2), // 1-bit output: CLKOUT2
.CLKOUT3(CLKOUT3), // 1-bit output: CLKOUT3
.CLKOUT4(CLKOUT4), // 1-bit output: CLKOUT4
.CLKOUT5(CLKOUT5), // 1-bit output: CLKOUT5
// DRP Ports: 16-bit (each) output: Dynamic reconfiguration ports
.DO(), // 16-bit output: DRP data
.DRDY(), // 1-bit output: DRP ready
// Feedback Clocks: 1-bit (each) output: Clock feedback ports
.CLKFBOUT(n_clkfbout), // 1-bit output: Feedback clock
.LOCKED(), // 1-bit output: LOCK
// Clock Inputs: 1-bit (each) input: Clock inputs
.CLKIN1(CLKIN1), // 1-bit input: Primary clock
.CLKIN2(CLKIN2), // 1-bit input: Secondary clock
// Control Ports: 1-bit (each) input: PLL control ports
.CLKINSEL(CLKINSEL), // 1-bit input: Clock select, High=CLKIN1 Low=CLKIN2
.PWRDWN(PWRDWN), // 1-bit input: Power-down
.RST(RST), // 1-bit input: Reset
// 动态重配相关的不使用,悬空即可
.DADDR(DADDR), // 7-bit input: DRP address
.DCLK(DCLK), // 1-bit input: DRP clock
.DEN(DEN), // 1-bit input: DRP enable
.DI(DI), // 16-bit input: DRP data
.DWE(DWE), // 1-bit input: DRP write enable
// Feedback Clocks: 1-bit (each) input: Clock feedback ports
.CLKFBIN(n_clkfbout) // 1-bit input: Feedback clock
);
//调用PLL的IP核
clk_wiz_0 pll_ip
(
// Clock in ports
.clk_in1(CLKIN1_ip),
.clk_in2(CLKIN2_ip),
.clk_in_sel(CLKINSEL),
// Clock out ports
.clk_out1(CLKOUT0_ip),
.clk_out2(CLKOUT1_ip),
.clk_out3(CLKOUT2_ip),
.clk_out4(CLKOUT3_ip),
// Status and control signals
.reset(RST),
.locked()
);
endmodule
module PLL_TB( );
reg CLKIN1,CLKIN2,CLKIN1_ip,CLKIN2_ip,RST,CLKINSEL;
wire CLKOUT0,CLKOUT1,CLKOUT2,CLKOUT3;
wire CLKOUT0_ip,CLKOUT1_ip,CLKOUT2_ip,CLKOUT3_ip;
initial
begin
CLKIN1=0;
CLKIN2=0;
CLKIN1_ip=0;
CLKIN2_ip=0;
RST=0;
CLKINSEL=0;
#50 RST=1; //复位信号切换为0,为CLKINSEL切换做准备,因为RST为0时,CLKINSEL不能进行切换
#100 CLKINSEL=1; //切换参考信号为CLKIN2
#10 RST=0; //取消复位
#2000 RST=1; //复位信号切换为0,为CLKINSEL切换做准备,因为RST为0时,CLKINSEL不能进行切换
#10 CLKINSEL=0; //参考时钟选择信号初始化为1,即选择CLKIN1为参考信号
#10 RST=0; //取消复位
end
always#10 CLKIN1=~CLKIN1; //CLKIN1输入周期为20ns
always#10 CLKIN1_ip=~CLKIN1_ip; //CLKIN1_ip输入周期为20ns
always#4 CLKIN2=~CLKIN2; //CLKIN2输入周期为8ns
always#4 CLKIN2_ip=~CLKIN2_ip; //CLKIN2_ip输入周期为8ns
PLL PLL_test(.CLKIN1(CLKIN1),.CLKIN2(CLKIN2),.CLKIN1_ip(CLKIN1_ip),.CLKIN2_ip(CLKIN2_ip),
.RST(RST),.CLKINSEL(CLKINSEL),.CLKOUT0(CLKOUT0),.CLKOUT1(CLKOUT1),.CLKOUT2(CLKOUT2),.CLKOUT3(CLKOUT3),
.CLKOUT0_ip(CLKOUT0_ip),.CLKOUT1_ip(CLKOUT1_ip),.CLKOUT2_ip(CLKOUT2_ip),.CLKOUT3_ip(CLKOUT3_ip));
endmodule
分别对比CLKOUT0-CLKOUT3与CLKOUT0_ip-CLKOUT3_ip,两种情况下4个输出端口的波形相同,符合预期
输入参考信号切换,下图中CLKOUT1-CLKOUT3在左右两侧的频率不同,即进行了输入参考信号的切换,左侧波形松散,右侧密实,即切换后参考信号频率更高
1)使用原语例化PLL时布线失败,报错如下图,
DRC error内容详细如下
[DRC PDRC-43] PLL_adv_ClkFrequency_div_no_dclk: The computed value 300.000 MHz (CLKIN1_PERIOD, net CLKIN1_IBUF) for the VCO operating frequency of the PLLE2_ADV site PLLE2_ADV_X0Y1 (cell PLLE2_ADV_inst) falls outside the operating range of the PLL VCO frequency for this device (800.000 - 1600.000 MHz). The computed value is (CLKFBOUT_MULT_F * 1000 / (CLKINx_PERIOD * DIVCLK_DIVIDE)). Please adjust either the input period CLKINx_PERIOD (10.000000), multiplication factor CLKFBOUT_MULT_F (3) or the division factor DIVCLK_DIVIDE (1), in order to achieve a VCO frequency within the rated operating range for this device.
通过该信息知设计的VCO的为300MHZ,不在允许的【800-1600MHZ】范围内,这是由于CLKIN1和CLKFBOUT_MULT设置不合理,CLKIN1为100MHZ,CLKFBOUT_MULT为3,因此VC0为300MHZ,将CLKFBOUT_MULT值改大即可
2)进行仿真,点击运行,弹出“Finish Vsim”窗口
内容如下,即仿真文件中在复位信号RST=1时进行了参考信号的切换,更改测试文件使CLKINSEL在RST为0时进行切换
Input Error : Input clock can only be switched when RST=1. CLKINSEL on PLLE2_ADV instance PLL_TB.PLL_test.PLLE2_ADV_inst at time 2190000 changed when RST low, which should change at RST high.