【红色飓风Nano二代测评】Xilinx DCM IP Core研究及使用方法
1赞Xilinx DCM IP Core研究及使用方法
—CrazyBingo
—20140506
信誓旦旦的,三下五除二,凭借Altera FPGA的丰富经验,一晚上搞定了Xilinx FPGA的基本开发流程,并且搞定了按键、LED灯等的驱动。很哈皮。。。哈皮。。。
不过不要高兴得太早,好戏还没开始呢。。。这FPGA只用外部的50MHz晶振时钟,浑身都不自在。强大的时钟网络,怎么可以不用呢???于是乎,开始调用IP Core,拿来主义,搞定PLL即可。。。
但是事实上,真没那么顺利。。。
首先搞不懂什么DCM、PLL之类的东西。。。。虽然这不是问题的重点。。。其次,各种警告让我崩溃,摸不着头脑。。。一鼓作气,看Sparatan的用户手册,了解到XC6S1X16有2个CMT。
而每个CMT包括2个DCM和PLL。DCM为数字时钟管理器,而PLL为模拟锁相环。Altera的FPGA只有PLL,因此对这个太熟悉了。。而DCM为Xilinx的数字时钟管理器,能输出DCM =CLK0 + CLK90 + CLK180 + CLK270 +CLK2X + CLK2X180 + CLKDV + CLKFX + CLKFX180这9中不同的时钟。但是不知怎么的。。。我竟然出问题了。。。不过一开始没搞清楚,很激动的定制了clock_wizard这个ipcore,如下图所示:
由于在Altera FPGA设计中,鄙人已经有了完整的时钟管理架构,因此直接移植sys_ctrl_pll模块,该模块在Quartus II中的RTL图如下所示:
即系统首先经过一段时间的延时(由于刚上电期间,外设、IC等不稳定),在这段时间延时后,开启PLL,等到PLL所想输出信号。当PLL输出锁相完成信号后,此时将外部输入的复位信号同步处理后的结果,通过与运算,输出最终的结果。该理论经过无数次理论与实际的验证,因此果断直接移植啊。。。。
由于一开始没搞清楚状况,莫名其妙的我定制的为DCM,而不是PLL。不过结果与Altera的PLL,完全一样,因此直接例化了,如下所示:
//----------------------------------- //system pll module wire pll_rst = 1'b0; wire locked; wire clk_out1; sys_dcm u_sys_pll ( .CLK_IN1 (clk), .RESET (pll_rst), .LOCKED (locked), .CLK_OUT1 (clk_c0) );
结果蛋疼的,在编译的时候出现错误,如下所示:
询问+查看sys_dcm的时候,发现模块中,软件自动添加了输入Buffer与输出Buffer,据说是为了提高信号的驱动能力(但实际上我也不是很清楚),如下所示(输出也有一个Buffer):
根据警告,可以直接将clkin1_buf删除,或者在定制Ipcore的时候,的确有一个选项,用以选择输入时钟是否需要Buffer,如下所示。
直接修改sys_dcm模块,或者通过ipcore修改后的结果如下所示。但这修改的只是源端时钟,而非终端。。终端依然有Buffer存在。。。
这样就不会有这个警告了。。同时流水灯跑的欢快。。。不过默认有Buufer,应该也有他的道理吧。。。仔细分析原因,源于我将输入的clk给DCM的同时,也给system_delay模块进行延时了。而DCM模块中有一个buffer,因此该时钟信号给模块1的同时,又通过buffer给模块2.。。至于这样为什么不行,摸不着头脑。。。但貌似我这样设计,的确有不合理的地方。。。
于是修改鄙人的sys_pll_ctrl模块,将system_delay模块的时钟换成clk_c0,即DCM输出的时钟,此时万事OK了,不管是否添加Buffer。。。貌似“科学了”。。。更仔细的分析sys_dcm模块,部分原语言如下所示:
正如Spararan DS160手册所说的那样,DCM输出9路时钟,分别为相位、2倍频、2分频、以及小数分频的时钟,手册说的如下:
序号 |
时钟 |
描述 |
1 |
CLK0 |
输出0相位差的时钟,并连接反馈时钟CLK_FB |
2 |
CLK90 |
输出90°相位差的时钟 |
3 |
CLK180 |
输出180°相位差的时钟 |
4 |
CLK270 |
输出270°相位差的时钟 |
5 |
CLK2X |
输出2倍时钟 |
6 |
CLK2X180 |
输出2倍、180°相位差的时钟 |
7 |
CLKFX |
输出CLKIN*M/D后的时钟 |
8 |
CLKFX180 |
输出CLKIN*M/D、180°相位差的时钟 M∈[2,32],N∈[1,32] |
9 |
CLKDV |
与CLK0对齐的小数分频时钟 分母∈[2,16]/1.5、2.5…15.5,以及2 |
备注:关于CLKDV的定义,不是看的很懂。。。求指点……
对于一个对代码的移植优化有强迫症的人,即便不用Xilinx原语来操作,也无法承受每次都要重复的定制IPCORE。。。。果断删除了sys_dcm.xco、sys_dcm.xise,如下所示:
此时添加sys_dcm文件,如下所示。。。(操作与Altera Quartus II完全一样)
打开sys_dcm,分析相关参数。由于前面已经研究完毕了DCM的9条时钟线,极其意义。。这些都变得轻松愉快了。。。这里左图为原始生成的2倍频(100MHz)的DCM原语描述,右图为笔者8倍频生成的400MHz时钟的原语描述,分别如下所示:
(1)从左图可见,2分频为FALSE,相位移动为NONE,因此乘除因子都不用管。。。。同时时钟从CLK2X输出,可见输出时钟为CLKIN*2,且无相位差。。。
(2)从右图可见,鄙人添加了clkfx并且CLKFX输出,将CLKFX_MULTIPLY改成8,因此最终频率理论上为400MHz。当然此时由于从clkfx输出,在最后的输出Buffer中需要做修改,如下:
此时,8个LED的流水灯,在极其快的速度下,努力的奔跑,亮瞎你的狗眼。。。。。哈哈。。。搞定。。此时,,可以脱离残酷的IPCORE GUI的崩溃速度了。。。。既然我们还没有直接写原语那么牛逼。。但至少。。我们可以一劳而永逸了。。。。
不过又出现了一个疑问:关于CLKFB,手册说With CLK0 Connect to CLKFB、、、但实际上我修改CLK0 = CLKFB后,即便CLKFB = CLK2X,也没出问题。。。。。求大神解释。。。
总结:就目前了解,DCM跟PLL相比,时钟与相位的生成比较欠缺。。但是方便。。。。2个CMT= 2个DCM + PLL,的确够用了。。。。