最近在准备FPGA秋招,看到很多面经都在问AXI4-Stream实时视频处理。我想问一个具体的场景:如果要做两路1080p@60fps视频的实时拼接,输入源是异步的,用异步FIFO做同步,FIFO深度怎么根据帧间隔抖动和读写时钟频率计算?另外拼接后的输出时序怎么保证不撕裂?求大佬给个推导过程和Verilog代码框架,最好能画出状态机。
2026年FPGA秋招,手撕Verilog实现AXI4-Stream实时视频拼接,多路输入同步用FIFO深度怎么算?求推导和代码框架
12 个回答

异步FIFO深度推导其实核心就一个公式:Depth > (写时钟频率/读时钟频率) (最大写突发长度) – (读时钟周期内能读走的数据量)。1080p@60fps,一行大概2200个像素(含消隐),帧消隐期间可以积累数据。如果两路PCLK都是148.5MHz,但相位和漂移不一致,最坏情况是一路连续写满一行另一路才开始读。个人建议深度至少取两行数据量再加20%余量,也就是4400左右。代码框架重点在状态机:IDLE等帧同步,CAPTURE收双路FIFO数据,MERGE按拼接位置交替读FIFO输出。你当前是准备做仿真验证还是已经在板级调过?

这问题其实面试官想考察两个点:一是你懂不懂异步FIFO深度计算的工程意义,二是你会不会处理视频时序里的帧同步头。先别急着背公式,得先搞清楚你的输入源是什么。如果是两路独立的Camera Link或MIPI,它们的帧同步(VSYNC)周期本身就有抖动——假设标称60fps(16.67ms),实际可能差几个微秒到几十微秒。异步FIFO深度要能缓冲最坏情况下的行累积差。推导思路:先算读时钟周期T_rd,写时钟周期T_wr,然后找最大写使能持续时间。对1080p来说,有效像素1920,但行消隐约280个时钟,所以一行总时钟2200。如果两路写使能可能连续写满两行才遇到读使能拉高,那深度至少需要2行2200=4400。但是更关键的其实是帧同步对齐,很多面试者忽略这个。建议用乒乓操作:两路FIFO各自存完整一帧,再用一个拼接控制状态机在帧消隐期切换读指针。状态机分四态:WAIT_FRAME(等两路VSYNC都到)、WRITE_FRAME(同时写两路FIFO)、SWITCH_OUT(读完一帧后切换输出源)、FRAME_GAP(留一个消隐间隙做同步)。代码框架方面,Verilog里用格雷码跨时钟域读指针,depth取2的幂次方便格雷码转换,实际5120比较安全。你如果还要考虑输出端AXI4-Stream的tready反压,那FIFO深度还得再乘1.5倍,因为读可能被tready拉低停几个周期。这个细节一般面试官会追问,提前准备好。

从实用角度泼点冷水:秋招手撕代码不会真让你推FIFO深度公式,更多是考察你的系统思维。面试官大概率会问'你怎么保证两路拼接处没有撕裂',标准答案是'在帧消隐期切换输出源,用双帧缓冲'。但很多人忽略一个坑:异步FIFO的empty和almost_empty信号跨时钟域时会有延迟,可能导致读使能过早拉高读到不完整数据。建议在写侧加一个行计数器,每写完一行拉一个标志给读侧,读侧等两路行标志都有效才启动读。深度计算可以简化:取两路时钟频率差的最大抖动时间乘以写入速率。比如两路PCLK都是148.5MHz但差±100ppm,一帧16.67ms最多差1.67us,乘以148.5M就是约248个像素,加上一行消隐280,深度设512就够。但面试官如果追问'怎么保证不溢出',你就说要预留两行余量。状态机画三个就够了:IDLE、SYNC(等两路帧头)、STREAM(按拼接顺序读FIFO)。别画太复杂,面试官只看你逻辑清晰不清晰。你手头有现成的仿真模型吗?可以拿个简单testbench先跑一次行同步对齐的场景看看。

面试官看到这个问题其实心里想的是:你能不能在纸上把写使能窗口和读时钟周期的关系画清楚。深度不用背公式,你拿白板画两行时钟,把最坏情况下一路写满一行时另一路才开始读的场景标出来,大概需要两行再加一行的余量才能兜住帧消隐期的累积。状态机就三个状态:等帧同步、收数据、拼完输出。别把代码写太复杂,面试官更看思路。

你问的这个问题其实秋招面经里出现率很高,但大部分人只背了公式没想过真实场景。我先说一个容易被忽视的点:两路输入虽然标称都是1080p@60fps,但实际摄像头晶振有ppm偏差,帧周期可能差几十微秒。假设写时钟148.5MHz,读时钟也是148.5MHz但不同源,最坏情况是连续两帧的写使能都提前于读使能,导致FIFO里累积了将近一帧的数据量。这时候你设512深度的FIFO肯定爆。正确的做法是先测两路帧同步信号的最大相位差,再结合行消隐时间算。1080p一行2200个像素,帧消隐45行,所以一帧里有效写使能窗口是1125行,但间隙有45行可以读走数据。保守点深度可以取两行数据量再加一行余量,就是32200=6600。但如果你用双帧缓冲的乒乓结构,每个FIFO只需要存一帧,深度可以降到19201080/2这种级别,不过面积大很多。面试时你可以先问面试官:输入源的帧同步是同一个PLL产生的还是完全独立?独立的话我建议用行同步对齐加FIFO深度为两行数据量,同一个PLL的话深度可以缩到一行加余量。代码框架上,状态机我会设IDLE、WAIT_FRAME、CAPTURE_LEFT、CAPTURE_RIGHT、MERGE五个状态,关键是MERGE阶段要等两路FIFO的almost_empty信号都无效才能启动读使能,否则输出会有撕裂。你在仿真里见过那种输出图像中间出现黑白条的情况吗?大概率是读使能时序没对齐。

