ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FPGA图像处理实战:基于SMPTE-SDI IP核的HD-SDI视频流解析

FPGA图像处理实战:基于SMPTE-SDI IP核的HD-SDI视频流解析 SDISerial Digital Interface这个接口在广电、医疗、工业视觉这些领域里几乎是无处不在的存在。做FPGA图像处理的工程师只要一碰到SDI大概率第一时间就去翻SMPTE 292M协议文档从几百页的英文规范里找“3FF 000 000 XYZ”这几个时序基准码到底怎么对齐结果折腾三天项目进度还是原地踏步。说实话这个坑我自己也踩过而且踩得相当深。这篇文章不打算带你一个字一个字去啃协议而是换个思路直接用Xilinx FPGA的SMPTE-SDI IP核把HD-SDI视频流的解析过程变成一次“搭积木”式的工程实践。看完你就知道视频数据是怎么从串行差分线上被收下来、做完时钟恢复、排列成并行像素流最后通过AXI4-Stream接口交给FPGA内部逻辑处理的。文章里会配关键时序图和数据对齐关系适合刚接手SDI相关项目、或者做视频采集卡/图像处理板卡的同学参考。1. 方案选型为什么直接上SMPTE-SDI IP核1.1 SDI协议解析的真正难点在哪先聊一个现实问题HD-SDI的物理层速率是1.485Gbps虽然这个速率在今天看起来不高但它背后的工程问题一点不少。SDI是单向串行接口信号经过线缆传输后会有衰减、抖动和码间干扰接收端必须先做均衡Equalization、时钟恢复CDR和解串才能拿到干净的并行数据。这一块涉及高速模拟前端和锁相环光靠用户逻辑里的状态机是玩不转的。再往上一层SDI不是简单地把像素数据串行发出去就完了。它要按照SMPTE 292M的格式把视频数据划分成行Line每行又分成有效视频区Active Video和水平消隐区Horizontal Blanking消隐区里还嵌入了时序基准码TRSTiming Reference Signal也就是大家经常听说的EAV和SAV。除此之外还有一个标准叫SMPTE 299M规定了辅助数据ANC Data的格式——音频、时间码、HDR元数据这些都藏在消隐期的ANC包里。所以自己写SDI接收逻辑等于要同时搞定三个层面的问题物理层的CDR和均衡、链路层的8B/10B解码和字对齐、还有协议层的TRS检测和行场解析。任何一个环节出错画面不是黑屏就是花屏而且排查起来极其痛苦。1.2 SMPTE-SDI IP核到底帮你干了哪些活Xilinx的SMPTE-SDI IP核本质上是把上面那三层工作打包成了一个可配置的模块。使用时只需要把它挂在GT TransceiverGTP/GTX上IP核内部会自动完成串行数据流的解串、解码、对齐和TRS检测最后输出一路AXI4-Stream格式的视频数据流。这里说的AXI4-Stream接口经常用FPGA的工程师应该不陌生它不像AXI4-Full那样需要地址读写而是纯粹的流式数据传输由tdata、tvalid、tready、tuser、tlast这几个信号组成。SDI核把解析好的YUV 4:2:2 10bit像素数据按行打包好一帧一帧地往这个接口上送用户逻辑只需要在tvalid有效时把数据接住就行。值得说明的是IP核同时提供了接收RX和发送TX两条通路。接收方向负责解串和解析发送方向则是把并行视频数据编码成SDI串行流发出去。做采集或者输入处理的项目用RX通路就够做发送卡或者视频输出再考虑TX。很多开发板上的SDI参考设计都是TX/RX同时使能方便做回环测试。1.3 一个误区IP核不是黑盒接口才是核心我见到过不少新人拿到IP核配置向导之后随便点了几下生成完IP就往工程里一放然后对着没有输出的tdata发呆。这里有个很重要的认知SDI IP核交付的是“已经解好串、对齐好字的视频流”但它并不会替你做后续的视频处理比如色彩空间转换、缩放、帧缓存、显示时序生成这些统统要自己写。换句话说IP核帮你把“获得干净视频数据”这个最脏最累的活干完了但你要真正把画面显示出来还需要理解它输出的数据结构——也就是每个时钟周期里tdata上那几十个bit分别代表什么tuser的哪个位是帧同步信号tlast在什么位置拉高。这部分工作没有捷径但好消息是它比啃协议文档轻松得多抓住几个关键信号就行。2. 硬件层面的关键决策引脚、时钟与参考设计2.1 GT Bank、参考时钟怎么选用SMPTE-SDI IP核第一步不是在Vivado里点IP配置而是先把硬件底子搞清楚。SDI的高速串行信号从连接器进来之后一般先过一颗SDI专用电缆均衡器比如LMH0384、GS2974这类芯片把单端信号转换成CML差分对然后送进FPGA的GT Bank。选择GT Bank时要看FPGA芯片的封装和可用资源。Artix-7系列里如果选到合适的封装GTX Bank数量有限而SDI信号最好分配在专用的高速Bank上避免与PCIe、SFP等其他高速接口抢位置。我自己的经验是画原理图之前就要先确认SDI的TX/RX差分对接到了哪个Bank参考时钟引脚是不是和这个Bank匹配不然后期布线换Bank简直是灾难。参考时钟的选择也很关键。SMPTE-SDI核的线速率在1.485GbpsHD-SDI或2.97Gbps3G-SDI对应的GT参考时钟通常是148.5MHz或者148.35MHz59.94Hz帧率对应也有些配置会用125MHz。这个频率必须和你的视频源帧率严格对应否则会出现间歇性的画面跳动。配置IP时界面里允许设置的参考时钟范围会根据目标线速率自动算出来你只需要根据板卡实际晶振频率选择即可。2.2 时钟架构恢复时钟与线路锁定SDI信号接收过程中最容易被忽略但也最重要的是时钟架构。FPGA内部存在好几套时钟它们之间有严格的频率关系。第一套是GT的参考时钟GT_REFCLK它只作为GT收发器的基准不直接参与像素数据处理。第二套是恢复时钟Recovered ClockSDI接收端通过CDR从串行数据流中提取出和发送端同步的时钟这个时钟就是视频数据的“节奏”。第三套是用户逻辑工作时钟通常是恢复时钟分频或者直接使用恢复时钟。这里要特别提一下“线路锁定”Line-Locked的概念。SDI视频流的像素时钟必须锁定在行频上这样处理音频和视频同步时才能保证样本数一致。Xilinx的SDI IP核会输出恢复时钟相关的信号用户逻辑如果需要做音频嵌入或者解嵌必须基于这个恢复时钟域来操作不能随便用板上的自由振荡时钟否则音频会慢慢漂移。做视频采集卡的人应该对这个坑深有体会。2.3 功耗、复位顺序和可靠性设计SDI项目的功耗估算要留足余量。GT收发器本身就是功耗大户1.485Gbps链路加上TX/RX同时工作电流轻松上到几百毫安。再加上FPGA内部逻辑、DDR颗粒、HDMI/SDI驱动芯片电源设计不能抠门。我建议至少在电源裕量上留出30%以上同时每个电源轨的纹波控制在30mV以内这对GT的抖动性能至关重要。复位设计同样不能马虎。SDI IP核的复位输入一般叫作sdi_rst它控制着核内部的全部状态机。上电后必须先等待GT的复位完成信号比如gt_rxresetdone拉高再释放sdi_rst顺序反了的话IP核可能永远锁不定信号。不少工程师遇到“为什么SDI收不到视频”的问题最后查出来就是复位时序不对。3. 核心节点解析配置步骤与时序图深度拆解3.1 Vivado中的IP配置以Vivado/Vitis版本为例打开Vivado的IP Catalog在搜索框里输入“SDI”一般能找到“SMPTE SDI LogiCORE IP”或者类似名称的IP。双击创建一个IP实例配置界面主要需要关注几个选项线速率Line Rate选择HD-SDI/3G-SDI等参考时钟频率以及数据接口的位宽。数据位宽的选项很有意思IP核允许你选择AXI4-Stream接口为20位、32位或者40位等不同宽度这些位宽对应不同的数据打包方式。如果是1080i/720p这类HD视频20位模式下tdata上每个周期正好是一个像素的YCbCr数据Y占10bitCb/Cr各占10bit交替出现32位模式下则是一次打包两个像素。选32位的好处是tdata宽度对后续DDR缓存比较友好因为DDR的位宽通常做32位或64位选20位则逻辑更直观。看项目需求定。配置完成后IP核会生成例化模板。在顶层模块里你需要在IP核周围加上GT的例化和时钟资源连接。Vivado的IP生成目录下会附带一个参考设计Example Design强烈建议直接参考它里面有完整的GT例化、复位逻辑、时钟缓冲器连接比自己从头接线省太多事。3.2 关键时序从K28.5到EAV/SAV的全链路对齐接下来是这篇文章最有价值的部分——HD-SDI的数据时序到底是怎么组织的。理解了这一节你以后看到任何SDI相关代码都会觉得亲切。SDI串行数据流在物理层是经过8B/10B编码的比特流接收端先要找到K28.5特殊字符来建立字对齐。对齐之后数据被组织成一个个10bit的码字。这些码字在IP核内部被转换为20bit并行数据然后经过ESCRAMBLING解扰操作恢复出真正的视频数据。视频数据按照行来组织。每一行都以一个时序基准码TRS开头整个TRS由4个码字组成3FF、000、000、XYZ。前三个是固定的XYZ则携带了场、消隐和行标识信息。TRS分为两类EAVEnd of Active Video出现在有效视频结束的位置SAVStart of Active Video出现在有效视频开始的位置。如图示意一行HD-SDI数据流 |- EAV -|- 水平消隐区 -|- SAV -|- 有效视频区 -| | 3FF | 000 | 000 | XYZ | ANC辅助数据/填充 | 3FF | 000 | 000 | XYZ | Cb Y Cr Y ... |从EAV的XYZ到SAV的XYZ之间的区域就是水平消隐期长度跟视频格式有关。比如1080i格式一行总共1920个有效像素加上消隐区一行总样本数通常是2200不同制式有差异。有效视频区就是实实在在的图像数据按Cb Y Cr Y的4:2:2采样结构排列每个分量10bit。XYZ这个码字里最有意思的是它的bit5、bit6、bit7三位它们分别表示H、V、F标志H位区分当前是EAV还是SAVH1表示EAVH0表示SAVV位表示当前是否处于垂直消隐期F位表示当前是奇数场还是偶数场。这三个标志位组合起来就能精确确定当前处在画面的哪个位置。3.3 拿到AXI4-Stream后的数据还原方法IP核完成所有协议解析之后通过AXI4-Stream接口把数据吐出来。先看一个典型的接收数据时序文字描述版m_axis_video_tdata : | Cb0 Y0 Cr0 Y1 | Cb2 Y2 Cr2 Y3 | ... | 行尾填充 | m_axis_video_tvalid: |_______高电平持续整个有效行_______| m_axis_video_tlast : | |____最后一个数据时拉高| m_axis_video_tuser : |第一个有效数据时拉高帧/场起始标记| |这里有个关键点tvalid不是只在有效视频区拉高。在消隐期SDI数据流中依然有数据不断输出只是这些数据不是图像像素而是ANC辅助数据或者无效填充。所以如果你想提取真正的图像数据不能只看tvalid还要通过IP核输出的行场同步信号或者EAV/SAV信息来判断当前是否处于有效视频区。我自己常用的做法是在FPGA内部维护一个行计数器和一个帧计数器收到tuser的帧起始脉冲后清零然后统计tdata上有效像素的数量。等到有效像素数量达到1920对1080i或者1280对720p时就认为这一行收满了可以做行缓存或者直接写入DDR。这种做法不依赖IP核内部的具体实现即使以后换IP版本也基本不用改逻辑。另一个实用技巧是把32位tdata拆成两个像素来处理。如果tdata的布局是{Cb_n, Y_n, Cr_n, Y_{n1}}这么交错排列的那么一个时钟周期内其实拿到了两个像素的Y分量和一个Cb一个Cr。你可以把每个像素补齐成YUV 4:2:2格式后存入FIFO也可以通过简单换算转成RGB。总之了解数据打包格式是后续所有图像处理的第一步这块一旦概念清晰后面的代码写起来就非常顺。4. 常见问题与排查技巧实录4.1 常见故障速查表这部分记录一下我调试SDI接收项目时碰到过的高频问题按经验整理成表方便直接对照排查。故障现象可能原因排查方法IP核完全无输出tvalid一直为低GT参考时钟未配置或晶振频率不对用ILA抓gt_rxresetdone是否拉高测量参考时钟引脚有输出但画面整体偏移/花屏SAV/EAV对齐位置理解错误像素坐标偏移检查tuser信号和tlast位置确认行数据是否移位画面偶尔黑一下信号源不稳定或CDR锁定丢失检查线缆和连接器查看rx_aligned/rx_locked信号是否出现毛刺输出帧率只有标称的一半场同步/帧同步提取逻辑错误重点观察F位和V位标志确认奇偶场判断条件是否正确音频数据取不到ANC辅助数据没被正确解析确认消隐期数据是否被丢弃检查ANC包的用户数据字UDW位置热插拔后需要重新复位才能恢复复位状态机不够健壮增加持续监测功能检测到锁定丢失后自动执行软复位流程这张表里最常出问题的就是第二行“画面整体偏移/花屏”。这种问题通常不是SDI链路本身出错而是你在提取像素时没有根据SAV的位置开始计数。如果你把消隐期的前几个数据误当成有效像素那整行数据都会向右偏移图像看起来就像被水平“撕裂”了一样。处理方法很简单在接收逻辑里检测到SAV的XYZ码字后再开始正式的有效像素计数。4.2 从行业社区学到的几个典型排查思路Xilinx官方论坛和各大FPGA技术社区里SDI相关的求助帖常年居高不下。久而久之我也总结出了一些通用的排查套路在这里分享给你们。第一招先测物理层再谈协议层。如果SDI输入信号不正常后面所有逻辑都白搭。可以用Vivado的IBERT IP核直接对GT链路做误码率测试根据眼图结果判断信号质量。实测下来如果误码率在1e-12以下物理层基本没问题可以放心去查协议层。不会用IBERT也没关系先用示波器探一下GT的差分接收引脚看有没有明显的信号幅度和眼图张开度至少能排除线缆和连接器的问题。第二招巧用环回模式。SMPTE-SDI IP核参考设计里一般会带一个近端PMA环回Near-End PMA Loopback或者远端环回选项。在SDI发送端发一个测试图样然后把串行数据直接环回到接收端就能在不依赖外部信号源的情况下验证整条链路。如果环回模式下能正常收到图像说明FPGA和IP核配置没问题问题一定出在外部输入链路上。第三招不要忽略AXI4-Stream的握手信号。FPGA用户逻辑如果没拉高treadySDI IP核会进入等待状态数据就会积压在核内部出不来看起来就像是“没有数据”。这种问题极其隐蔽因为tvalid和tdata看起来可能是正常的但tready一直为低导致数据流卡住。排查方法很简单在ILA波形里同时抓tvalid、tready、tdata三个信号看握手状态。接收端如果暂时不需要处理数据也要保证tready信号逻辑正确不要出现死锁。4.3 测试验证的实用技巧最后聊聊怎么把SDI接收链路完整地测起来。毕竟光看波形只能确认数据通路上有东西在跑是否真的是正确的视频画面还必须结合图像内容来判断。最省心的方式是利用SDI信号发生器。市面上的SDI测试信号源能输出彩条、灰阶、活动图像等标准测试图形配合IP核接收和缓存逻辑在HDMI显示器上或者通过JTAG读回帧缓存一眼就能看出接收是否正常。如果预算紧张也可以用支持HDMI转SDI的转换器虽然画质不是专业级别但做功能验证足够了。我自己做验证时有几个固定动作先在FPGA里写一个简单的视频帧存模块把SDI核输出的YUV数据写入DDR3然后通过Vivado的ILA抓取写入DDR前的最后一级数据检查每一行的像素数量是否和预期一致。对于1080i30这种隔行格式还要特别注意场标志F位的切换规律奇数场和偶数场的数据顺序不能搞混。另外一个小技巧是打印错误计数。在SDI接收逻辑里加一个CRC校验或者简单的行计数值比对如果连续检测到不正常的行长度就累加一个错误计数。实测中这种错误统计比单纯看画面更敏感很多间歇性故障在画面上可能只是偶尔闪几帧但错误计数早就悄悄涨上去了。有了这个统计值排查“偶发黑屏”“偶发花屏”这类神出鬼没的故障时就多了一双眼睛。对于刚接触SDI的朋友我特别想说一开始就打算“先熟读协议再动手”的思路在SDI这种复杂接口上真的效率太低。更务实的路径是先跑通IP核参考设计用ILA把EAV/SAV和XYZ这几个关键点抓到亲眼看一遍数据流的组织方式然后再回头翻协议文档去验证理解。这时候原来觉得晦涩的那些章节往往会变得豁然开朗。
返回列表