ARTICLE DETAIL

资讯详情

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

FPGA接USB3.0:CYUSB3014的Slave FIFO时序与状态机设计

FPGA接USB3.0:CYUSB3014的Slave FIFO时序与状态机设计 简介面向FPGA高速USB 3.0开发的CYUSB3014官方例程包适合需要在FPGA设计中集成USB 3.0接口的工程师、研究生及嵌入式开发者也适合有一定Verilog基础、希望深入USB 3.0协议栈的学习者。该压缩包以Cypress官方文档AN65974为背景覆盖从功能验证到系统集成的常见场景。包内共1223个文件压缩后10.25MB。文件构成以Quartus工程文件qsf/qpf、Verilog/VHDL源码v/vhd、时序约束sdc/ucf为主体另有C代码、readme说明以及大量编译中间产物cdb/hdb/obj等。其中源码用于理解数据通路设计约束文件有助于时序收敛中间产物便于复盘综合、布局布线与工程配置。内容预览显示例程覆盖slaveFIFO2b_partial、slaveFIFO2b_ZLP、slaveFIFO2b_streamIN/streamOUT、loopback等多种模式可对照块传输、流传输、零长度包等场景直接复用并学习LTSSM链路训练、包缓冲与流控机制。目前已有608人学习下载。通过学习这份资源开发者可掌握CYUSB3014初始化、DMA传输和错误处理等核心流程减少信号完整性与时序调试成本加快USB 3.0产品落地进程。1. 从 AN65974 出发CYUSB3014 为什么是 FPGA 接 USB3.0 的最短路径做 FPGA 的人想给上位机回传高速数据第一反应通常是 PCIe 或者千兆网。这两条路都成熟但驱动、DMA、协议栈的工程量不小如果项目只需要 200MB/s 左右的有效带宽USB3.0 桥片方案往往更省事。AN65974 是 Cypress现英飞凌官方应用笔记配套压缩包里的 CYUSB3014 也就是大家常说的 FX3内部集成了 USB3.0 PHY、ARM9 处理器和 GPIF II 可编程并行接口。FPGA 端不碰 USB 协议只要按 Slave FIFO 时序把数据写进 32 位总线PC 端就能通过驱动看到普通 Bulk 端点并读走数据。这正好覆盖图像传感器采集、ADC 数据流、FPGA TDC 直方图这类连续上传需求也适合 FPGA 入门阶段想绕开 USB 协议栈但又不愿意牺牲吞吐量的开发场景。2. 看懂 CYUSB3014 的 GPIF II 写时序再写 FPGA 状态机2.1 Slave FIFO 模式下 FPGA 要控制的信号AN65974 例程里的“Slave FIFO”很容易叫错名字FPGA 才是总线主控FX3 只是把 GPIF II 的 DMA socket 暴露成一组并行 FIFO 接口。同步模式下 PCLK 由 FPGA 产生最大可以跑到 100MHzFPGA 拉低 SLWR#把数据放上 FD 总线数据在 PCLK 上升沿被 FX3 采进去。这个方向和“从 FPGA 写到 PC”一致也是最常用的数据上传路径。先记住下面这张信号表再去看例程就不会乱信号方向作用PCLKFPGA → FX3同步写时钟FPGA 输出最大 100MHzFD[31:0]FPGA → FX332 位数据总线例程也可配成 16 位SLWR#FPGA → FX3写使能低有效与 PCLK 上升沿对齐FLAGBFX3 → FPGA写方向状态标志官方例程默认低有效表示“未满”A[1:0]FPGA → FX3线程选择官方例程默认值固定写方向通常为 00PKTEND#FPGA → FX3短包提交低有效脉冲传输尾包不满时使用SLRD#FPGA → FX3读使能PC 往 FPGA 下发数据时使用FLAGA/C/DFX3 → FPGA其他状态标志按例程配置使用FLAGB 是新手最常栽的地方。官方例程把 FLAGB 配成“低有效表示可写”也就是flag_b 1b0时 FPGA 才能拉 SLWR#。不少人想当然地认为低有效代表满了结果状态机从启动到超时一次 SLWR# 都没拉出来。拿到别人的修改版工程时先用逻辑分析仪抓 FLAGB 和 SLWR# 的相位关系再决定套用哪套极性。2.2 同步写状态机的 Verilog 模板下面的模块演示连续突发写把本地 FIFO 数据搬到 FX3 的 32 位 GPIF 总线上。BURST_LEN 默认 128正好是 512 字节对应 AN65974 例程里一个常见 DMA 缓冲长度。// fx3_slavefifo_wr.v // 同步 Slave FIFO 写突发32-bit 数据总线 module fx3_slavefifo_wr #( parameter BURST_LEN 128, // 128 * 4B 512B parameter DATA_WIDTH 32 )( input wire clk, input wire rst_n, input wire [DATA_WIDTH-1:0] din, input wire fifo_valid, output reg fifo_ready, output reg [DATA_WIDTH-1:0] fdata, output reg slwr_n, output reg pktend_n, input wire flag_b, // 0: FX3 可写 input wire start ); localparam S_IDLE 3d0; localparam S_WRITE 3d1; localparam S_SHORT 3d2; reg [2:0] state; reg [15:0] cnt; always (posedge clk or negedge rst_n) begin if (!rst_n) begin state S_IDLE; slwr_n 1b1; pktend_n 1b1; fdata {DATA_WIDTH{1b0}}; fifo_ready 1b0; cnt 16d0; end else begin slwr_n 1b1; pktend_n 1b1; fifo_ready 1b0; case (state) S_IDLE: begin if (start !flag_b) begin cnt 16d0; state S_WRITE; end end S_WRITE: begin fifo_ready 1b1; if (fifo_valid !flag_b) begin slwr_n 1b0; fdata din; if (cnt BURST_LEN - 1) begin cnt 16d0; state S_IDLE; // 正好整包不需要 PKTEND end else begin cnt cnt 1b1; end end end S_SHORT: begin // 短包当前 DMA buffer 不满必须通知 FX3 提交 pktend_n 1b0; state S_IDLE; end default: state S_IDLE; endcase end end endmodule逻辑说明状态机在start拉高且 FLAGB 为低时进入 S_WRITE每个 PCLK 上升沿检测fifo_valid满足条件就打一拍 SLWR# 并输出din。计数到 BURST_LEN-1 时整段结束因为数据量正好填满一个 USB 传输单元FX3 会自动提交不需要 PKTEND。如果fifo_valid提前拉低说明源数据不足一整包这时应进入 S_SHORT 分支拉一个 PCLK 的 PKTEND# 让 FX3 把短包搬到 USB 端。参数说明BURST_LEN 改成 256 时一次突发 1024 字节贴合 USB3.0 Bulk 最大包长如果 GPIF 总线换成 16 位同样 512 字节需要把 BURST_LEN 改成 256。注意 PKTEND# 拉低期间 SLWR# 必须保持高两个信号同时有效时 FX3 行为不确定。2.3 突发长度、FLAG 水印与短包的关系AN65974 例程默认把 FX3 的端点缓冲和 GPIF socket 分成若干块常见一块 512 字节或 1024 字节。FPGA 侧一次突发越长USB 侧越不容易产生碎片但突发太长会让 PC 端等待时间变长图像采集里可能叠加额外延迟。FLAG 水印在固件里通过 socket 配置决定。水印设成 0 时 FLAGB 基本等效于满/空标志设成 16 字节时 FLAGB 会提前拉高给 FPGA 留出停止写的时间代价是 GPIF 总线上会多出一些气泡。实时数据流建议保留一点水印余量但不要超过 64 字节否则总线利用率下降明显。3. 官方例程的固件与 FPGA 工程怎么跑起来3.1 解压 AN65974 后先看固件而不是 PDF拿到 AN65974.rar解压后不要急着通读 PDF。例程包通常按 firmware、fpga_reference、host、doc 四类文件组织其中 firmware 里的 slfifo 工程最值得先看。把对应工程导入 FX3 SDKEclipse 环境编译生成 .img 镜像再用 CyControlCenter 的 Program → FX3 → RAM 下载到板子上。这一步如果通过PC 端 Streamer 软件可以直接从 0x81 端点读到数据说明 FX3 本身工作正常。FPGA 参考工程官方给过不同厂商版本Xilinx 用 Vivado/ISEAltera 用 Quartus核心逻辑都一样不外乎一个写状态机和一个读状态机。自己移植也不难重点是把 PCLK 频率和 GPIF 位宽和固件保持一致。AN65974 的一大优点就是固件、FPGA、上位机三部分都能单独验证任何一个环节出问题都能快速定位。3.2 上板前必须确认的三个参数先确认 GPIF 数据位宽。官方例程里用宏控制 16 位还是 32 位FPGA 工程的总线宽度必须和固件一致否则所有数据都会错位。第二确认 PCLK 极性官方例子按上升沿采样设计Altera 和 Xilinx 工程里都要保证slwr_n有效后数据已经稳定不能依赖时钟下降沿出数。第三确认端点号例程常用 0x01 作为 PC 到 FPGA 的 consumer 端点0x81 作为 FPGA 到 PC 的 producer 端点Streamer 里选错端点就会一直显示“无数据”。配置项例程默认值上板前检查GPIF 位宽32 位FPGA 侧 data 总线与固件宏一致PCLK 频率100MHzFPGA 锁相环输出无 jitter 超限端点号0x01 / 0x81Streamer 和固件配置一致地址线A[1:0] 固定确认没有浮空引脚导致线程跳变设备管理里确认 FX3 是否枚举成功Windows 下可以用 PowerShell 查Get-PnpDevice -PresentOnly | Where-Object { $_.FriendlyName -match FX3|Cypress } | Format-Table Status, FriendlyName, InstanceIdLinux 下用 lsusb 更直接lsusb -d 04b4:00f1解释04b4 是 Cypress 的厂商 ID。显示 00f1 通常表示 FX3 还停在 bootloader固件没有运行固件跑起来后会变成例程自定义的 PID。PowerShell 命令用来确认设备是否被 Windows 识别避免出现“FPGA 在跑但 PC 根本没看到设备”的低级问题。3.3 枚举正常但读不到数据时的排查表现象直接原因下一步操作VID/PID 固定 04b4:00f1固件没加载到 RAM用 CyControlCenter 重新下载 .imgStreamer 找不到 0x81 端点GPIF 状态机没启动查固件串口日志是否打印初始化成功上电固化后无设备I2C EEPROM 启动配置错误检查 PMODE 引脚和 EEPROM 地址有数据但速率只有几 MB/s短包过多或 URB 太小调大上位机 Xfer Size检查 FPGA 突发长度PC 端能看到设备但读不到数据90% 的根因在固件初始化顺序上常见是 GPIF 状态机加载失败后 DMA 通道没有起来而 USB 枚举本身不依赖这段逻辑。串口日志这时候比仿真值钱例程固件里默认带 UART 打印先看到 print 再谈波形。4. 把 AN65974 接到自己的数据源ADC、图像和 TDC 直方图4.1 12-bit ADC 数据打包到 32 位总线很多射频板和软件无线电项目里的 ADC 是 12 位或者 14 位比如 AD9361 相关板卡上就能看到 FX3 的身影但 GPIF 总线最小常用位宽是 16 位例程默认还是 32 位。直接丢数据会造成总线大量空闲位正确做法是先打包再写入。两个 12 位样本拼成一个 32 位字每字里低 4 位和高 4 位补零// 连续两个 12-bit ADC 样本打包为一个 32-bit GPIF word reg [31:0] gpipe_data; reg gpipe_valid; reg adc_slot; always (posedge clk) begin if (adc_valid !adc_slot) begin gpipe_data[15:0] {4b0, adc_din}; adc_slot 1b1; gpipe_valid 1b0; end else if (adc_valid adc_slot) begin gpipe_data[31:16] {4b0, adc_din}; gpipe_valid 1b1; adc_slot 1b0; end else begin gpipe_valid 1b0; end end逻辑说明adc_slot相当于一个乒乓标志奇数样本放低 16 位偶数样本放高 16 位凑齐两个才拉高gpipe_valid。这样送到 FX3 的数据字不会出现“半个样本”的悬空周期短包数量也会减少带宽更稳定。补零位置取决于你后续做 FPGA 图像处理还是数字信号处理如果想保持一致的系统增益可以把样本左对齐也就是放到高 12 位而不是低 12 位。4.2 上传带宽怎么算先算 GPIF 再打 USB 折扣我一般先按 GPIF 侧理论峰值算一次再按 USB3.0 实际可用带宽算第二次取较小者作为设计预算。总线配置GPIF 理论峰值USB3.0 实际可用典型场景16-bit 100MHz200 MB/s180 - 190 MB/s双通道 12-bit ADC32-bit 100MHz400 MB/s350 - 380 MB/s图像传感器、多通道 TDC32-bit 50MHz200 MB/s180 MB/s数据量不大但需要低延迟这里的 USB3.0 实际值是大块连续传输下的经验区间受线材、主机控制器、驱动 URB 影响会浮动。标注一下GPIF 是并行总线USB3.0 是串行协议二者都有开销所以 32-bit 100MHz 时真正的瓶颈是 USB 侧而不是 FPGA 侧。算图像传感器时一个简单参考1080p30 RGB888 约 187MB/sUSB3.0 余量充足1080p60 约 373MB/s必须保证整包传输任何短包策略都会把可用带宽压到 350MB/s 以下。4.3 FPGA TDC 直方图的回传结构TDC 直方图场景有点特殊FPGA 内部做时间戳测量PC 不需要每一笔时间戳只需要周期拉取直方图结果。数据量不大但要求一致性强不能读到一半直方图被新数据覆盖。常见做法是在 FPGA 里做双缓冲统计区一段累计另一段可读PC 读之前先发一个读请求FPGA 把当前帧锁定。AN65974 的 Slave FIFO 正好适合这种“PC 定时拉取、FPGA 被动供给”的模型因为 FPGA 永远掌握数据节奏。回传帧建议这样组织前 64 字节是表头包含 frame_id、bin_count、溢出标志后面是 N 个 32 位 bin 计数值。PC 先读表头根据 bin_count 决定继续读多少字节。FPGA 侧在表头发完后如果发现 bin 总数不是 128 的整数倍就补一个 PKTEND# 收尾如果正好是整包则正常自动提交。这样 PC 端即使收到跳号的 frame_id也能立刻判断这一帧读取失败而不会拿错数据做直方图分析。5. 让最后一包不丢AUTO DMA、PKTEND 与 Streamer 验证5.1 GPIF 位宽与 16 字节对齐FX3 的 DMA 引擎搬运粒度是 16 字节也就是说无论总线多宽FPGA 传给 FX3 的总数据量最好按 16 字节对齐分割。AN65974 例程里的固件默认使用 AUTO DMAARM9 不参与逐包搬运数据从 GPIF 到 USB 的移动完全由硬件完成如果 FPGA 端发来一个不对齐长度最后一小段数据会滞留在 DMA buffer 里直到超时才被提交。GPIF 位宽一个 16 字节单元对应拍数建议突发长度16 位8 拍8 的整数倍32 位4 拍4 的整数倍也就是说 32 位总线下一次突发写成 127 个 word 是可以的但最好补到 128 个 word16 位总线下一次突发 31 个 word 虽然只差一拍却要额外触发一次短包提交。这个细节在老代码里经常被忽略结果就是传输率波动和尾包延迟。5.2 PKTEND 触发窗口怎么验证PKTEND 并不是每次传输都要拉。数据量正好填满端点 buffer 时FX3 会自动把包提交到 USB只有数据量填充不满时才需要 FPGA 拉一个低脉冲触发短包提交。检查两个点第一PKTEND# 低电平至少保持一个 PCLK第二PKTEND# 为低时 SLWR# 必须为高。用 ILA 抓这组信号最直观触发条件设成pktend_n 1b0回看前一个周期和后三个周期的 SLWR# 状态。上位机侧验证带上 CyStreamer参数可以这样设参数建议值原因Xfer Size1 MB给驱动足够大的缓冲来掩盖 USB 调度抖动Timeout1000 ms不会把瞬时停顿误判成断流Pipe 选择0x81 (IN)producer 方向FPGA 往 PC 传连续发 1000 次 1MB 传输如果短包数量占比超过 1%回查 FPGA 状态机的突发长度和 FLAGB 水印阈值如果吞吐曲线周期性掉底把 ILA 触发条件改成flag_b 1b1大概率能看到 FPGA 等水印恢复时出现气泡。把 Max URB 调到 32 后仍锯齿再回头检查 GPIF 状态机里的地址线是否被无关信号干扰。本文还有配套的精品资源点击获取
返回列表