深度推导其实就抓住一个变量:两路帧同步信号的相对抖动。假设帧周期16.67ms,两路差100ppm就是1.67us的抖动,折合到148.5MHz下约248个时钟周期。加上一行消隐280个时钟,深度设512就够。但如果你没做帧同步对齐,最坏情况可能差一个完整帧周期,那深度就要按一行乘以帧行数来算。建议代码里加一个行计数器在写侧,每写完一行拉一个done信号跨时钟域给读侧,读侧等两路done都有效再读,这样能避免读到半行数据。状态机可以简化成两状态:IDLE检测两路vsync上升沿后进CAPTURE,CAPTURE里靠行done标志控制拼接输出。你手撕代码时记得把读写指针的格雷码转换写清楚,面试官会盯着那个看。你现在是已经写完仿真了还是卡在综合时序上?

我猜你手头应该还没有具体的板级测试数据吧,那就先别急着套FIFO深度公式,容易绕晕。这个场景的核心矛盾其实不是深度本身,而是两路帧同步信号之间的相对抖动到底有多大。如果你只是拿两个同型号摄像头对着同一信号源,晶振ppm差异通常很小,帧周期差可能在微秒级,那深度取一行数据量再加个几百就够,算出来大概2200+256这种级别。但如果是完全独立的两个视频源,最坏情况可能差到一整个帧周期——那深度就得按一帧来算,19201080,这就完全不是同一个数量级了。所以你第一步不是推导,而是去确认你的输入源特性:两路VSYNC是否有硬件上的同步机制?比如有没有用同一个PLL或者外部同步信号?如果没有,那老老实实把深度设成一行整数据量的两倍加余量,然后靠帧消隐期做拼接切换。至于代码框架,我建议你状态机只做两件事:写侧用行计数器控制每行写完拉一个done信号跨时钟域到读侧,读侧等两路done都有效再交替读FIFO输出。这样撕裂问题就变成了一个简单的握手问题,不用搞复杂的状态机。你现在的摄像头接口是MIPI还是SDI?不同接口的帧同步抖动范围差很多,这个会影响你的最终深度取值。

你这个问题,面试官大概率不会让你当场推一个精确的数字,而是想看你能不能把写使能窗口和读时钟周期的关系画清楚。简单点说:假设两路写时钟都是148.5MHz但不同源,最坏情况是一路已经写满一行(2200个像素)另一路才开始读,那深度至少要2200。再加上帧消隐期间写使能不停而读使能可能被拉低,再加一行余量,总共4400左右就够了。状态机你就写三个状态:IDLE等两路VSYNC上升沿、CAPTURE收数据到FIFO、MERGE交替读FIFO输出。手撕代码时注意异步FIFO的格雷码指针要写对,别的面试官一般不深究。你现在是在看面经阶段还是已经写过仿真了?

个人感觉你这个问题其实可以拆成两个层面来看,一个是秋招面试时怎么答才不露怯,另一个是真实工程里怎么选参数。先说面试场景:面试官大概率不会让你当场心算一个精确的深度数字,他更想听你讲清楚异步时钟域下的最坏情况累积模型。你拿白板画两路写使能窗口,假设两路PCLK都是148.5MHz但不同源,ppm差导致帧周期相差几十微秒,那最坏情况就是其中一路连续写两行有效数据(22002=4400个像素)而另一路读使能还没拉起来,这时候深度取4400再加一行余量到6600左右就能兜住。但这里有个很多人忽略的坑——你要区分帧同步信号是否做了硬件对齐。如果两路VSYNC是独立产生的,它们之间的相对抖动会累积,深度就得按一帧数据量来算,19201080=2M级别,这时候单级FIFO就不现实了,得用双帧缓冲乒乓结构。代码框架上我建议你状态机只做三件事:IDLE等两路VSYNC上升沿对齐,CAPTURE阶段每写满一行就往FIFO里推一个行done标志,MERGE阶段等两路行done都有效才交替读FIFO输出。手撕代码时注意异步FIFO的格雷码指针要写对,跨时钟域的empty信号采样延迟可以用两级寄存器打拍。面试官如果追问怎么保证拼接处不撕裂,你就说在帧消隐期切换输出源,同时读侧要等写侧行计数器跨时钟域过来确认数据完整。你现在是已经写过仿真了还是刚开始看代码框架?如果是后者,建议先搭个简单的单路FIFO读写测试,把格雷码指针的跨时钟域逻辑调通,再上双路拼接,不然容易把自己绕晕。

深度推导的核心其实就一个变量:两路帧同步信号的相对抖动范围。假设帧周期16.67ms,两路晶振ppm差100,那最大抖动就是1.67us,折合到148.5MHz下约248个时钟周期。加上一行消隐280个时钟,深度设512就够了。但这是建立在两路VSYNC有硬件同步机制的前提下,比如用同一个PLL分频或者外部同步信号对齐。如果完全没有同步,最坏情况可能差一个完整帧周期,那深度就得按一行乘以帧行数来算,直接上双帧缓冲更稳妥。状态机可以简化为两状态:检测两路VSYNC上升沿后进入采集模式,然后靠行done信号控制拼接输出。代码里记得把写指针格雷码转换和读指针格雷码转换分开写,面试官会盯着那个看。
发表回答
登录后可在本页底部提交回答