大家一定对我上一节的突然结尾表示一脸茫然:我是来学习时序约束的,然后你告诉我时序约束里面IO约束很重要,然我又跟着你的文章继续往下看,本以为你就要讲如何进行IO约束了,结果呢,你一个取反时钟就把我们打发了,不仁义呀。
不仁义那就不仁义吧,不过话又说回来,这种取反时钟的方式解决时序问题,貌似并非是个例,其他很多地方也都有这种操作,比如以太网GMII接口也有这么干的,高速DAC输出也有这么干的,不过有时候是将时钟取反了输出,而有时候则是在FPGA内部使用下降沿作为触发器的采样信号,形式不同,原理一样,效果一样。只是,这么干的人多了,貌似就成了公理,反而我写一个使用时钟上升沿触发寄存器,同时不给时钟取反就直接驱动DAC或者以太网GMII的程序,会被人质疑写错了。既然如此,那就让事实再次来说话吧。还是以第四节讲到的VGA显示的程序为例,这一次,我们不再用取反时钟的方法,而是使用时序约束这种理论上的正统方法来解决这个问题。
先介绍下整个系统吧。如下图所示,在FPGA中,编写了一个名为disp_driver的模块,用来产生VGA时序并将每个像素的三元色值分别输出。同时使用了PLL的clk[3]端口输出74.5MHz的时钟信号,既提供给disp_driver驱动逻辑使用,也作为Disp_CLK引出,接到ADV7123芯片的CLOCK引脚上,作为数据同步时钟。
既然Disp_CLK是输出时钟信号,那么就需要对其加上约束。约束方法很简单,以PLL的CLK[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的数据(R、G、B)和控制(HS、VS)信号进行输出约束了。约束内容如下:
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显示器上显示的摄像头采集的图像又是完全正常的了,不会再有发霉的迹象,和之前将PLL的clk[3]信号取反后接给Disp_CLK的现象是一样OK的了。至此,验证了使用IO约束的方法是确实可以解决这个问题的,或者,也可以说是验证了前面说的图像异常问题确实是由IO时序不满足导致的。
好了,到这里,本节内容就算是结束了,深入龙潭并看到了真龙。
纳尼?起这么个让人热血沸腾的名字,结果你就让我看这个?眼看着你进深入龙潭,想象着你与恶龙搏斗的场景,本以为你德胜归来,好歹也让我们一睹真龙,结果你就拧条水蛇出来跟我们说你看到龙了?我们就这样静静的看着你给出一串代码,然后编译两次工程,你就告诉我们通过约束解决了?不,我们想看的不是这个,而是想看你如何一步一步进行约束的,更想知道你的约束中这些参数是怎么来的,最想知道你为啥要这样约束。
嘿嘿嘿,如果你真的有了上述疑问,我就真的是挺开心了,证明我真的提起了诸位对时序约束的兴趣和好奇心,并且展示出了时序约束的魅力,既然这样,那么接下来我再来和大家讲理论,讲步骤,大家也就能看的静静有味,能够边看边消化了。
好了,看着大家这么的急切的心情,我也就不卖关子了,预知后事如何,且听下回分解吧。
各位慢聊,我还有事,先走了。(隐约感觉昨天那伙要打我的人马上就要追上来了已经)
作者: 小梅哥., 来源:面包板社区
链接: https://mbb.eet-china.com/blog/uid-me-452191.html
版权声明:本文为博主原创,未经本人允许,禁止转载!
curton 2019-9-3 21:08
用户284745 2019-7-14 22:41
用户3893525 2019-7-5 21:51
用户1854426 2019-7-5 10:00
后面的对ADV7123数据和控制信号的约束时间在其datasheet的TIMING SPECIFICATIONS看得到分别对应的是其Data and Control Setup和Hold的时间
用户3893407 2019-7-4 18:00