做高速数据采集这些年最难受的往往不是采集本身而是数据怎么从板卡上搬出来。要么UART慢得只能传点调试信息要么USB2.0跑满也就三四十兆字节每秒想上USB3.0吧FPGA这边直接做协议栈和物理层又重得让人劝退。直到我接触到基于CH569的这套方案——一颗内置USB3.0 PHY和控制器的RISC-V芯片专门负责把FPGA采集到的高速数据实时上传到电脑整个链路一下子清爽了。今天就把这套系统的设计思路、核心细节和实操过程完整拆一遍适合正在做数据采集、图像传输、高速接口类项目的FPGA开发者参考也适合想快速上USB3.0传输的MCU玩家了解整体架构。1. 这套系统到底在解决什么问题1.1 高速采集的瓶颈往往不在采集而在传输很多朋友刚接触FPGA时以为难点在采样率、位宽、时序这些采集端问题。真正做过项目以后你会发现ADC采样、传感器读取这类活儿FPGA天生就能干而且干得很漂亮。真正的瓶颈经常出现在把数据送出去这一步。举个例子一个100M采样率、12位的ADC连续采集时每秒产生的数据量是100M × 2字节 200MB/s。这个速率跑UART完全是天方夜谭GPIF、并行口直连GPIO也没有任何上位机软件能稳定接住。USB2.0理论峰值480Mbps实际Bulk传输能稳定跑到35MB/s已经算不错了连零头都不够。以太网倒是带宽大但MAC、PHY、协议栈、上位机socket编程一套下来工作量也不小而且对于裸数据流传输TCP的粘包、缓冲、延迟问题够你调一阵子。USB3.0的SuperSpeed模式理论5Gbps实际Bulk传输在PC端可以稳定跑出300MB/s以上的有效带宽取决于主板、线缆、驱动、端点配置基本覆盖绝大多数中高速采集场景。但问题是USB3.0不是你想上就能上的。它既有复杂的协议栈又有严格的物理层要求差分阻抗、信号完整性、链路训练、电源管理……FPGA直接实现这些工作量巨大用现成的USB3.0 PHY芯片又贵又难买。1.2 为什么不选纯FPGA方案或纯MCU方案纯FPGA方案比如用FPGA USB3.0 PHY芯片 自己写USB控制器逻辑这条路不是不能走但设计周期非常长。USB3.0的协议层包含链路训练、电源管理、均衡、重放机制等一大堆状态机验证和调试的坑又多又深。即便用了一些大厂的USB3.0 IP核License费用、集成难度、调试周期也足够劝退很多人。除非你是做芯片验证这类特殊场景否则不建议这么自虐。纯MCU方案呢很多高端MCU内部有USB HS甚至SS控制器比如带USB3.0的ARM或带专用高速接口的芯片但MCU本身去采集高速并行数据流IO翻转速度和DMA吞吐能力都有限。你让MCU直接去接一个100Msps的ADC光数据总线就忙不过来更别提前端预处理了。于是折中方案就出现了FPGA负责采集、预处理和缓存一颗带USB3.0的高速MCU负责把数据搬到PC。FPGA发挥并行采集和硬件加速的优势MCU发挥内置USB3.0 PHY和控制器、开箱即用的优势两边各干各最擅长的事。而且CH569本身就是RISC-V内核开发流程熟悉以后固件改起来比传统ARM还顺手整套方案从硬件到软件都有很高的可复现性。2. 系统架构与数据链路拆解2.1 总体数据流与模块划分整套系统的数据流可以概括成一条单向流水线信号源 → FPGA采集模块 → FPGA预处理/转换 → 异步FIFO缓存 → CH569并行接口读取 → CH569内部DMA搬运 → USB3.0端点 → PC上位机。模块划分要非常清晰否则后面排查问题很容易各模块互相甩锅。建议按功能切成四个主要部分采集前端ADC或各类传感器数据接入完成时序采样、位宽对齐。不同传感器接口方式差异很大比如模数转换器常用SPI或并行接口MIPI摄像头则要走LVDS差分。数据预处理滤波、定点转换、格式封装等。这部分是可选的但很多场景离不开。比如光采集原始数据不处理上位机大量计算很费劲在FPGA里先做一遍定点FIR、LMS均衡或者去马赛克能大幅降低上位机压力。缓存与跨时钟域采集时钟和CH569读取时钟通常不是一个域必须用异步FIFO隔离。同时FIFO也能吸收USB传输中PC端偶尔的调度延迟尖峰避免数据丢失。传输桥接CH569运行固件把并行FIFO接口收到的数据通过DMA搬进USB端点缓存再由USB3.0控制器发送到主机。每一层之间用握手信号做缓冲比如FIFO的空满标志、CH569的请求读取信号等。这样上层速度波动不会直接传导到下层采集端系统才能稳定长时间运行。2.2 CH569在链路中扮演的角色CH569在整套系统里更像一个USB3.0桥接协处理器而不是传统意义上的主控MCU。它不需要理解业务数据只负责把外部并行接口的数据往USB端点上搬所以固件逻辑可以做得非常轻量。这颗芯片有几个特性在这个场景下特别关键内置USB3.0 SuperSpeed物理层和控制器的完整解决方案硬件设计时不需要额外接昂贵的PHY芯片这直接解决了我前面说的USB3.0物理层难搞的大麻烦。RISC-V内核主频可以跑到120MHz级别配合DMA做数据搬运绰绰有余。提供并行FIFO接口可以直接对接FPGA的通用IO类似单片机读写外部FIFO的方式时序逻辑清晰、容易握手。支持自定义端点配置Bulk传输可以设定多个端点、多种缓存大小配合DMA能有效提升实际吞吐。所以你看CH569并不需要跑复杂的USB协议栈逻辑固件里主要做三件事初始化USB控制器、配置端点、在中断里响应并启动DMA传输。具体到工程实现下面章节细说。2.3 FPGA与CH569的接口协议与时序FPGA和CH569之间的连接建议采用并行FIFO从模式即FPGA侧把CH569当做一个可以写的FIFO设备。常用的信号组大致如下数据总线 8位或16位并行数据线我实际偏好在带宽足够的前提下用16位这样等效数据率可以翻倍。写使能WR/WE与读使能RD/RE指示总线上的数据是否有效。FPGA作为生产者向CH569的FIFO写入时需拉低写使能。FIFO满标志FULL/AFULLCH569内部FIFO满时通知FPGA停止写入这是反压机制的关键。FIFO空标志EMPTY/AEMPTYCH569从FIFO读取数据时如果FIFO空读操作不产生有效数据。时钟写时钟可以由FPGA提供也可以由CH569提供取决于数据手册的具体接口定义。这个细节务必以手册为准否则时序对不上很容易出现写进去的数据错位。时序上最核心的是保证建立时间和保持时间满足要求尤其是FPGA输出数据给CH569时数据必须在写使能有效前保持稳定。如果接口电平不匹配中间还要加电平转换或做IO标准配置。FPGA侧建议直接在综合工具里对IO约束根据CH569手册的时序参数设置input delay/output delay而不是全靠运气和肉眼观察波形。3. CH569的RISC-V内核与USB3.0控制器先讲透3.1 一颗带USB3.0 PHY的RISC-V芯片能省多少事做USB3.0设备端传统方案绕不开USB3.0 PHY芯片和配套的控制器逻辑。PHY负责5Gbps高速串行信号的物理层收发控制器负责USB协议层。这两个东西拆开卖都贵集成到一起的更不多见。CH569把PHY、控制器和MCU核打包在一颗芯片里光物料成本和PCB面积就能省一截开发调试的复杂度也降低了一个量级。它内部的USB3.0物理层支持SuperSpeed模式对外提供SSTX_P/SSTX_N和SSRX_P/SSRX_N两组高速差分对同时保留了USB2.0的DP/DM引脚做兼容。硬件设计时高速差分对要求100欧姆差分阻抗控制走线尽量短远离时钟和电源干扰。参考时钟、电源退耦这些也要按手册要求做严格不然容易出现设备偶尔识别不到的问题。RISC-V内核本身开发体验和常见的MCU差别不大。用官方推荐的MounRiver Studio或者RISC-V GCC工具链写C代码、编译下载流程很直接。如果你以前玩过STM32或者其它MCU切过来基本没有学习成本。3.2 端点配置与Bulk传输的关键参数USB3.0设备端要往主机传数据常用的是Bulk批量传输。Bulk传输没有等时传输的带宽保证但有重传机制数据可靠特别适合数据采集。关键是端点缓存和DMA怎么配合。USB协议里Bulk端点有最大包大小USB3.0下通常可以设到1024字节。单包越大、端点数越多、缓存越深吞吐越有利。实际工程里CH569允许配置多个Bulk端点比如一个IN端点用来传采集数据一个OUT端点用来接收主机控制命令。每个端点可以分配一定大小的FIFO缓冲区数据从并行接口进来后由DMA直接写入端点FIFO而无需CPU逐字节搬运。要跑出高带宽建议这样配置使用双缓存或四缓存机制一组在DMA传输时另一组可以被USB控制器读出这样能有效避免缓存切换间隙造成的带宽损失。中断不要做成每字节触发而是等DMA搬完一块或者端点数据包发完再触发减少CPU介入开销。单次DMA传输长度尽量大减少启动DMA和响应中断的次数。我见过很多人把USB3.0速度跑不满一查都是DMA长度太小、中断太频繁带宽全耗在切换上了。3.3 USB3.0硬件设计要点与Type-C方向如果直接用USB3.0标准A型连接器焊接和设备端相对简单SSTX/SSRX差分对一一对应就行。如果板子要做USB Type-C接口那就多出CC引脚的配置问题因为Type-C支持正反插需要根据CC引脚的电压判断方向再用对应的USB3.0信号路由。CH569本身不带Type-C的方向逻辑你需要在小板上额外加一个CC逻辑控制或者用支持DRP的PD协议芯片来协商角色和方向。从数据传输角度USB3.0的信号完整性要求比USB2.0高不少。差分对要做100欧姆差分阻抗控制尽量走内层、包地更好连接器附近加ESD保护期间注意寄生电容别太大以免劣化信号眼图。电源方面USB3.0的SuperSpeed收发器对电源噪声敏感VDD要加足够的去耦电容最好独立LDO供电。硬件设计这些细节前期不到位后面调试时会用各种诡异现象回报你。4. FPGA侧采集、缓存与流量控制4.1 采集端设计从ADC到定点预处理FPGA采集端的具体电路跟你的信号源强相关但从工程抽象角度来看可以统一分成几个环节接口时序控制、数据对齐、可选的预处理。以并行ADC为例比如AD7606这类常见芯片FPGA的工作就是按照转换时序发起采样在数据准备好后读回16位结果。这个过程涉及状态机设计、busy信号判断、时序余量检查。如果数据里偶发读到错误值先用示波器看转换完成信号和数据总线时序是否满足芯片手册要求很多时候问题出在代码里没留时序余量而不是芯片坏了。预处理环节如果你想做FIR滤波、LMS均衡这类算法建议采用定点数运算避免浮点IP核占用过多逻辑资源。定点数要特别注意整数位宽和小数位宽的分配先估算输入动态范围再根据滤波增益确定小数位否则很容易溢出或者精度不够。对比直接用浮点IP定点方案在FPGA上可以做到每个时钟周期处理一个采样点吞吐大、资源省是在高速数据流场景下的常规选择。4.2 异步FIFO与深度估算跨时钟域处理是FPGA高速设计中躲不开的问题。采集端时钟可能是ADC的采样时钟而CH569读取数据使用的是它那边的接口时钟两个时钟频率和相位都没有确定性关系此时绝不能直接用一个时钟域的寄存器去读另一个时钟域的信号会触发亚稳态。标准做法是插入异步FIFO。写时钟域写数据、写指针用格雷码同步到读时钟域读时钟域读数据、读指针同步回写时钟域。用FPGA厂家提供的FIFO IP核是最省事的选择Quartus和Vivado里都有异步FIFO的现成IP只需要配置位宽、深度、读写时钟和满空标志。FIFO深度该怎么定最朴素的原则是FIFO要吸收的最大瞬时数据差等于写速率乘上最长阻塞时间。USB3.0传输中PC端调度、驱动回调、DMA搬运都可能造成短时间的读端停顿最长阻塞时间可能在几十微秒到几百微秒级别。以200MB/s写入速率、最长停顿200微秒计算FIFO深度至少要容纳40KB。再留出安全余量设计时按64KB来做比较从容。如果FPGA内部BRAM不够可以外挂SRAM或者降低批量包大小、调整DMA调度策略来缓解。4.3 反压与握手状态机光有深FIFO还不够写数据的状态机必须能感知下游压力。用CH569的FIFO满标志或可编程阈值标志作为反压信号当它拉高时FPGA立即暂停写入等标志释放后再继续。这个反压逻辑看似简单实现时最容易犯的错误是状态机只判断满信号而忽略了FIFO快满的标志导致临界情况下主控还没来得及响应数据就溢出了。稳妥做法是使用可编程almost full标志把阈值设在FIFO容量的四分之三左右留出几个周期的响应余量。同时状态机设计要注意从反压中恢复时的时序。不要在标志释放后立刻写第一笔数据先等时钟沿对齐确保CH569那边已经准备好接收。FPGA复位信号也要小心异步复位同步释放是基本要求不然复位释放瞬间逻辑状态不确定容易产生亚稳态问题这在高速接口设计中是高频踩坑点。5. 实操把整条链路完整跑起来5.1 硬件连接与电平匹配我这里用的是常见的FPGA开发板和一块CH569核心板组合。先把两组芯片之间的接口引脚分好数据线、写使能、读使能、满标志、空标志逐条对照CH569手册确认信号方向和电平标准。电平匹配这里要特别提醒如果FPGA的IO电压是3.3V而CH569的接口电压要求1.8V或2.5V直接连过去轻则功能异常重则烧坏IO。确定电平标准后必要时加电平转换芯片或者用FPGA的bank电压配置来匹配。很多高速采集项目最后调试不通查了好久发现是电平标准不匹配这种基础问题还是要一开始就确认好。连接完成后用示波器或者逻辑分析仪抓一下FPGA发出的写时序看数据和写使能的相对关系是否符合CH569手册的建立时间要求。这一步看似浪费几分钟但能省掉后面盲调的痛苦。5.2 CH569固件USB3.0BulkDMA最小实现我以最小能跑通的固件为例代码逻辑大致如下具体寄存器配置务必以官方头文件和例程为准// 伪代码示意实际工程请以CH569官方库为准 void USB3_Init(void) { // 初始化USB3.0控制器选择SuperSpeed模式 USB3_DeviceInit(); // 配置Bulk IN端点最大包大小1024字节 USB3_EndpointConfig(EP_IN_BULK, BULK_PACKET_SIZE, BULK_DOUBLE_BUFFER); // 开启端点IN中断 USB3_EnableEndpointInterrupt(EP_IN_BULK); } void ExternalFifo_To_USB(void) { uint8_t* buf GetDMABuffer(); // 从并行FIFO接口读取一块数据到内存缓冲区 ReadExternalFIFO(buf, TRANSFER_LEN); // 启动DMA把数据搬到USB端点FIFO USB3_DMA_Start(EP_IN_BULK, buf, TRANSFER_LEN); } void USB3_EP_IN_Interrupt(void) { // 上一个DMA传输完成立刻继续读下一块数据 ExternalFifo_To_USB(); }整个过程理解起来就是不断从并行接口读数据进缓冲区再由DMA送进USB端点中断里接力下一块。注意不要在中断里做耗时长的操作中断标志、状态处理尽量精简否则会拖慢传输节奏。我第一次跑的时候忘了配端点缓冲为双缓冲模式带宽只能到一半左右后来改成双缓冲后吞吐立刻上来了。这部分优化空间很大建议根据实际传输速率逐步调整DMA传输长度和缓冲策略。5.3 FPGA逻辑FIFO例化与写时序约束FPGA侧直接在综合工具里例化异步FIFO IP配置好位宽、深度然后把写端口接到采集模块读端口接到连接CH569的一组IO上。以状态机为例写CH569接口的简化思路// 伪代码示意需要根据实际接口时序修改 always (posedge clk or negedge rst_n) begin if (!rst_n) begin wr_en 1b0; state IDLE; end else begin case (state) IDLE: begin if (!ch569_fifo_full !fifo_empty) begin data_out fifo_dout; wr_en 1b1; // 数据先放总线再拉低写使能 state WR_DATA; end end WR_DATA: begin wr_en 1b0; // 一个时钟周期的写使能脉冲 fifo_rd_en 1b1; // 同时读走FIFO下一笔数据 state IDLE; end default: state IDLE; endcase end end这里最关键的是数据有效要提前于写使能。CH569在写使能判定时数据总线必须已经稳定否则会采到不确定值。我习惯在写使能有效前一个周期就把数据放到总线上保证建立时间足够。IO时序约束也不能偷懒。在工程里给这些接口信号设置input/output delay参考CH569数据手册里的时序参数填写。如果不做约束工具默认的时序分析结果可能和实际物理表现不一致板子跑起来就会偶发数据错位时好时坏。5.4 上位机收数验证与带宽测试固件和FPGA都烧好后把USB3.0线连到电脑。第一次插上时系统枚举设备后需要安装驱动。如果CH569官方提供了驱动或INF文件用官方的最省心如果自己写应用可以用WinUSB或libusb做免驱的Bulk通信Windows下配置好INFLinux下直接libusb就行。验证带宽和数据的常见做法是FPGA侧生成一个递增的计数序列当作测试数据上位机收下来检查数据是否连续递增、错位、丢包。先小数据量跑比如1MB确认数据完整再逐步增大到几十GB观察速率稳定性。实测下来Bulk传输在普通电脑上跑到250MB/s以上是可行的再往上提升就要检查主板USB控制器、线缆质量、DMA配置和上位机接收缓冲的大小了。很多时候上位机开线程收数据、处理数据的代码写得不好反而会成为瓶颈。6. 常见问题与排查手记6.1 USB无法识别或枚举失败这个现象通常不是固件逻辑的问题而是硬件链路或初始化顺序的问题。优先检查这几个点USB3.0差分对供电和参考时钟是否正常SSTX/SSRX走线是否满足100欧姆差分阻抗。有的人用杜邦线飞线连接高速信号根本传不过去这不是软件能救的。CH569的复位时序是否正确上电后等待电源稳定再释放复位。如果USB2.0能识别但USB3.0识别不了多半是SuperSpeed差分对信号质量问题或者线缆被识别成USB2.0线。固件里USB控制器初始化顺序有没有问题比如先配置端点再使能设备还是先使能再配置以官方例程为准。排查时先用逻辑分析仪看设备端的USB3.0链路训练是否完成再看枚举阶段主机发出的控制请求是否响应能快速缩小问题范围。6.2 数据丢包与字节错位链路已经通了的稳定性问题先别怀疑USB协议绝大多数情况下是FPGA与CH569之间的并行接口时序有问题。字节错位一般是因为数据总线建立时间不够或者写使能和数据变化同时发生导致CH569采样到一半稳定一半不稳定的数据。用示波器同时抓数据线和写使能看数据和写使能下降沿之间的相对关系数据必须先稳定写使能再下降。丢包则可能是FIFO溢出。检查CH569的满标志是否正常反馈到FPGA以及FPGA侧是只是判断满了暂停还是快满了才响应。如果用的almost full阈值设置太高响应时间不够压力一大就会丢。调低阈值留出足够响应余量问题能解决大半。6.3 实测带宽远低于理论值如果只跑出几十MB/s先别怀疑芯片能力按这套思路排查端点是不是单缓冲改成双缓冲或四缓冲带宽往往直接翻倍。DMA传输长度是不是太小每包传输从64字节改成1024字节甚至更大中断频率降下来吞吐会明显改善。上位机接收缓冲够不够如果上位机收得慢USB控制器会因主机侧反压降低设备传输速率。检查应用读取数据的线程优先级和缓冲区分配。PC端是否接在USB3.0端口很多机箱前置面板的USB口实际是USB2.0内部线这个坑我踩过好几次。把这些逐项排除一般带宽都能回到合理的范围。6.4 综合时序不满足与亚稳态FPGA工程在布局布线后报告时序不满足先看是哪些路径。如果是IO路径通常是IO约束没写对补上input delay/output delay再跑。如果是FIFO内部或跨时钟域路径检查异步FIFO的时钟约束是否正确。亚稳态的问题比较隐蔽表象是系统偶尔跑飞、数据偶尔错误。异步FIFO本身解决的是跨时钟域的数据传递安全性但如果你在其它地方直接跨时钟域采样了信号就要用两级同步器或专用握手来保证安全。FPGA设计里务必坚持每个跨时钟域信号都有明确处理的原则否则出问题真就是玄学。布局和布线的区别这时候也有体会了布局决定逻辑单元在芯片上的排布位置布线决定物理走线两者相互影响直接决定时序是否收敛。遇到综合后的时序问题先看约束是否合理再看逻辑级数是否太深必要时在关键路径上插流水线寄存器。最后再分享一点个人体会。这套系统的核心价值是把USB3.0这种硬骨头留给专用芯片而让FPGA专注于自己擅长的采集和预处理分工明确、可调试性强。实际做下来最难的不是某个模块单独实现而是两个芯片之间的握手和时序细节。如果你也准备做类似的高速采集系统建议先打通最小链路——FPGA发计数序列、CH569收数、上位机收数校验把整条通路跑通摸稳之后再接真实信号源逐步升级。验证好主链路再叠加预处理、多通道扩展、波形显示等能力就顺理成章了。
