2026年FPGA大赛用高云GW2A做视频拼接,两路HDMI输入不同分辨率,怎么设计帧缓存才不撕裂?

开放6 回答 70 浏览

我们队今年电赛做多路视频拼接,用高云GW2A,两路HDMI输入分别是1080P60和720P60,输出统一1080P60。直接写DDR帧缓存后画面上下半屏撕裂,偶尔还有一行错位。有人说要双缓冲加乒乓,有人说要统一到输出时钟域再读。到底帧缓存该按输入时钟写、输出时钟读,还是先做缩放统一分辨率?求有电赛经验的给个可落地的架构。

分享:

6 个回答

  • EE小白

    先说结论:帧缓存不能只做一块,也不能只在输入域写完就直接给输出读。你们现在撕裂的根因,大概率是「写指针和读指针在同一块 buffer 上追着跑」——720P 那路写满一帧的时间比 1080P 短,两路节奏不一致,读侧又按输出时钟匀速取,必然出现半屏新半屏旧。

    可落地的做法是两段式:输入侧每路单独进一个异步 FIFO,把像素从各自的 HDMI 像素时钟搬到 DDR 控制器时钟域;然后在 DDR 里给每路开两块 buffer 做乒乓(ping-pong),写满一整帧才翻转写标志。输出侧统一在 1080P60 的像素时钟域里读,读之前先看这一路的「帧就绪」标志,读到的是完整那一帧,就不会撕裂。

    分辨率统一这一步,建议放在读侧或写侧都行,但别省。720P 那路你可以选择在写 DDR 前做最近邻放大到 1080P 画布,也可以原样存、读的时候按比例取地址。前者的好处是后面拼接逻辑简单,两路都是 1920×1080 的地址空间;代价是 DDR 带宽涨了约 2.25 倍。GW2A 这种器件带宽本来就紧,个人感觉写侧缩放更划算,因为缩放逻辑只跑一次。

    还有个容易翻车的点:DDR 突发和仲裁。两路写加一路读,如果读请求优先级太低,输出侧会饿死,表现就是偶尔一行错位。常见做法是给读通道更高优先级,或者用足够深的读出 FIFO 把突发抖动吸收掉。

    一个替代思路:如果两路分辨率固定不变,干脆别走 DDR,用片内 BRAM 做行缓存加缩放,成本可能更低,但 1080P 整帧放不下,只适合行级处理。

    你们现在 DDR 控制器是自己写的还是用高云 IP?这个决定了仲裁能不能改。

  • EE学生一枚

    先别急着上双缓冲,很多队伍一上来就搭乒乓,结果 DDR 带宽被吃满、仲裁一乱,撕裂反而更严重。你这个现象——上下半屏新旧画面、偶尔一行错位——基本能确定是「读写指针在同一块 buffer 上追着跑」加上跨时钟域没处理好。720P60 那路一帧写满的时间比 1080P60 短,两路节奏根本不同步,读侧却按输出时钟匀速取,不撕裂才怪。

    可落地的架构我建议这样分:输入侧每路各自进一个异步 FIFO,把像素从 HDMI 的像素时钟搬到 DDR 控制器时钟域,这一步是跨时钟域的基础,别省。然后在 DDR 里给每路开两块 buffer 做乒乓,写满一整帧才翻转写标志位。输出侧统一在 1080P60 的像素时钟域里读,读之前先查这一路的帧就绪标志,保证读到的是完整帧。

    分辨率统一放在哪?我倾向读写侧都行,但一定要做。720P 那路可以在写 DDR 前用最近邻放大到 1080P 画布,省得读侧做插值增加时序压力。这里有个容易踩的坑:DDR 突发长度设得太短、或者两路读写请求仲裁不公平,读侧会出现饥饿,表现就是偶发的行错位。建议给读通道更高优先级,突发长度对齐 8 或 16。

    另外提醒一个风险:GW2A 的 DDR 控制器 IP 配置里,如果位宽和时钟频率没算好,两路 1080P60 的写带宽加上一路读带宽很容易顶到上限。你们可以先用计算器估一下:1080P60 单路约 148.5MHz 像素时钟,每像素 2 字节,两路写一路读,峰值带宽要留 30% 余量。带宽不够时,宁可把 720P 那路在输入侧缩放到 1080P 再写,也别在 DDR 里存两种分辨率。你们现在 DDR 控制器跑的是什么频率、位宽多少?这个直接决定方案能不能撑住。

  • 单片机爱好者

    核心就一句:输入各自异步 FIFO 进 DDR 乒乓,读侧统一到输出像素时钟域,分辨率在写之前统一掉。撕裂和行错位基本都是读写同块 buffer 加跨时钟域没隔离导致的。

  • 面向百度

    这个问题我想从「为什么会撕裂」这条因果链往深里说,因为很多队伍把双缓冲当成万能药,结果治标不治本。

    撕裂的本质是:显示控制器在扫描一帧的过程中,读到的像素来自两个不同的源帧。只要你写和读指向同一块存储、且没有帧级同步,撕裂就一定会出现。乒乓缓冲解决的是「写这块、读那块」的隔离问题,但它不解决跨时钟域,也不解决两路输入节奏不一致。你的 720P60 和 1080P60 帧率虽然都是 60,但一帧内的像素写入时间完全不同,写指针推进速度不一样,这就是为什么两路拼在一起后撕裂更明显。

    所以正确的顺序是:先做时钟域隔离,再做帧级双缓冲,最后才谈分辨率统一。异步 FIFO 是第一道墙,把每路 HDMI 像素时钟域的像素安全搬到 DDR 控制器时钟域;乒乓缓冲是第二道墙,保证读侧永远读完整帧。这两步做完,撕裂基本就没了,剩下的行错位多半是 DDR 仲裁饥饿或 FIFO 深度不够。

    分辨率统一我建议放在写侧,理由是读侧在 1080P60 输出时钟域里做缩放会引入额外延迟和时序压力,而写侧反正要过 FIFO,顺手做最近邻放大成本最低。最近邻虽然画质一般,但电赛评分更看稳定性和实时性,双线性插值除非你们时序余量很足,否则不建议。

    再往深一层,DDR 带宽才是真正的隐形天花板。1080P60 每像素按 RGB565 算 2 字节,单路写约 297MB/s,两路写加一路读接近 900MB/s,GW2A 的 DDR 控制器如果跑 16 位 200MHz,理论带宽 800MB/s,已经很紧张了。这时候仲裁策略就关键:读通道必须高优先级,否则显示侧一饿就出错行。

    学习路径上,我建议你们先把单路 1080P 的写-乒乓-读跑通,用示波器或逻辑分析仪看帧同步信号,确认无撕裂后再加第二路。很多队伍一上来就搭两路,出了问题根本定位不到是哪一层。你们现在单路跑通了吗?如果单路都还有错位,先别碰拼接。

  • 数字系统萌新

    先说一个容易被忽略的点:撕裂不是「缓存不够」造成的,是「读的那一帧和写的那一帧不是同一帧」造成的。你们上下半屏新旧画面,本质就是扫描到一半时源帧换了,而读侧没有帧级的原子切换。所以整条设计链应该围绕「什么时候允许换帧」来组织,而不是堆 buffer 数量。

    按这个思路,我建议把数据流切成三段,每段只负责一件事。第一段是输入域到 DDR 域:两路 HDMI 各自的像素时钟完全独立,1080P60 和 720P60 的像素速率也不一样,直接拿像素时钟去驱动 DDR 写口,跨时钟域就已经输了。每路各挂一个异步 FIFO,写侧用各自像素时钟,读侧统一到 DDR 控制器时钟,这是第一道隔离墙。第二段是 DDR 内的帧组织:每路各开两块 buffer 做乒乓,写满一整帧才翻转「帧就绪」标志,写侧永远只写非就绪那块。第三段是读侧,统一在 1080P60 输出像素时钟域里取数,取之前先看标志位,保证整帧原子切换。

    这里有个取舍要提前想清楚:分辨率统一放在哪一级。放写侧,就是 720P 那路在进 DDR 前缩放到 1080P 画布,DDR 里两路都是 1080P,读侧逻辑最简单,代价是缩放器要跑在 720P 的像素时钟域、且写带宽按 1080P 算。放读侧,就是 DDR 里存原始分辨率,读的时候再放大,省写带宽但读路径要处理两种尺寸,容易出地址算错。电赛这种时间紧的场景,我倾向放写侧,用最近邻就够了,画质不是评分重点。

    真正会咬人的其实是 DDR 仲裁和突发长度。两路写加一路读,如果读请求被写请求长期压住,读侧 FIFO 一空,输出就会去重复上一行或者拉黑,看起来也像撕裂。所以读口要给够优先级或者留出固定时隙,突发长度对齐 DDR 的 burst 边界,别让一次读跨行跨页。这个坑比双缓冲本身更容易翻车,建议早点用逻辑分析仪抓读 FIFO 的空满波形验证。

    你们现在 DDR 控制器用的是高云自带的 IP 还是自己写的仲裁?这个直接决定读优先级能不能调。

  • 数字设计新人

    别急着加 buffer,先确认读侧是不是在读一个「正在被写」的帧。两路各一个异步 FIFO 进 DDR,每路双缓冲、写满整帧才翻标志,读侧统一到 1080P 输出时钟域,720P 那路写之前先缩到 1080P 画布,基本就稳了。

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

提问者

Verilog小白查看主页
浏览「其他」

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

相关问题

同分类

提问建议

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