FPGA例程(5):时钟(clock)分频倍频(PLL/MMCM)实验--vivado行为级仿真、综合后仿真和实现后仿真说明

《FPGA经典例程及解读--基于xilinx K325T平台》系列导航

本专栏主要针对与想学习FPGA的同学,从基础的点灯到之后的复杂功能实战例程,从入门到进阶,通过这些例程的学习和了解,希望可以帮助你从一个FPGA小白进阶到FPGA中级阶段,能够处理工作中大多数的FPGA使用场景。

本篇是该系列的第五篇内容

上一篇:FPGA例程(4):按键消抖实验-CSDN博客

**下一篇:**关注我,第一时间获取更新!!


1 引言

很多初学者会遇到一个问题,我们硬件的输入时钟只有100MHz,但是我们内部需要使用200MHz或者50MHz这样的时钟,我们该怎么办呢?其实在FPGA内部集成了PLL或者MMCM,不同的厂商叫法可能不同,但是功能类似,通过PLL(MMCM)可以分频和倍频,产生很多其它的时钟,本实现通过调用xilinx的clock wizard的IP核来学习PLL(MMCM)的使用方法。

2 硬件环境

开发环境使用vivado2019.1

开发板使用米联客的MK7160FA

3 实验原理

PLL,即锁相环,是FPGA中的重要资源。由于一个复杂的FPGA系统往往需要多个不同频率、相位的时钟信号,所以,一个FPGA芯片中PLL的数量是衡量FPGA芯片能力的重要指标。

7系列的FPGA使用了专用的全局(Global)和区域(Regional)IO和时钟资源来管理设计中各种的时钟需求。Clock Management Tiles(CMT)提供了时钟合成(clock frequency synthesis)、倾斜矫正(deskew)、过滤抖动(jitter filtering)功能。

每个CMTs包含一个MMCM(mixed-mode clock manager)和一个PLL。如下同所示,CMT的输入可以是BUFR、IBUFG、BUFG、GT、BUFH、本地布线(不推荐使用),输出需要接到BUFG或者BUFH后再使用

3.1 混合模式时钟管理器(MMCM)

MMCM用于在与给定输入时钟有设定的相位和频率关系的情况下,生成不同的时钟信号。MMCM提供了广泛而强大的时钟管理功能,MMCM内部的功能框图如下图所示:

3.2 数字锁相环PLL

锁相环主要用于频率综合。使用一个PLL可以从一个输入时钟信号生成多个时钟信号。PLL内部的功能框图如下图所示:

4 建立工程

按照FPGA例程(1):LED流水灯实验--vivado工程创建、编译及下载bit_vivado创建例程-CSDN博客

中的步骤,创建一个名为PLL_test的工程。

点击IP Catalog-->选择Clocking Wizard

clocking Wizard的具体说明详见:FPGA基础知识(十五):Xilinx Clocking Wizard IP核完全指南--从基础到高级应用-CSDN博客

我们的输入时钟为100MHz,我们内部需要使用200MHz和50MHz的时钟

其它参数的配置详见:FPGA基础知识(十五):Xilinx Clocking Wizard IP核完全指南--从基础到高级应用-CSDN博客

我们点击OK-->Generate生成IP核

生成的IP核如下,展开可以看到IP核的TOP层,之后我们在工程中就例化的是这个TOP层。

我们新建一个PLL_test.v文件,例化module clk_wiz_0

大家注意到,程序的最后有一段产生clk_div的程序,即将100MHz进行2分频产生50MHz,故clk_div的频率与clk_50M是一样的,只是生成的方式不同,方便大家看一下这两种方式的区别。

复制代码
module PLL_test(
input sys_clk,  //100MHz
output clk_200M,
output clk_50M,
output clk_div
);

parameter RST_DELAY = 8'd128;
reg [7:0] rst_cnt;
always @(posedge sys_clk) begin
    if(rst_cnt < RST_DELAY)begin 
        rst_cnt <= rst_cnt + 1'd1;
    end else if(rst_cnt == RST_DELAY) begin 
        rst_cnt <= rst_cnt; 
    end else begin 
        rst_cnt <=0;
    end
end
reg rst_n;
always @(posedge sys_clk) begin
    if(rst_cnt == RST_DELAY) begin 
        rst_n <= 1;
    end else begin 
        rst_n <= 0;
    end
