ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FPGA与CYUSB3014实现USB3.0高速传输:320MBps方案解析

FPGA与CYUSB3014实现USB3.0高速传输:320MBps方案解析 做FPGA和USB3.0对接这块CYUSB3014也就是大家常说的FX3绝对是一个绕不开的芯片。我这些年经手过不少高速数据采集的项目从ADC采样到图像传感器抓拍几乎每次往外传数据都要靠它。标题里说的320MBps这个数字不是拍脑袋定的而是基于USB3.0 SuperSpeed实际有效带宽算出来的一个稳妥目标。这篇就结合我用Vivado配置FPGA、和FX3对接的完整经历把原理、配置、实操步骤和遇到的坑都梳理一遍给准备上手的朋友一条能走通的路。1. 方案选型与核心逻辑为什么是CYUSB3014 FPGA1.1 这套组合到底解决了什么问题先说说这套组合解决的核心痛点。FPGA最大的优势是接口灵活、并行处理能力强适合做数据采集、信号处理这类高速任务。但FPGA本身没有像样的USB控制器如果非要在FPGA里用软核做USB协议栈光协议处理就能吃掉大量逻辑资源而且USB3.0的5Gbps信号速率普通逻辑很难稳定跟上。CYUSB3014是英飞凌原Cypress收购后归属的EZ-USB FX3系列芯片内集成了USB3.0 PHY和可编程的GPIF II接口。GPIF II本质上是一个可配置状态机支持多种接口协议最常用的就是同步从FIFO模式。这时候FPGA只需要以主控的身份按照时序要求读写FX3里的FIFO缓冲区USB协议部分完全交给FX3处理。数据通路变成数据源 - FPGA逻辑 - GPIF II接口 - FX3内部DMA - USB PHY - PC。每段都由最合适的硬件来完成性能和可靠性都有保障。这个方案解决的最大问题就是协议分担。FPGA不碰USB协议只需要管住数据流FX3不关心数据从哪来只负责把数据搬上USB。两个器件各干各的活接口清晰调试也方便。实际项目里我接触到的绝大多数USB3.0高速采集方案都是这个架构。1.2 320MBps这个数字是怎么来的很多人看到320MBps这个数字第一反应是质疑USB3.0不是能到5Gbps吗怎么换算过来才400MBps这里有个基本物理常识要先确认。USB3.0的5Gbps是线速率而SuperSpeed使用8b/10b编码每传10bit实际只有8bit有效数据所以理论有效带宽就是500MB/s。再加上USB协议本身的包开销、握手、校验纯突发传输能到400MB/s左右已经是极限了。我们再算FPGA侧。GPIF II接口在同步FIFO模式下数据位宽32bit时钟频率可以跑到100MHz甚至更高。32bit x 100MHz 400MB/s这是GPIF II接口的理论能力。所以如果FPGA侧能以接近满速的方式连续写FIFOUSB侧也能持续接收整体达到350MB/s以上是可能的。那为什么标题选320MBps而不是380MBps或400MBps从我实测经验来看320MBps是一个留足余量的工程安全值。USB传输过程中上位机软件处理、DMA中断响应、驱动缓冲、PC总线调度都会有瞬时波动如果把硬件速率推到顶任何一环节抖动都会造成丢数据或者重传。而跑到320MBps硬件还保留大约20%的裕量系统稳定性会好很多。做产品的朋友应该都有体会跑的满不如跑得稳。1.3 另一类方案的对比PCIe、千兆网、嵌入式处理器有人会说传数据为什么不用PCIe或者千兆网这里也要说清楚适用场景。PCIe吞吐率高延迟低但是需要电脑主板有PCIe插槽笔记本基本无缘而且PCIe接口逻辑在FPGA里占资源明显更多复杂度和成本都高。千兆网只有125MB/s的带宽跑不到300MB这个量级除非上万兆网卡但那个成本就上去了。嵌入式处理器方案比如ARMUSB3.0开发门槛低但当数据率特别高、要求低延迟实时转发时ARM的处理能力往往跟不上而且CPU介入数据搬移也会引入额外延迟。CYUSB3014的优势在于它内置了DMA控制器数据从GPIF II进来到USB出去全程不需要CPU参与纯硬件数据通路。这就很适合FPGA这种不间断、大流量、实时性要求高的应用场景。嵌入式方案适合控制类项目而咱们这套是高速数据传输类架构上就不太一样。2. 硬件架构与GPIF II接口的拆解2.1 GPIF II是什么别把它想复杂了GPIF II全称是General Programmable Interface II你可以把它理解成一个可配置的高效DMA引擎。FX3内部有多个DMA通道每个通道有一对socket一头连GPIF II引脚一头连USB端点。FPGA读写GPIF II的逻辑实际上就是在往socket对应的缓冲区里塞数据或者取数据。GPIF II支持多种模式同步从FIFO、异步从FIFO、SDR、DDR、并行摄像头接口等。做高速USB3.0传输最常用、性能最好的就是同步从FIFO模式。这个模式下FX3相当于一个从设备FPGA是主设备FPGA提供时钟和数据由写使能信号控制数据写入。我第一次接触GPIF II的时候被它那一堆FLAGA/FLAGB/SLWR/SLRD/SLOE/PKTEND信号弄得晕头转向。后来总结成一句话就好理解了这些信号一起构成了一个带流控的、可以随时打标记的FIFO读写接口。SLWR是写使能SLRD是读使能SLOE是输出使能PKTEND是强制结束当前数据包FLAG系列信号是FIFO的状态反馈。FPGA侧的逻辑就是围绕这些信号设计状态机。2.2 同步从FIFO模式最常用的握手方式同步从FIFO模式简单来说就是所有信号都在同一个时钟的上升沿采样。时钟PCLK可以由FX3提供通常是100MHz也可以用FPGA提供。用FX3时钟的好处是天然同源时序上不用额外对齐。FPGA侧把PCLK当作接口逻辑的主时钟所有状态跳转、数据输出都以PCLK的上升沿为基准。工作流程大约是FPGA要发数据时先看FX3的FIFO满信号FLAGB或者FLAGB反映的是某个DMA线程的满状态。如果未满FPGA把数据放到DQ[31:0]总线上拉低SLWR一个时钟周期数据就被写入FX3缓冲区。如此反复。当一帧数据发完FPGA可以拉低PKTEND一个周期告诉FX3当前包结束这样USB侧的短包或精确包长就能被正确处理。读方向就是反过来FPGA看FIFO空信号FLAGA如果非空拉低SLRD然后在下一个时钟周期从DQ总线上把数据读走。整体时序简单但细节里有一些延迟问题比如FLAG信号从FX3输出经过PCB走线再到FPGA需要几个时钟周期才能稳定采样这在高速传输时必须考虑。我的经验是在FPGA设计里对FLAG信号打两拍做同步用同步后的信号做状态机判断能避免很多毛刺问题。2.3 FPGA侧要准备哪些接口信号先列一个标准的GPIF II同步从FIFO接口的信号清单方便对照信号名方向作用PCLKFX3输出/外部输入接口工作时钟常用100MHzSLCS#FPGA输出片选可以固定拉低SLWR#FPGA输出写使能低有效SLRD#FPGA输出读使能低有效SLOE#FPGA输出输出使能读模式下用PKTEND#FPGA输出包结束信号低有效A[1:0]FPGA输出线程/缓冲区地址选择DQ[31:0]双向数据总线FLAGA~FLAGDFX3输出状态标志可配置这个表里实际设计中经常省略SLCS#固定拉低FLAG信号只需要一个满和空即可。A[1:0]用于选择不同的DMA线程可以理解为选择FX3内部的哪组缓冲区。做单向传输通常只用线程0两个方向同时传就用线程0和线程1A[1:0]分别接00和01。这里有个非常关键的点DQ总线是双向的。FPGA侧IO必须配置成Tri-state用方向控制引脚切换。Vivado里写inout逻辑时要小心不要出现多驱动否则综合出来的电路会有问题。我在早期项目里吃过这个亏信号方向控制没写好导致数据总线冲突仿真正常上板就数据错乱。3. Vivado工程搭建从零到能跑通的配置流程3.1 版本选型与环境安装的几个坑做这个项目Vivado版本选型没有太多讲究2020.2、2021.1、2022.2我都用过都能正常工作。如果手上开发板附带例程尽量用配套版本省去兼容性问题。没有特殊依赖的话我推荐Vivado 2020.2或者2022.2这两个版本社区活跃遇到的坑很容易搜到方案。安装Vivado有个容易被忽略的问题就是安装路径和许可证。正版License如果是按节点锁定的要注意网卡绑定安装时别乱改电脑网卡或者禁用虚拟网卡不然License会失效。破解版不在讨论范围内但正版也偶尔会出问题最常见的是License环境变量设置不对。Vivado启动时读取LM_LICENSE_FILE或VIVADO_LICENSE_FILE环境变量如果没设置好启动会提示缺少license。还有一个坑winpcap和Vivado安装有时候会冲突。Vivado的安装程序和WinPcap在某些环境下会较劲如果装不上去先卸载旧WinPcap装完Vivado再重新装一遍。还有一个常见问题是安装到一半卡在某个驱动环节这种情况多发生在Windows系统建议安装时关闭杀毒软件以管理员身份运行。3.2 创建工程与IP配置先解决时钟新建一个RTL工程后第一件事是添加时钟约束和引脚约束。如果开发板上有独立时钟晶振可以直接把时钟引脚约束进去。在这一步很多人会直接把时钟接到内部逻辑但更合理的做法是用Clocking Wizard IP生成需要的时钟域。拿这个项目举例FPGA和FX3的接口时钟是FX3输出的100MHzFPGA内部数据源可能是另一个时钟域比如DDR采集是250MHz图像传感器是150MHz两边频率不同直接用异步逻辑跨域非常危险。所以应该在工程里例化一个FIFO IP输入侧接数据源时钟输出侧接100MHz的PCLK天然解决跨时钟域问题。创建FIFO IP时有一个配置项需要注意Output Data Width输出数据位宽。GPIF II是32bit所以FIFO的输出宽度也配成32bit。输入宽度可以根据数据源任意配置比如16bit或64bitFIFO会自动做位宽转换。FIFO的读时钟选PCLK读使能由状态机控制。此外FIFO的Almost Full/Almost Empty信号要拉出来配合FX3的FLAG信号做流控防止数据溢出。3.3 用Xilinx FIFO IP把跨时钟域问题直接干掉跨时钟域是FPGA设计里最容易翻车的地方。如果信号从一个时钟域直接进另一个时钟域不做任何同步处理综合工具不会报错但上板之后就会出现偶发的数据错误或逻辑错乱。这种问题排查起来非常头疼因为现象不是每次都出现比如偶尔丢一帧、偶尔多传几个错误字节。用FIFO IP是最标准、最偷懒也最可靠的解法。Xilinx FIFO IP内部已经处理好了格雷码指针同步和亚稳态问题只要把两个时钟域的数据分别接在FIFO的写端和读端问题基本就解决了。唯一要注意的是FIFO的复位信号也需要同步。标准做法是用Xilinx提供的Proc Sys Reset IP或者自己写一个异步复位同步释放的小模块保证FIFO复位信号和对应时钟域时钟是同步关系。我用的是Xilinx FIFO IP的Standard FIFO模式读写指针、数据计数、满空标志都齐全。实际配置时注意把Read Data Count打开方便状态机判断当前FIFO里有多少数据。这个信号在控制突发长度时很有用。4. FPGA内部逻辑实现状态机、时序与调试技巧4.1 发送状态机的设计思路发送状态机是整个FPGA侧的核心我用一个三段式状态机来实现写FIFO到GPIF II的处理。状态不算复杂分成IDLE、WAIT_FIFO、DATA_TRANSFER、WAIT_FLAG、PKT_END几个状态但每个状态的边界条件要理清楚。IDLE状态下FPGA等待数据源的触发信号。比如ADC采集完一帧或者FIFO中的数据深度达到某个阈值就发起一次传输。这时状态机跳转到WAIT_FIFO检查FIFO的Empty信号。如果FIFO非空再检查FX3的FLAGB满信号未满则拉低SLWR从FIFO读出32bit数据放到DQ总线上状态机进入DATA_TRANSFER。DATA_TRANSFER状态下每个PCLK上升沿如果FIFO非空且FX3未满就持续写入数据。这个状态可以一直循环到FIFO读空或者一帧数据全部发完。一帧结束后拉低PKTEND一个周期通知FX3当前包结束然后回到IDLE等待下一帧。这里有一个细节值得说一下就是PKTEND处理。USB批量传输是按包进行的包长度通常对齐512字节或者1024字节。如果最后一包数据不满一个包长必须通过PKTEND告诉FX3强制发送短包否则FX3会一直等后续数据造成传输卡住。很多新人在调试时发现数据总是差最后几个字节就是这个原因。4.2 关于空满信号和反压处理的思考数据通路里反压是最常见的问题。所谓反压就是下游处理不过来必须通知上游先暂停。在GPIF II链路里FX3的FLAGB满信号是最直接的反压信号FPGA看到FLAGB有效就必须暂停写入。FLAG信号来自FX3内部经过引脚输出、PCB走线、到FPGA输入这中间有几纳秒的延迟。在100MHz时钟下一个周期是10ns信号传输延迟加上同步打拍相当于延迟了2到3个周期。这意味着FPGA即使看到FLAGB有效后立刻停止写入前面还有几个周期已经写入的数据可能需要被丢弃或者重新处理。对于一般的数据采集场景多写几个周期通常问题不大因为FX3的FIFO本身有一定深度。但如果数据源速率刚好在临界值这几个周期的溢出就可能导致丢数。我的做法是在FPGA内部额外加一个Almost Full阈值信号。FX3的FLAGB可以配置成在FIFO快满时提前触发而不是等真正的满信号。比如配置成还剩4个条目的空间时就报告满这样即使有几个周期的延迟数据也不会溢出。FX3的GPIF II配置工具里有这个选项功能叫Watermark设置好之后能显著提高可靠性。4.3 仿真先行Vivado仿真提速与在线调试ILAFPGA的开发流程一定不能跳过仿真。这个接口逻辑在真机上调试一旦出错光靠LED和串口很难定位问题。所以我的习惯是先写好测试平台testbench把GPIF II从设备的行为模型搭出来先在仿真里把状态机跑通再上板。Vivado自带的Xsim仿真器完全够用但大规模工程仿真确实慢。提速的办法有几个。第一仿真时只仿真核心逻辑模块不要把整个系统顶层拿去做全局仿真尤其是例化了DDR控制器、CPU软核的大工程仿真时间会暴长。第二控制仿真时间范围。这个接口状态机跑几十微秒的仿真足够检查时序不必跑完整个一秒钟的数据流。第三testbench里用任务封装数据生成循环写数据时直接比对齐快。不过仿真归仿真上板后仍然可能出问题。我习惯在FPGA内部例化ILAIntegrated Logic Analyzer核把PCLK作为采样时钟观察SLWR、PKTEND、FLAGB、FIFO读使能、数据输出等关键信号。ILA的触发条件设为FLAGB下降沿看看FLAGB拉低时状态机的行为是否符合预期。Vivado的硬件管理器可以实时看到波形调试效率比传统示波器高很多。实际项目里几乎每一次高速率调试都离不开ILA强烈建议从一开始就预留几个ILA通道。5. FX3固件侧配合别只盯FPGA固件才是关键5.1 固件框架选择与DMA配置FPGA跑对了还不行FX3侧固件不配合数据一样传不上来。这里明确一个概念FX3是一个可编程芯片它内部有一个ARM926EJ-S核需要烧录固件才能工作。Cypress官方提供了FX3 SDK里面有完整的固件例程、驱动和工具。用到这套方案固件里最重要的就是DMA配置。FX3的DMA可以配置成手动模式或自动模式。手动模式下固件CPU需要参与数据搬运速度上不去自动模式下DMA直接在GPIF II和USB之间搬数据CPU只负责配置不参与数据通路速率才能达到几百MBps。所以做高速传输必须用自动DMA模式。具体配置思路是创建一个DMA通道生产者socket配置为GPIF II消费者socket配置为USB Bulk端点。把缓冲区数量设置成多缓冲比如4到8个每个缓冲区大小2KB或4KB。这样当GPIF II侧写入一个缓冲区时DMA控制器自动切换到下一个缓冲区同时USB侧开始搬运写满的缓冲区形成流水线操作。5.2 描述符和驱动为什么要装.infFX3上电后如果没有有效固件它默认进入USB Boot模式这时候电脑识别到的是一个VID/PID为04B4/00F1的设备需要手动烧录固件。量产场景下通常把固件烧录到FX3外接的SPI Flash里上电自动加载。开发调试时可以用USB Control Center工具把固件直接下载到FX3的RAM里运行方便快速迭代。固件工程编译出来是一个.img文件同时需要编写一个.inf设备驱动描述文件。Windows系统首次插入设备时会提示安装驱动指定的.inf告诉系统该加载哪个驱动。Cypress官方提供CyUSB3.sys驱动用于Windows下访问USB3.0设备的通用驱动。很多人在这一步卡住设备管理器里显示感叹号多半是.inf文件没配对或者签名问题。Windows 10/11的64位系统驱动强制签名如果驱动没签名要进高级启动菜单选择禁用驱动签名强制才装得上。做产品的话更推荐给设备写自己的WinUSB驱动用微软自带的WinUSB.sys配合一套自己的上位机通讯接口比CyUSB的私有驱动更通用也免去许多签名麻烦。5.3 实测工具与测速方法固件和驱动都就绪后怎么验证数据率和正确性Cypress官方提供了一个上位机工具叫StreamerStreamFX3可以用来做基准测试连续读取数据并在PC内存里统计吞吐率。它能直观显示当前USB链路的实际速率是判断320MBps目标是否达标的直接工具。用Streamer测速时有几个参数值得关注。一是块大小通常设置成1MB或者4MB每次请求的传输块越大吞吐率表现越好。二是传输模式选Bulk模式。三是超时时间如果USB总线不稳定会出现超时错误。测速前先确认USB连接没有经过Hub直接插电脑主板USB3.0口Hub会引入延迟甚至造成带宽瓶颈。除了测速还要做数据完整性校验。我通常的做法是在FPGA侧生成一个递增数序列比如32bit计数器PC端接收后做递增校验。如果收到的数据是0,1,2,3...按序递增说明链路稳定。如果出现乱序或者跳变说明某个环节丢包或错位。这个测试数据发生器逻辑很简单但却是排查问题的利器。6. 常见问题与排查实录6.1 枚举失败、设备驱动感叹号上电后电脑识别不到设备这是我被问得最多的问题。先区分两种情况一是FX3还没烧录固件处于Boot模式此时电脑应该出现Cypress FX3 USB BootDevice设备。如果连这个都看不到检查USB线、电源和FX3的时钟。FX3需要外部晶振通常是19.2MHz晶振不振PHY不懂枚举必然失败。如果Boot设备正常但烧录固件后设备未被识别先确认固件是否加载成功。用USB Control Center下载固件后电脑应该出现新的USB复合设备。这里最常见的问题是.inf文件匹配失败驱动装不上。在设备管理器中手动更新驱动选择.inf文件所在目录强制安装一次多半能解决。另外检查VID/PID是否和.inf文件中的定义一致不一致的话驱动不会匹配。6.2 速度上不去只有几十MBps如果链路能通但速度只有70MB/s甚至更低这属于性能问题而不是通断问题。按照我的经验排查顺序是先确认电脑端连接的是USB3.0口蓝色芯的口才是USB3.0插到USB2.0口上速度只能到40MB/s左右。再查USB线很多声称支持USB3.0的线实际质量很差换一条线试一下。这两个外部条件太容易被忽略。然后看FX3固件的DMA配置。手动模式是最常见掉速原因先检查固件代码里的CyU3PDmaChannelCreate参数确认使用了CY_U3P_DMA_AUTO_TYPE。再看缓冲区数量缓冲区太少会导致DMA频繁需要切换流水线暂停吞吐率下降。建议配置至少4个缓冲区。最后看FPGA侧如果状态机随机访问FLAG有太多等待周期也会拖慢速度。可以抓ILA波形看SLWR有效期间是否有FLAGB拉高的间歇。如果FLAGB拉高频繁说明FX3的USB侧消费速度没跟上问题方向就转向USB协议和PC端驱动。6.3 时序违例、布局布线和信号完整性问题如果综合实现后时序报告里有红色FAIL而且点开路径看到是GPIF II接口相关的跨时钟路径那多半是约束没写对。GPIF II接口信号的约束需要配置成虚假路径或是跨时钟处理因为数据总线和控制信号是跟随PCLK的实际是由FX3或者FPGA输出的同步信号。如果Vivado默认按内部时钟约束这些引脚会报告很严重的违例。解决方法是在XDC里对DQ数据总线设置SET_MAX_DELAY/SET_MIN_DELAY约束或者直接设成Input Delay基于PCLK。对于FLAG输入信号可以设置false path因为FPGA内部已经打拍同步不需要在单周期内达到时序要求。布局布线如果还是紧张把接口逻辑的IOB属性关了允许寄存器放进IOB常常能减少路径延迟。上板级的信号完整性问题更隐蔽但会造成偶发数据错误。DQ总线和控制信号尽量走同一层保持长度接近避免跨分割。USB3.0差分对必须按90欧姆差分阻抗控制走线尽量短串接0欧电阻或者共模电感谨慎选择。FX3的数据线如果走太长信号边沿变缓在100MHz下容易采样出错。我经历过一次调试现象是低速正常、高速数据率上到200MB/s以上就报错最后发现是DQ总线等长没做好调整走线后问题消失。6.4 比特流生成失败与固化问题Vivado生成比特流过程偶尔会卡住或者报错。最常见的问题出现在IP核配置更改后没重新生成综合产物导致综合和实现阶段不一致。我的习惯是每次改完IP配置先右键IP核选择Reset Output Products再Generate Output Products最后再综合。这个流程虽然繁琐但能避免很多莫名其妙的错误。固化到SPI Flash是另一个话题。Vivado里选择Generate Bitstream后再执行Write Binary Configuration File生成.bin或.mcs文件通过JTAG加载到配置Flash中。要注意的是如果FPGA配置引脚的电平标准设置不对Flash配置模式会失败。比如开发板用的是x4模式还是x1模式需要和Flash的实际接线匹配。而FX3固件固化是独立的它固件烧在SPI Flash里用FX3 SDK的Cypress Programmer工具直接烧录。千万不要把FX3固件和FPGA比特流混在一个Flash里除非你用了专门的配置管理方案否则系统复杂度会急剧上升。常规做法是两块独立Flash各自加载互不干扰。7. 写在最后的经验这套FPGAFX3方案我前前后后调过不下五个版本。每次做新项目硬件平台换了、数据率要求变了、Vivado版本也升级了但核心逻辑基本没变过。回头看最影响成败的反而不是那些高深的技术点而是几个基础功夫时序约束写清楚、仿真testbench做充分、ILA信号留够、PCB高速走线靠谱。给新上手的朋友一个建议不要一上来就追求320MBps先把链路通起来。我习惯分三步走第一步跑通FX3官方例程用Streamer自测USB链路能到多少速度第二步FPGA侧接一个简单的数据源比如计数器把数据发到PC验证正确性第三步把数据源换成真实业务数据逐步提高速率到目标值。每一步都验证缩小排查范围比一次性搞定要轻松得多。另外数据校验模块从第一天就加上。不管是什么数据源在FPGA里生成一个32bit递增计数器作为测试序列是一个成本极低但价值极高的装备。它能让数据问题一出现就定位是链路还是业务逻辑省下大量调板时间。这套系统成熟之后可扩展的方向也很多。比如配合DMA和DDR缓存可以实现更长时间的连续采集通过GPIF II的多线程接口可以做到双向同时传输再加上上位机的软件协议就能拼出一个完整的数据采集系统。但第一步始终是把USB3.0的320MBps路先跑通。把这篇文章里的路子走一遍你会少走很多弯路。
返回列表