原创 小梅哥FPGA时序分析笔记(五)I/O约束显神威——深入龙潭

2019-7-2 08:57 11691 61 12 分类: FPGA/CPLD 文集: FPGA深入学习

大家一定对我上一节的突然结尾表示一脸茫然:我是来学习时序约束的,然后你告诉我时序约束里面IO约束很重要,然我又跟着你的文章继续往下看,本以为你就要讲如何进行IO约束了,结果呢,你一个取反时钟就把我们打发了,不仁义呀。

不仁义那就不仁义吧,不过话又说回来,这种取反时钟的方式解决时序问题,貌似并非是个例,其他很多地方也都有这种操作,比如以太网GMII接口也有这么干的,高速DAC输出也有这么干的,不过有时候是将时钟取反了输出,而有时候则是在FPGA内部使用下降沿作为触发器的采样信号,形式不同,原理一样,效果一样。只是,这么干的人多了,貌似就成了公理,反而我写一个使用时钟上升沿触发寄存器,同时不给时钟取反就直接驱动DAC或者以太网GMII的程序,会被人质疑写错了。既然如此,那就让事实再次来说话吧。还是以第四节讲到的VGA显示的程序为例,这一次,我们不再用取反时钟的方法,而是使用时序约束这种理论上的正统方法来解决这个问题。

先介绍下整个系统吧。如下图所示,在FPGA中,编写了一个名为disp_driver的模块,用来产生VGA时序并将每个像素的三元色值分别输出。同时使用了PLLclk[3]端口输出74.5MHz的时钟信号,既提供给disp_driver驱动逻辑使用,也作为Disp_CLK引出,接到ADV7123芯片的CLOCK引脚上,作为数据同步时钟。

既然Disp_CLK是输出时钟信号,那么就需要对其加上约束。约束方法很简单,以PLLCLK[3]端口为主,创建一个生成时钟,并指定到Disp_CLK引脚上即可。约束命令如下所示:

create_generated_clock -name {CLK_Display} -source [get_pins {pll|altpll_component|auto_generated|pll1|clk[3]}] -master_clock  {pll|altpll_component|auto_generated|pll1|clk[3]} [get_ports {Disp_PCLK}]


注意,由于页面排版问题,上面的代码是被自动换行了,实际在sdc文件中,是不存在换行的

既然定义了一个时钟且绑定到了具体的输出信号上,为了让Quartus能够对该信号进行分析,需要对该信号添加输出约束。约束命令如下所示:

set_max_delay -from [get_pins {pll|altpll_component|auto_generated|pll1|clk[3]}] -to [get_ports {Disp_PCLK}] 5.000

set_min_delay -from [get_pins {pll|altpll_component|auto_generated|pll1|clk[3]}] -to [get_ports {Disp_PCLK}] 1.000

接下来,就是对输出给ADV7123的数据(RGB)和控制(HSVS)信号进行输出约束了。约束内容如下:

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[0]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[0]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[1]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[1]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[2]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[2]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[3]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[3]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[4]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[4]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[5]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[5]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[6]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[6]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Blue[7]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Blue[7]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_DE}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_DE}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[0]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[0]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[1]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[1]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[2]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[2]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[3]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[3]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[4]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[4]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[5]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[5]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[6]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[6]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Green[7]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Green[7]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_HS}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_HS}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[0]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[0]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[1]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[1]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[2]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[2]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[3]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[3]]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[4]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[4]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[5]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[5]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[6]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[6]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_Red[7]}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_Red[7]}]

set_output_delay -add_delay -max -clock [get_clocks {CLK_Display}]  0.200 [get_ports {Disp_VS}]

set_output_delay -add_delay -min -clock [get_clocks {CLK_Display}]  -1.500 [get_ports {Disp_VS}]

好了,到这里,对FPGA输出给ADV7123的信号的约束就算是OK了,接下来全编译工程,然后下载到开发板中,就可以观察到相应的现象了。

如果不出意外,通过此种约束过后。全编译得到的结果下载到开发板后,VGA显示器上显示的摄像头采集的图像又是完全正常的了,不会再有发霉的迹象,和之前将PLLclk[3]信号取反后接给Disp_CLK的现象是一样OK的了。至此,验证了使用IO约束的方法是确实可以解决这个问题的,或者,也可以说是验证了前面说的图像异常问题确实是由IO时序不满足导致的。