end
//----------------------------------------------------
wire sys_rstn;
//wire clk_200M;
//wire clk_50M;
clk_wiz_0 clk_wiz_0(
.clk_200M(clk_200M),
.clk_50M(clk_50M),
.resetn(rst_n),
.locked(sys_rstn),
.clk_in1(sys_clk)
);
//-----------------------------------------------------
reg clk_div_c;
//wire clk_div;
always @(posedge sys_clk or negedge rst_n ) begin
if (!rst_n) begin
    clk_div_c <= 1'b0;
end
else begin
    clk_div_c <= ~clk_div_c;
end
end
BUFG BUFG_inst (
.O(clk_div), // 1-bit output: Clock output
.I(clk_div_c)  // 1-bit input: Clock input
);
endmodule

按照FPGA例程(1):LED流水灯实验--vivado工程创建、编译及下载bit_vivado创建例程-CSDN博客

中的步骤,添加我们的约束文件,如下:

复制代码
## ----------- clock -----------------------
create_clock -period 10.000 -name sys_clk [get_ports sys_clk]
set_property PACKAGE_PIN AA3 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS15 [get_ports sys_clk]
## ------------ led pin -----------------------------
set_property PACKAGE_PIN G14 [get_ports {clk_200M}]
set_property PACKAGE_PIN H14 [get_ports {clk_50M}]
set_property PACKAGE_PIN J10 [get_ports {clk_div}]
set_property IOSTANDARD LVCMOS33 [get_ports {clk_200M}]
set_property IOSTANDARD LVCMOS33 [get_ports {clk_50M}]
set_property IOSTANDARD LVCMOS33 [get_ports {clk_div}]

## ========================== SPI X4 =================================
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE Yes [current_design]

5 程序仿真

我们点击Add Sources-->选择Add or create simulation sources添加以下仿真激励文件。

如果我们有现成的文件,选择Add Files,选择文件路径即可

这里我们没有现成的,就点击Create File--->输入仿真激励文件名称--->OK---->Finish

就会在Simulation Sources下面产生以下tb_PLL_test.v的文件,我们开始编写测试激励:

输入时钟是100MHz,对应周期为10ns,故5ns我们执行一次反转

复制代码
module tb_PLL_test();
reg sys_clk;
initial begin
    sys_clk = 0;
end
always begin
    #5 sys_clk = ~sys_clk;
end

wire clk_200M,clk_50M,clk_div;
PLL_test DUT(
.sys_clk(sys_clk),  //100MHz
.clk_200M(clk_200M),
.clk_50M(clk_50M),
.clk_div(clk_div)
);
endmodule

5.1 行为级仿真

点击Run Simulation ,选择Run Behavioral Simulation

选择例化的名称,可以在Objects中看到相关的信号,右键选择Add to Wave Window,就可以将信号加入观测窗口的

添加好之后,设定仿真的时间,比如10us,点击Run for 10us(三角形+T的图标)就可以进行仿真了,跑完10us会自动停下

如果不知道设置多长时间可以直接点击Run All(三角形图标),等跑一下自己手动暂停即可。

仿真结果如下:

输出的clk_200m对应的周期为5ns,即200mhz时钟周期

输出的clk_50m对应的周期为20ns,即50mhz时钟周期

输出的clk_div对应的周期亦为20ns,即50mhz时钟周期

这些时钟均与sys_clk上升沿对齐

5.2 综合时序仿真

执行完Run Synthesis之后,点击Run Simulation ,选择Run Post-Synthesis Timing Simulation

通过仿真我们可以看到综合后仿真加入了延迟,会更加接近实际中芯片的运行场景

首先输入的sys_clk与输出clk_200M和clk_50M之间存在相位偏移

clk_200m与clk_50m之间也存在相位偏移,但是偏移非常小

输入的sys_clk与输出的clk_div存在相位偏移,且相位偏移要大于其与clk_50M之间的偏移

5.3 布局布线后时序仿真

完成Run Implementation之后,点击Run Simulation ,选择Run Post-Implementation Timing Simulation

通过仿真可以看出,通过布局布线之后加入了延迟,比综合后的仿真更接近于真实的情况,时序之间的相位延迟也更大一些。

6 总结

一般来说,程序的功能是否正常,我们可以先查看行为级仿真,当程序出现一些未预料的bug时,综合后仿真和实现后仿真能很好的帮助我们定位bug,尤其是一些因为不当的设计被优化掉的信号,从综合后仿真和实现后仿真能明显的看出来。

相关推荐
仲南音2 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner2 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20203 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy3 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia3 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20203 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子3 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安4 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun5 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议