基于ZYNQ-7000系列的FPGA学习笔记10——IP核之锁相环
上一期内容,我们学习了VAVADO软件在线逻辑分析仪的使用方法,这一期我们IP核中另一个常用的内容:锁相环
1. 实验要求
通过例化VAVADO软件中的锁相环模块,产生四路不同的时钟信号,具体要求如下:
- 一路时钟信号,频率为10MHz
- 二路时钟信号,频率为10MHz,但是相位和一路相差180度
- 三路时钟信号,频率为5MHz
- 四路时钟信号,频率为25MHz
2. 功能分析
2.1 锁相环简介
要完成以上内容,我们需要先来了解一下锁相环。
锁相环(Phase-Locked Loop,简称PLL)作为一种反馈控制电路,其特点是利用外部输入的参考信号来控制环路内部震荡信号的频率和相位。因为锁相环可以实现输出信号频率对输入信号频率的自动跟踪,所以锁相环通常用于闭环跟踪电路。锁相环在工作的过程中,当输出信号的频率与输入信号的频率相等时,输出电压与输入电压保持固定的相位差值,即输出电压与输入电压的相位被锁住,这就是锁相环名称的由来。下面是一个最简单的锁相环模型:
锁相环通常由以下三个基本部分组成:
- 鉴频鉴相器(Phase Detector,PD):比较输入信号与压控振荡器(VCO)输出信号的相位差,并产生一个与相位差成正比的误差电压。
- 环路滤波器(Low-Pass Filter,LPF):对相位检测器输出的误差电压进行滤波,消除高频分量,得到一个平滑的控制信号。
- 压控振荡器(Voltage-Controlled Oscillator,VCO):其输出频率随输入控制电压的变化而变化,通过调整VCO的输入电压,可以改变其输出频率,从而使VCO的输出信号相位逐渐接近输入信号相位。
这种锁相环的特点和明显,输入和输出的频率是一样的,如果需要输入和输出之间的频率不同,则需要引入分频锁相环和倍频锁相环,通过不断的分频和倍频就可以满足输出各种不同频率的信号,这就是锁相环的基本工作原理。
【注】:一个 PLL IP 核输出的时钟路数是有限的,且输入/输出的时钟频率也是有限制的,我们不能无限制的输入无穷大/小的时钟频率,也不可能通过倍频或分频输出无穷大/小的时钟频率。这里我们总结了一下几款常用芯片的相关信息,如下表所示:
2.1 MMCM(混合模式时钟管理)
我们在使用VAVADO软件中的锁相环IP核时,也可能会遇到MMCM。这里我们简单的介绍一下:
MMCM(混合模式时钟管理):是基于 PLL 的新型混合模式时钟管理器,实现了最低的抖动和抖动滤波,为高性能的 FPGA 设计提供更高性能的时钟管理功能。
MMCM 是一个 PLL 上加入 DCM 的一部分以进行精细的相移,也就是说 MMCM 在 PLL 的基础上加上了相位动态调整功能,又因为 PLL 是模拟电路,而动态调相是数字电路,所以 MMCM 被称为混合模式,MMCM 相对 PLL 的优势就是相位可以动态调整,但 PLL 占用的面积更小,而在大部分的设计当中大家使用 MMCM 或者 PLL 来对系统时钟进行分频、倍频和相位偏移都是完全可以的。
2.3 功能分析
有了上面锁相环的相关知识,相信对于如何实现本次实验的内容,聪明的你一定想到了解决办法,和上期一样,创建对应的IP核,进行相关配置,然后例化就好啦。至于例化输出的端口,我们这里选择的是正点原子领航者底板上的J3扩展口
3. 模块设计
根据实验要求,我们设计了如下的模块
- 输入分别是50MHz的系统时钟输入和复位信号
- 输出是四路需要输出的信号,这里不做赘述
4. 波形图
接着我们根据功能框图和实验要求,设计了如下的波形图:
到这里我们就基本明了本次实验的具体内容,下一步与之前的实验步骤不太一样,需要我们创建锁相环对应的IP核,然后再例化对应的模块。
5. 创建锁相环的IP核
创建锁相环IP核的步骤如下:
- 进入PLL创建向导
- 配置时钟选项
- 配置输出选项
完成上述步骤,就可以创建一个简单的锁相环IP核,下一步可以编写代码。
6.代码编写
- 编写rtl代码:
`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/12/08 16:54:27
// Design Name:
// Module Name: ip_clk_wiz
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
//顶层模块的端口定义
module ip_clk_wiz(
input sys_clk, //系统时钟
input sys_rst_n, //复位信号,低电平有效
output clk_10m, //输出10MHz
output clk_10m_180deg, //输出10Mhz,反向的信号
output clk_5m, //输出5MHz的信号
output clk_25m //输出25MHz的信号
);
wire locked;
//PLL模块的例化
clk_wiz_0 u_clk_wiz_0(
.clk_in1 (sys_clk),
.reset (~sys_rst_n),
.clk_out1 (clk_10m),
.clk_out2 (clk_10m_180deg),
.clk_out3 (clk_5m),
.clk_out4 (clk_25m),
.locked (locked)
);
endmodule
- 编写tb代码:
`timescale 1ns / 1ns //仿真单位/精度
module tb_ip_clk_wiz();
parameter CLK_PERIOD = 20; //时钟周期
reg sys_clk;
reg sys_rst_n;
wire clk_10m;
wire clk_10m_180deg;
wire clk_5m;
wire clk_25m;
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
#200
sys_rst_n <=1'b1;
end
always #(CLK_PERIOD / 2) sys_clk <= ~sys_clk;
ip_clk_wiz u_ip_clk_wiz(
.sys_clk (sys_clk), //系统时钟
.sys_rst_n (sys_rst_n), //复位信号,低电平有效
.clk_10m (clk_10m), //输出10MHz
.clk_10m_180deg (clk_10m_180deg), //输出10Mhz,反向的信号
.clk_5m (clk_5m), //输出5MHz的信号
.clk_25m (clk_25m) //输出25MHz的信号
);
endmodule
7. 代码仿真
如果按照之前的步骤,对我们编写的代码进行仿真,会发现Modelsim仿真报错了,这是因为我们调用了VIVADO自带的IP模块,在仿真的过程中缺少了需要的仿真库文件,解决的方式有两个,第一个是使用VIVADO自带的仿真,第二个是使用VIVADO和Modelsim进行联合仿真,下面我将介绍这两种方式:
7.1 使用VAVADO自带的仿真
Vivado 设计套件内部集成了仿真器 Vivado Simulator,能够在设计流程的不同阶段运行设计的功能仿真和时序仿真,结果可以在 Vivado IDE 集成的波形查看器中显示。使用的方法也很简单,步骤如下:
- 添加激励文件
- 保存之后按照如下方式开启仿真
【注】:这里仿真的使用方法不做介绍,和Modelsim很类似,感兴趣的也可以去找找教程,或者自行探索。
7.2 使用VIVADO和Modelsim进行联合仿真
除了使用VAVADO自带的仿真,Vivado 还支持与诸如 ModelSim、Verilog Compiler Simulator (VCS)、Questa Advanced Simulator 等第三方仿真器的联合仿真。
- 首先我们需要再Modelsim的安装目录下创建一个存放vivado仿真库文件的目录:
- 然后需要生成对应的仿真库文件,需要我们打开VAVADO软件
-
进入VAVADO软件进行仿真设置
-
完成上述步骤之后,就可以直接开启仿真,然后VIVADO会自动开启Modelsim,进入仿真页面。
可以看到仿真结果和我们绘制的波形图是一样的,频率符合预期,至此代码仿真完成,下一步添加约束文件,并综合分析
8. 添加约束文件并分析综合
- 添加如下的我约束文件
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports clk_10m]
set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports clk_10m_180deg]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports clk_5m]
set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports clk_25m]
- 然后分析综合,得到如下结果
可以看到顶层模块中是例化了锁相环模块的,锁相环这里就相当于一个黑匣子,点进去只能看到如下内容:
无法看到锁相环的内部结构,只能看到对应接口的连接方式。
至此,本次实验内容到此结束,下一步就是生成比特流文件,然后观察实验结果。
9. 实验结果
由于我这里的条件有限,只有双通道的示波器,所以四路的输出信号这里分开展示。
- 一二路的输出信号
- 三四路的输出信号
10. 补充:不同仿真方式的区别
我们在使用仿真的时候,是可以看到有很多个仿真选项,但是我们使用的是第一个选项:行为仿真。实际上这里一共有五种仿真方式,分别如下:
- run behavioral simulation :行为级仿真,也是通常说的功能仿真。
- post-synthesis function simulation : 综合后的功能仿真。
- post-synthesis timing simulation : 综合后的时序仿真,和真实运行的时序就相差不远了。
- post-implementation function simulation : 实现后的功能仿真。
- post-implementation timing simulation : 实现后的时序仿真,最接近真实的时序波形。
根据数字电路设计的不同阶段,产生了三个阶段的仿真,分别是RTL行为级仿真,综合后门级功能仿真和时序仿真。
- RTL 行为级仿真
在大部分设计中执行的第一个仿真都是 RTL 行为级仿真。这个阶段的仿真可以用来检查代码中的语法错误以及代码行为的正确性,需要注意是该阶段的仿真是不包含延时信息的。如果没有实例化一些与器件相关的特殊底层元件的话,这个阶段的仿真也可以做到与器件无关。因此在设计的初期阶段不使用特殊底层元件即可以提高代码的可读性、可维护性,又可以提高仿真效率,且容易被重用。(绝大部分设计人员
将这个阶段的仿真叫做功能仿真!)
- 综合后门级功能仿真 (前仿真)
一般在设计流程中的第二个仿真是综合后门级功能仿真。绝大多数的综合工具除了可以输出一个标准网表文件以外,还可以输出 Verilog 或者 VHDL 网表,其中标准网表文件是用来在各个工具之间传递设计数据的,并不能用来做仿真使用,而输出的 Verilog 或者 VHDL 网表是可以用来仿真的。之所以叫门级仿真是因为综合工具给出的仿真网表已经是与生产厂家的器件的底层元件模型对应起来了,所以为了进行综合后仿真必须在仿真过程中加入厂家的器件库,并对仿真器进行一些必要的配置,不然仿真器并不认识其中的底层元件,也就无法进行仿真了。
- 时序仿真 (后仿真)
在设计流程中的最后一个仿真是时序仿真。在设计布局布线完成以后可以提供一个时序仿真模型,这种模型中也包括了器件的一些信息,同时还会提供一个 SDF 时序标注文件(Standard Delay format Timing Anotation)。SDF 时序标注最初使用在 Verilog 语言的设计中,现在 VHDL 语言的设计中也引用了这个概念。对于一般的设计者来说并不需知道 SDF。
以上就是本期的所有内容,创造不易,点个关注再走呗。