好了,到这里,本节内容就算是结束了,深入龙潭并看到了真龙。

纳尼?起这么个让人热血沸腾的名字,结果你就让我看这个?眼看着你进深入龙潭,想象着你与恶龙搏斗的场景,本以为你德胜归来,好歹也让我们一睹真龙,结果你就拧条水蛇出来跟我们说你看到龙了?我们就这样静静的看着你给出一串代码,然后编译两次工程,你就告诉我们通过约束解决了?不,我们想看的不是这个,而是想看你如何一步一步进行约束的,更想知道你的约束中这些参数是怎么来的,最想知道你为啥要这样约束。

嘿嘿嘿,如果你真的有了上述疑问,我就真的是挺开心了,证明我真的提起了诸位对时序约束的兴趣和好奇心,并且展示出了时序约束的魅力,既然这样,那么接下来我再来和大家讲理论,讲步骤,大家也就能看的静静有味,能够边看边消化了。

好了,看着大家这么的急切的心情,我也就不卖关子了,预知后事如何,且听下回分解吧。

各位慢聊,我还有事,先走了。(隐约感觉昨天那伙要打我的人马上就要追上来了已经)

作者: 小梅哥., 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-452191.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

文章评论5条评论)

登录后参与讨论

curton 2019-9-3 21:08

学习了

用户284745 2019-7-14 22:41

纳尼?!

用户3893525 2019-7-5 21:51

我裤子都脱了你就给我看这个?

用户1854426 2019-7-5 10:00

想知道 -from clk[3]-to [get_ports {Disp_PCLK}]这里的max和min delay的5和1ns分别是怎么确定的?这里没看明白。
后面的对ADV7123数据和控制信号的约束时间在其datasheet的TIMING SPECIFICATIONS看得到分别对应的是其Data and Control Setup和Hold的时间

用户3893407 2019-7-4 18:00

小梅哥,这些时序约束是手写的还是用Quartus II中的工具自己生成的,如果是手动约束的,延时的时间怎么确定的
相关推荐阅读
小梅哥. 2019-09-04 22:10
小梅哥FPGA时序分析笔记(6.2)深入现象看本质——庖丁解牛之FPGA内数据传输模型
通过上一节,我们了解了FPGA内部数据的传输形式,接下来我们就可以根据上一节的内容来总结一下FPGA内部的数据传输模型了。 时钟和数据传输路径 通过上一节内容中,我绘制的那个FPGA内部数据在逻辑...
小梅哥. 2019-09-01 21:28
小梅哥FPGA时序分析笔记(6.1)深入现象看本质——庖丁解牛之FPGA可编程原理
上一次发博客,已经是2个月前了,这中间两个月,干了件很有意义的事情,尤其是对于自己来说,感觉学到了非常多的知识和经验,每天都很忙,忙到没时间逛网站博客,终于忙完闲下来了,连载的事情可不能忘,终于可以书...
小梅哥. 2019-06-30 11:07
小梅哥FPGA时序分析笔记(四)I/O时序定成败——化险为夷
小梅哥FPGA时序分析从遥望到领悟系列没有遇见过I/O时序问题,没有通过I/O约束方式实际解决过I/O时序问题,就很难明白I/O约束的重要性,也很难相信各种EDA软件真的有那么的傻白甜。 我遇到的最...
小梅哥. 2019-06-22 10:32
小梅哥FPGA时序分析笔记(三)时钟约束真重要——事实说话
小梅哥FPGA时序分析从遥望到领悟系列以前,那是在以前,经常有网友(原谅我行文动不动就是网友说,网友问,毕竟我是卖开发板的,正面接触学FPGA的网友相对多一些,所以这些也都是事实存在的事情)问我:小梅...
小梅哥. 2019-06-21 10:33
小梅哥FPGA时序分析笔记(二)时钟质量是生命——初遇时序
小梅哥FPGA时序分析从遥望到领悟系列第一次遇到时序问题并通过相应的手段解决问题,算是2年前做百兆以太网图像传输的时候了吧。当时遇到的问题为:同一个工程,每次编译结果的效果都不一样,有的时候编译了,下...
我要评论
5
61
关闭 站长推荐上一条 /2 下一条