2026年FPGA大赛用国产高云GW2A做千兆以太网UDP视频传输,为什么PC端能收到包但画面撕裂,是跨时钟域FIFO深度不够还是UDP协议栈没做流控?

开放6 回答 129 浏览

我们队用高云GW2A做摄像头采集+千兆以太网UDP发送,上板后PC端抓包能看到数据,但上位机显示画面有横向撕裂。仿真里FIFO读写正常,怀疑是图像时钟和以太网发送时钟跨域时FIFO深度算错,也可能是UDP发送没做背压导致丢包。想请教有电赛/大赛经验的学长,这类问题一般从哪几个点排查?

分享:

6 个回答

  • 码电路的张同学

    先说结论:画面撕裂这种「包能收到但图像错位」的现象,八成不是 FIFO 深度算错,而是帧同步/行同步信息在传输链路里丢了或者错位了。你仿真里 FIFO 读写正常,说明功能逻辑没大问题,问题多半出在时序和边界。建议先用 ILA 抓几个关键点:图像时钟域的写使能、写指针、FIFO 满标志,同时抓以太网时钟域的读指针和空标志。重点看满标志是不是频繁拉高——如果采集端写得比发送端快,FIFO 一直溢出,那丢的就是像素,画面会花不会只是撕裂。撕裂更像是一帧里部分行来自旧帧、部分行来自新帧,典型原因是帧起始标志没对齐,或者 UDP 分包时帧头信息没跟数据绑定。你先确认上位机是按什么规则拼帧的,是固定长度还是靠帧头?如果是固定长度,那丢一个包就会整体错位,看起来就像撕裂。所以排查顺序我建议:先抓空满标志判断是采快还是发慢,再查分包边界和帧头对齐。你们上位机是怎么判断一帧结束的?这个信息很关键。

  • Verilog小白在路上

    做电赛那会儿我们也踩过类似的坑,说点实际的排查思路。跨时钟域 FIFO 深度这件事,很多队直接拍一个 512 或者 1024 就完事,其实应该按突发长度和时钟频率比算。比如图像时钟 74.25MHz、以太网侧有效写入带宽可能只有 60MHz 左右(千兆虽然线速高,但你协议栈处理不过来),那 FIFO 长期是入不敷出的,深度再大也只是延迟溢出时间。所以别只盯着深度,先看平均带宽够不够。

    另一个容易被忽略的是 UDP 发送没有背压。很多同学写的 UDP 栈就是「有数据就发」,不管 MAC 层忙不忙,结果 FIFO 读出的数据被覆盖或者丢掉。建议加乒乓缓冲:一帧图像分成两块,采集写 A 块的时候发送读 B 块,块满了再切换,这样即使发送慢也不会撕裂到同一帧内部。

    风险点在于,乒乓缓冲会引入一帧延迟,对实时性有要求的场景要权衡。替代做法是用带 FIFO 的 MAC IP 或者自己加 credit 机制,发送端每发完一包给采集端一个反馈。

    定位丢包在哪端,最直接就是 ILA 同时挂图像域和以太网域的信号,看满标志拉高的时候是不是刚好对应画面撕裂的位置。如果满标志从没高过,那问题就在协议栈的分包重组,不在 FIFO。你们现在用的是自己写的 UDP 栈还是 IP 核?这决定了排查方向完全不同。

  • 前端初号机

    这个问题我得往深里说一层,因为「撕裂」和「丢包」其实是两个不同层面的病,很多人把它们混在一起查,最后越查越乱。

    先建立因果链:摄像头出的是带行场同步的像素流,以太网出的是无同步语义的字节流。中间必然要做的一件事,是把「这是一帧的第几行第几个像素」这个信息,要么编码进数据(加帧头行号),要么靠收发两端约定固定长度来隐式对齐。撕裂的本质,是接收端重组时用的对齐依据和发送端的实际边界对不上。

    如果是 FIFO 深度不够导致溢出,丢的是连续一段像素,表现通常是画面某几行花掉或者整块色块,而不是「横向撕裂」这种错位感。所以你的现象更指向对齐问题:可能是 UDP 分包时最后一包没补齐就发了,接收端按固定长度切导致后续错位;也可能是帧起始标志在跨时钟域传递时被采样丢了,接收端把上一帧的尾巴当成了新帧的头。

    排查上,我建议先把「丢包」和「错位」分开验证。第一步,用 ILA 抓发送端的包计数和帧计数,看每帧发出的包数是否恒定。如果包数恒定但画面撕裂,那就是对齐或同步标志的问题,跟流控无关。第二步,如果包数不恒定,再去看 FIFO 满标志,确认是采集快还是发送慢。第三步,在发送端人为插入帧头和行号,接收端按帧头重组,这样即使丢包也只是局部花屏,不会整体撕裂。

    关于流控,千兆线速下 UDP 本身不保证可靠,但 FPGA 内部发送侧一定要做背压:MAC 的 ready 信号没拉高就不能读 FIFO。很多开源 UDP 栈为了简单直接忽略这个信号,短时间看不出来,长时间跑或者图像分辨率一高就崩。

    学习路径上,这类问题最好的训练方式是先把链路拆成「采集—缓存—发送」三段,每段单独上板验证,而不是整条链路一起调。你们现在是三段一起跑的吗?如果是,建议先断开以太网,只验证采集进 FIFO 的数据对不对,再逐步接上后面。

  • ScriptBoy

    个人感觉你们大概率是发送侧没有背压,而不是FIFO深度不够。深度这东西只影响能扛多久的突发,扛不住长期带宽不匹配。先算一下:图像行频乘每行字节数得到平均写入速率,和以太网侧有效读速率比一比,如果长期是写快读慢,那FIFO再深也只是推迟溢出时间,最终每帧都会丢一段,画面就会错位。真正要解决的是让采集端能感知到发送端忙,最简单的办法是乒乓缓冲:两块内存轮流,一块采集时另一块发送,块切换时如果发送还没完成就丢整帧而不是丢半帧,上位机至少能看到完整帧或者直接黑一帧,而不是撕裂。另外UDP本身没有重传和流控,别指望协议栈帮你兜底,流控得自己在MAC和用户逻辑之间做。你们现在用的图像时钟和以太网用户时钟分别是多少?这个比例决定了FIFO该按多大突发来算。

  • EEnovice

    先给个排查顺序,别一上来就怀疑FIFO深度,那个是最容易被冤枉的。第一步用ILA同时抓图像时钟域的写使能、写指针、满标志,和以太网时钟域的读使能、读指针、空标志。看满标志是不是频繁拉高:如果是,说明采集端确实写太快,FIFO溢出,丢的是连续像素,画面一般表现为整块花掉或者某几行糊掉;如果满标志很少拉高但画面还是撕裂,那问题就不在深度,而在帧同步信息。第二步查UDP分包逻辑。很多队伍的实现是「一帧切成N个固定长度包直接发」,帧头里没带行号或者帧起始标志,接收端只能靠包序号拼。一旦中间丢一个包,后续所有包都往前挪,画面就横向错位,这跟撕裂的视觉表现几乎一样。你可以先在上位机做个实验:故意屏蔽掉一个包,看画面是不是出现同样的撕裂,如果是,基本就锁定是拼帧规则太脆弱。第三步看有没有背压。UDP发送通常没有反压,MAC层忙的时候你的发送状态机如果还在从FIFO读数据,读出来的字节就丢了。常见做法是在读侧加一个almost_full或者发送完成握手信号,让读指针在MAC忙时暂停。一个更稳的替代方案是把整帧先缓存到DDR或者大块BRAM,发送时按包发,发完一帧再切换,这样即使中间丢包,最多丢整帧,不会出现半帧错位。风险在于乒乓或者整帧缓存会引入至少一帧延迟,如果比赛对实时性要求高,得权衡。你们上位机现在的拼帧逻辑是按长度还是按帧头?这个决定了排查该往哪个方向使劲。

  • 嵌入式探索者

    先别急着改FIFO深度,我建议你按这个顺序做个五分钟的判断:把ILA同时挂在图像时钟域和以太网时钟域,抓写使能、写指针、满标志、读使能、读指针、空标志。看满标志是否频繁拉高。如果满标志几乎不动,那FIFO深度就不是主因,你算得再深也没用,问题在帧同步或分包规则上;如果满标志一直拉高,那才轮到算深度。算的时候别只算平均速率,要按突发长度算:图像一行的时间乘以行内像素速率,得到一行突发能塞进多少字节,再除以两个时钟频率比,乘个1.5到2倍余量。很多队直接拍个1024,结果行突发就超了,每行丢几个像素,画面就是横向错位,看起来像撕裂但不是。

    另一个维度是发送侧背压。UDP本身没有流控,这一点别指望协议栈。如果你的发送逻辑是「FIFO非空就读一个字节发一个字节」,而MAC层忙时你还在读,数据就丢了。常见做法是加乒乓缓冲:一帧分两块,采集写A块时发送读B块,块切换时如果发送没完成就丢整帧,这样上位机看到的是完整帧或者黑帧,不会是撕裂。代价是引入一帧延迟,对实时性有要求的场景要权衡。

    还有个容易忽略的点:高云GW2A的千兆MAC和你的用户逻辑时钟可能不是同一个,跨域信号如果只做了单bit打拍,多bit的指针或帧头传递就会采到中间态,出现偶发错位。建议用格雷码指针加两级同步,帧起始标志单独用握手或脉冲同步。你先抓一下满标志的拉高频率,再告诉我你的图像时钟和以太网用户时钟分别是多少,我帮你算一下深度够不够。

登录后可在本页底部提交回答

提问者

Verilog代码练习生查看主页
浏览「其他」

描述场景与已尝试方案,更容易获得有效解答

相关问题

同分类

提问建议

  • 标题写清核心疑问,避免「求助」「请问」等空泛用语
  • 正文补充环境、版本、报错信息或截图
  • 先搜索本站是否已有相近问题,减少重复提问
  • 若与课程相关,请标明课时或章节便于讲师定位