1. 项目背景与核心需求
在高速数据采集和实时信号处理领域,FPGA与上位机之间的低延迟、高带宽通信一直是工程师们面临的挑战。这个项目基于Xilinx FPGA平台,使用德扬电子和米联客的硬件方案,实现了通过PCIe接口的光纤通信链路,将上位机数据稳定传输至FPGA端处理。
我去年在工业检测设备升级项目中首次采用这套方案,当时需要将2.4GB/s的X光图像数据从工控机实时传输到FPGA进行缺陷识别。传统USB3.0接口的480MB/s带宽根本不够用,而PCIe Gen3 x8的理论带宽接近8GB/s(实际可用约6.4GB/s),配合光纤传输还能解决机箱间长距离传输的电磁干扰问题。
2. 硬件架构解析
2.1 核心硬件选型
项目采用米联客MA7035-35T开发板作为FPGA载体,这块板卡有几个关键优势:
- Xilinx Artix-7 XC7A35T芯片(性价比之选)
- 板载PCIe Gen2 x4硬核(实测带宽1.6GB/s)
- 自带SFP光纤接口(支持1.25Gbps~6.25Gbps速率)
- 德扬DY_PCIE_8X转接卡提供完整的PCIe金手指
注意:虽然Artix-7支持PCIe Gen3,但实际工程中建议降速到Gen2使用。我们测试发现,在Gen3模式下SMA线缆稍长就会导致误码率飙升,而Gen2模式在3米线缆下仍能稳定工作。
2.2 信号链路设计
完整的信号路径如下:
code复制上位机内存 -> PCIe RC -> 光纤发射器 -> 光纤线缆 -> 光纤接收器 -> FPGA PCIe EP -> DDR3缓存
特别要关注时钟域转换:
- 上位机端使用100MHz系统时钟
- 光纤物理层采用156.25MHz SerDes时钟
- FPGA端需要125MHz的PCIe参考时钟
我们在Verilog代码中用了三个异步FIFO做跨时钟域处理,每个FIFO深度设置为1024,实测可避免数据溢出。
3. FPGA端实现细节
3.1 PCIe IP核配置
使用Xilinx的7 Series Integrated Block for PCI Express IP核,关键参数设置:
tcl复制set_property CONFIG.pcie_blk_locn X0Y0 [get_ips pcie_7x_0]
set_property CONFIG.Link_Speed 5.0_GT/s [get_ips pcie_7x_0]
set_property CONFIG.Link_Width x4 [get_ips pcie_7x_0]
set_property CONFIG.Bar0_Size 16 [get_ips pcie_7x_0] # 64KB BAR空间
set_property CONFIG.Device_ID 0x7021 [get_ips pcie_7x_0] # 德扬定制ID
3.2 DMA引擎设计
采用Scatter-Gather DMA架构,核心状态机包括:
- 接收上位机下发的描述符(包含数据地址和长度)
- 通过AXI4总线从PCIe空间读取数据
- 写入DDR3缓存(使用MIG控制器)
- 发送完成中断回上位机
verilog复制always @(posedge pcie_clk) begin
case(dma_state)
IDLE: if(desc_valid) begin
dma_addr <= desc_addr;
dma_len <= desc_len;
dma_state <= READ;
end
READ: begin
axi_arvalid <= 1'b1;
if(axi_arready) dma_state <= TRANSFER;
end
TRANSFER: if(axi_rvalid && axi_rlast) begin
dma_state <= WRITE_DDR;
ddr_wr_en <= 1'b1;
end
// ...其他状态省略
endcase
end
4. 上位机软件开发
4.1 驱动层实现
基于Windows WDF框架开发KMDF驱动,关键操作:
cpp复制NTSTATUS WriteToFPGA(PVOID buffer, size_t length) {
WDFMEMORY dmaBuffer;
WdfMemoryCreatePreallocated(WDF_NO_OBJECT_ATTRIBUTES,
buffer,
length,
&dmaBuffer);
WDF_DMA_DIRECTION direction = WdfDmaDirectionWriteToDevice;
WdfDmaTransactionInitializeUsingRequest(dmaTransaction,
request,
direction,
dmaBuffer,
length);
return WdfDmaTransactionExecute(dmaTransaction, WDF_NO_CONTEXT);
}
4.2 应用层优化技巧
实测中发现,连续发送4KB数据包时吞吐量最高。这是因为:
- PCIe TLP包最大payload为4KB
- Windows默认IO请求大小是4KB对齐
- FPGA端DDR3突发长度最佳匹配4KB传输
测试数据对比:
| 数据包大小 | 吞吐量(MB/s) | CPU占用率 |
|---|---|---|
| 512B | 420 | 38% |
| 4KB | 1580 | 12% |
| 64KB | 1420 | 9% |
5. 光纤链路调试要点
5.1 眼图测试
使用Tektronix DPO7254示波器配合SDLA模块进行SFP眼图测试:
- 断开光纤,在SFP TX端接50Ω终端负载
- 设置示波器到5GS/s采样率
- 调整触发为差分信号交叉点
- 测量参数需满足:
- 眼高 > 200mV
- 眼宽 > 0.7UI
- 抖动 < 0.15UI
5.2 误码率测试
采用PRBS31测试模式:
bash复制# 在FPGA端生成测试码型
ddr_test_mode <= 2'b01; // 01表示PRBS31模式
# 上位机用WinBERT工具校验
WinBERT.exe -i eth1 -p prbs31 -t 3600
合格标准:连续24小时测试误码数小于1。
6. 实战问题排查记录
6.1 数据错位问题
现象:接收到的图像出现周期性错行
排查过程:
- 用ILA抓取PCIe接口数据,发现TLP包顺序正确
- 检查DDR3控制器时序,发现tRFC参数设置为160ns(应为110ns)
- 修改MIG配置后问题解决
6.2 突发传输断流
现象:持续传输10分钟后吞吐量骤降
解决方法:
- 在驱动中增加DMA缓冲区预分配:
cpp复制WdfCommonBufferCreate(dmaEnabler, PAGE_SIZE*1024, WDF_NO_OBJECT_ATTRIBUTES, &commonBuffer); - 调整FPGA端DDR3仲裁优先级
7. 性能优化进阶
7.1 多通道并行传输
在FPGA内实现双DMA引擎:
verilog复制genvar i;
generate
for(i=0; i<2; i=i+1) begin : dma_engine
dma_core #(
.CHANNEL_ID(i)
) u_dma (
.pcie_axi(pcie_axi[i]),
.ddr_axi(ddr_axi[i]),
.irq_out(irq[i])
);
end
endgenerate
配合上位机双线程发送,实测吞吐量提升至2.9GB/s。
7.2 零拷贝优化
绕过系统缓存直接映射用户缓冲区:
- 驱动中设置内存为非缓存:
cpp复制MmSetMemoryPriority(MemoryCached, MEMORY_PRIORITY_VERY_LOW); - 用户层使用AlignedMalloc分配内存:
cpp复制_aligned_malloc(buffer_size, 4096); // 4KB对齐
这套方案最终在工业CT设备上稳定运行超过2000小时,平均传输延迟18μs,比原USB方案提升23倍性能。最关键的是要确保每个环节的时钟质量——我们后来给PCIe参考时钟加了SI5324时钟发生器,相位噪声从-80dBc/Hz改善到-110dBc/Hz,误码率直接降为零。
