由于项目需要,对QSPI SLV模块进行原型验证,FPGA使用的是Xilinx ZCU106开发平台,该平台拥有PS和PL两部分。因为我们有定制的上位机,因此只需要使用PL逻辑部分即可。
Xilinx ZCU106开发详解(Xilinx Zynq UltraScale+ MPSoC)_zynq ultrascale+ zcu106资料-CSDN博客https://blog.csdn.net/lixiaolin126/article/details/83998558FPGA原型验证的主要目的是将RTL代码实现在FPGA平台上,可以高效直观的看到验证效果,例如本次的QSP SLV模块就是一个典型应用,非常适合在FPGA验证平台上进行验证。
第一步 了解概念,明确目的
第一次做FPGA原型验证,需要对整个流程有一个明确的概念。使用vivado对RTL代码进行综合,实现,将其下载到FPGA中,然后使用上位机向FPGA发送QSPI相关指令,例如读写寄存器,特殊指令,图像视频数据等等。
第二步 IO映射
根据ZCU106官方文档选取需要的IO和RTL代码的顶层接口进行一一对应,其中包括QSPI的6根io,系统时钟有1个,外部复位1个,led灯1个,测试端口若干个。使用的命令如下,选取合适的IO进行设定,其中需要注意的是QSPI_CLK作为时钟信号,需要create clk定义时钟信息,并且需要将QSPI CLK信号制定到一个clk io上,在vivado中可以看到所有io的性质,六边形的io即为clk io。
set_property PACKAGE_PIN F5 [get_ports {led_tri_o[0]}]
set_property IOSTANDARD LVCMOS15 [get_ports {led_tri_o[0]}]
而代码中多余的输入输出端口为了方便可以忽略,综合实现阶段如果有相关的error可以将其ignore,而更严谨的做法是将其在代码中删除,顶层文件在FPGA项目中需要单独维护,这样即减少了FPGA资源消耗,又完善了代码版本管理。
ZCU106中提供了许多时钟可以作为系统时钟,可以根据时钟频率选择适合的时钟,注意区别PS和PL的时钟,需要选择提供给PL使用的时钟,例如LVDS的两组时钟,LVDS差分信号可以支持高频时钟,相比于单端时钟,更加稳定,波形更好。在IP目录中选择生成clk,输入填选取的时钟频率,输出填系统时钟频率即可。
第三步 define FPGA
在RTL代码中需要对某些部分进行FPGA处理,例如CLK GATING,MEMORY等等。因为clk gating会极大的增加FPGA时钟资源,可能会导致整个项目放不下去,因此需要将clk gating全部打通。memory则需要使用IP目录中生成的sram,若是sram较少,则可以一一生成后进行例化,替代原本的仿真模型,可以在filelist中进行替换,保持接口一致即可。但是比较大的项目中通常会有上百块sram,此时需要使用脚本直接生成vivado能够识别的sram模型,在综合时,FPGA会自动识别出sram,并使用FPGA自带的sram资源进行替换。
第四步 综合实现,远程下载
完成上述准备工作后即可完成vivado的综合实现流程,最后生成bit stream文件后,可以使用远程调试功能,直接将服务器上的bit文件直接下载到本地电脑上连接的FPGA中,需要本地电脑也下载安装vivado或者仅下载调试程序。
第五步 原型验证,调试测试
根据本次验证目标可以整理出如下2个流程,
- QSPI读写寄存器,SPI读写寄存器
- QSPI发送视频数据,内部数据流是否接收到正确数据
首先应该对上位机下发的指令进行检查,保证其正确性,可以使用逻辑分析仪对其进行信号采样,检查时钟频率,数据发送格式是否完整和正确。完成读写寄存器的测试后,可以认为QSPI基础功能无误,此时需要检查内部信号,需要将内部信号连接到测试相关的IO上,即可直观看到内部信号是否与预期一致。
第六步 遇到的问题
在读写寄存器的时候发现在读特定数据时会有错误,首先改变逻辑分析仪的采样频率试图分析问题,但收效甚微,其次改变FPGA对IO的驱动电流,默认为12mA,修改为4mA,依旧没有进展。
随着尝试的数据越来越多,最终定位到QSPI 4根信号线或3根信号线同时翻转时,会固定出错,怀疑是电流串扰,因为数据线的大批翻动,电流急剧变化,引起了时钟信号的干扰。最后将QSPI 3根线和时钟信号接到示波器上,对波形进行反复观察,发现在3根信号同时变化时,时钟信号的波谷反冲相比于其他周期高100mV不到,非常逼近500mV,怀疑是这个波谷反冲产生了毛刺,使得FPGA多接收到了一个时钟上升沿。最后在时钟信号上焊了一个50欧姆的电阻,滤掉了这个毛刺,成功解决了问题。
在这个过程中发现QSPI上位机在回读数据时,setup足足有一个周期,hold几乎为0,为了系统的健壮性,遂检查代码,发现代码中使用上升沿采集输入数据,并且同样使用上升沿发送数据,导致了该问题的产生,因此将代码修改为使用下降沿发送数据,这样当路径延迟很小的时候,上位机即可收到一个setup和hold均为接近半个周期的信号,若是在产品实际应用中,路径延迟较大,那么可以在回读信号时降低QSPI时钟频率,这样路径延迟对于整个时钟的占比大大减小,既可以实现回读信号时保持健壮性。当然该项目回读信号的场景并不多,若是上位机和下位机有频繁的数据交流,则需要尽量减少其间的路径延迟。