ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ARINC818上板验证实战:从时钟复位到图像回读的FPGA调试全流程

ARINC818上板验证实战:从时钟复位到图像回读的FPGA调试全流程 说实话看波形仿真的时候ARINC818协议解析这件事让我产生过一种错觉帧头、CRC、数据负载该算的都算清楚了仿真波形也齐整得像教科书。等到把工程综合完下载到板子上接上光模块那一刻才意识到上板验证完全是另一个世界。这篇是系列第三篇前面两篇分别把ARINC818的帧结构、FC-AV映像规则、OL行切割逻辑和仿真工程讲完了。这篇接着写从协议解析逻辑落地到FPGA之后怎么一步步把它真正验证跑通。内容按我实际调试的顺序来先讲整体验证思路再讲时钟复位这些底层的坑然后是链路层误码测试、OL解析验证、带宽预算最后是怎么用图像回读做内容级确认。适合正在做ARINC818接收或者航电视频类测试的FPGA工程师参考你哪怕还没接触过这个协议里面的分层验证思路和上板调试方法也值得借鉴。1. 上板验证的思路先分清楚每一层该验证什么1.1 仿真里你看不见的三类问题行为仿真能解决的是逻辑正确性问题状态机会不会走飞、FIFO会不会溢出、CRC计算对不对、OL切分后行数据是否完整。这些问题当然重要但仿真环境本质上是理想化的它不会告诉你三件上板才会暴露的事。第一是物理层问题。2.5Gbps级别的高速串行链路PCB走线长度、过孔stub、连接器质量、光模块的CDR锁定特性这些在仿真里完全没有体现。仿真里你给一个理想比特流进去解析状态机跑得欢天喜地实际上板后接收端的恢复时钟可能有几百ps的抖动字节边界可能偶尔对不齐误码率可能高到协议层根本没法正常工作。第二是复位时序问题。行为仿真里复位信号通常是全局变量一拍拉低所有模块同时清零皆大欢喜。真实硬件里全局复位网络到达各个触发器的时间有先后异步复位释放的瞬间如果不在时钟边沿附近可能造成亚稳态GT收发器的复位要求更是严格往往需要配合CDR锁定、RX同步状态机一起判断不是一根线拉低再拉高就能解决的。第三是跨时钟域问题。ARINC818解析逻辑里GTX/GTH输出的并行数据时钟和后续图像处理用的像素时钟往往不是整数倍关系。比如1080p60的像素时钟是148.5MHz而2.5Gbps线速率、20bit并行数据对应的用户时钟是125MHz。这两个时钟域之间的数据交互仿真里可以用理想握手掩盖上板后必须用异步FIFO或格雷码同步老老实实处理否则就会出现偶发的像素错位。1.2 四层验证金字塔我在实际项目中习惯把上板验证拆成四层从底层往上逐层确认。不要跳级底层不稳上层看到的都是假象。层级验证目标常用手段通过标准物理层光链路可用、误码可接受IBERT/PRBS、环回光模块BER 小于 1e-12字同步与链路层8B/10B对齐、RX Sync稳定GT状态寄存器、ILA抓RXDATA无失步、无字错误FC帧与OL层帧头正确、CRC通过、OL切分正确硬件计数器、ILA比对、长时间跑测CRC错误为0、OL行号连续图像内容层像素值、行场位置正确测试图案、DDR回读比对、显示输出像素无错位、亮度色度误差可接受这个金字塔的思想其实和软件测试里的分层测试很像先保证底层依赖可靠再测上层逻辑。如果你一上板就直接去盯画面发现画面有条纹或者花屏你会陷入一个非常痛苦的境地——你根本不知道问题是出在光模块、GT配置、帧解析还是行缓存同步。分层验证就是把这个大问题拆成四个小问题每个小问题都有明确的判据。1.3 我这次搭建的验证环境硬件环境方面我用的是一块带SFP笼子的FPGA开发板主芯片是Xilinx Kintex-7系列光模块用的是850nm多模短距模块光纤跳线也是多模的。实验室里没有专门的ARINC818协议分析仪所以对端设备我用了一块同型号的FPGA板卡一边做发送端一边做接收端中间用光纤直连。这样接收端出问题的时候我可以确定对端发送的逻辑是我自己写的方便排查。如果只有一块板子也可以买一个环回光模块把TX直接环回给RX先自测链路层。但要注意环回光模块只能验证物理层和字同步验证不了对端协议发送的兼容性。我自己是先用环回光模块跑通物理层然后才接上对端板卡做协议级验证。还有一个小建议调试板上最好留一组拨码开关或者按键用来手工复位接收链路。第一次调GT的时候CDR失锁、字节失步这类问题很多有一个独立的手动复位手段会方便很多。2. 时钟和复位上板第一天最容易翻车的地方2.1 线速率、并行数据位宽与用户时钟ARINC818标准里面物理层沿用了Fibre Channel的编码方式数据在链路上是8B/10B编码传输。这意味着你做时钟规划的时候要始终记得一个换算关系链路实际有效数据速率等于线速率乘以0.8。以最常见的2.5Gbps线速率为例经过8B/10B编码之后有效净带宽是2.0Gbps。GTX/GTH收发器内部接收到串行数据后会按照并行数据位宽恢复出并行数据和用户时钟。比如20bit并行位宽用户时钟就是2.5GHz / 20 125MHz如果配成32bit位宽用户时钟就是78.125MHz。这个时钟是你后续解析逻辑的主时钟不是随便配的。我做这个项目时用的是20bit位宽、125MHz用户时钟。这个频率和常见的视频像素时钟148.5MHz不是整数倍关系所以OL数据从链路时钟域进入像素时钟域之前必须经过异步FIFO。这个FIFO的设计我会在后面OL映射部分详细讲这里先提一句异步FIFO的读写指针同步处理一定要做对否则图像会偶发地出现一整行错位而且不是每次开机都复现非常讨厌。2.2 复位信号里的坑异步复位同步释放只是一半GT收发器的复位远比普通逻辑复位复杂它涉及多个层次的初始化顺序PLL锁定、CDR锁定、RX字节对齐、RX通道绑定如果用了多通道、RX弹性缓冲。如果这些初始化没有完成就贸然让上层解析逻辑开始接收数据那收到的数据大概率是错位的。我遇到的一个典型问题就是复位顺序。一开始我把整个接收链路共用一个复位信号由复位IP产生上电后拉高几百微秒再释放。看起来没毛病但实际上GT的RX复位和逻辑复位是同时释放的而GT内部CDR锁定、字节对齐需要的时间比普通逻辑长得多。结果就是逻辑复位已经释放了GT还没准备好解析状态机已经把前几个时钟周期的无效数据当成有效数据存进去了导致帧头偏移、OL行号错乱。修法是把复位域拆开GT的RX复位单独控制等rxbyteisaligned信号拉高、rxresetdone拉高之后再延迟几十个周期释放上层逻辑复位。这个顺序在Xilinx的GT手册里有明确要求但真正写代码的时候很容易图省事就忽略掉我后来做了个模板专门处理这个时序。另外复位信号释放最好用异步复位同步释放的标准电路避免亚稳态。2.3 用户时钟使能信号还有一个细节GT输出的用户时钟是始终运行的但并行数据不是每个周期都有效。比如2.5Gbps线速率、20bit位宽、每个时钟周期恢复出20bit数据这20bit数据什么时候算有效要看RXVALID和RXNOTINTABLE这些信号。如果你是直接从RXDATA里抓数据而没有先了解GT输出时序很容易把填充字符当成有效数据解析。ARINC818在链路空闲时会发送IDLE有序集K28.5这类特殊字符。接收端的8B/10B解码器会把控制字符和普通数据区分开但如果你没有用K字符标志位只盯着数据总线就会把IDLE当成帧数据的一部分。所以解析逻辑里一定要保留GT输出的RXCHARISK信号用它来区分K字符和普通数据这是协议解析正确性的基础。3. 物理层测试光模块连接和误码率才是第一道门槛3.1 先用内部回环排除布线问题第一次拿到板子先别急着跑ARINC818协议先确认GTX/GTH通道本身是好的。我习惯先做内部近端回环测试也就是在FPGA内部把TX数据回环给RX不经过光模块和PCB高速走线这样可以把收发通道的数字逻辑先验证一遍。Xilinx的IBERT IP是干这个活的利器。它通过JTAG口和ChipScope配合可以在GT通道上跑PRBS伪随机序列接收端统计误码。我会先用IBERT把每个GT通道都跑一遍PRBS31模式连续跑至少半小时误码率必须为0才算通道基本没问题。如果IBERT都报错那就要检查原理图、时钟芯片配置、PCB焊接而不是急着调协议。近端回环通过之后再通过SFP光模块做远端环回测试也就是把一根光纤的TX和RX用环回光模块短接或者直接用光纤跳线连接两个光模块。此时信号经过光电转换和CDR恢复才能真正考验物理层。3.2 误码率判据多少误码才算合格ARINC818属于航电视频传输误码率要求不能含糊。我给自己定的标准是BER小于1e-12这基本是高速串行链路的行业惯例。怎么测用PRBS31模式如果链路速率是2.5Gbps跑24小时大概要传输2.16e14个比特按1e-12的BER标准允许的概率错误数是约216个。但实际工程中我要求24小时PRBS测试一个误码都不能有因为误码率本身会受温度、电源纹波影响留出余量才有安全感。如果24小时跑下来出现几十个误码先不要怀疑光模块大概率是电源纹波过大或者参考时钟抖动超标。可以换上低抖动时钟芯片对应的参考时钟源看看有没有改善。如果是多个通道同时误码优先排查GT参考时钟输入引脚是否有干扰。3.3 伪锁定现象灯亮着但数据全乱上板测试中最坑的一次是CDR锁定指示正常、RX同步状态机显示良好但接收到的数据全是乱码。当时现象特别迷惑GT的rxresetdone拉高了rxbyteisaligned也拉高了rxdisperr偶尔跳一下但没过多久又恢复。RXDATA里看起来有数据但完全对不上预期的K字符序列。我加了一个ILA核去抓RXDATA发现RX收到的内容是一个固定乱码序列的重复中间偶尔夹杂正确的同步字符。排查了好久才怀疑到复位时序上负责GT复位的逻辑里我在等待rxresetdone之后立刻释放逻辑复位但此时GT内部弹性缓冲可能还在调整阶段字节边界并没有稳定。释放复位后前几千个周期内解析器就锁定了一个错误的字节边界后续的K字符对齐判断自然就全错了。这个问题的根源就是对GT初始化完成信号的判断不完整。Xilinx的GT IP一般会给出rxbyteisaligned和rxcommadet但可靠的复位释放条件是rxresetdone置位并且rxbyteisaligned保持至少一个稳定的有效窗口。我当时直接用了rxresetdone没有等字节对齐稳定。后来改成在rxresetdone之后额外等待50个用户时钟周期再检查rxbyteisaligned为高才释放逻辑复位。问题消失。4. 协议解析层的长时间验证帧计数和CRC错误统计4.1 用硬件计数器把模糊的“帧对不对”变成具体数字物理层稳定之后终于可以开始跑ARINC818的帧协议了。这个阶段的目标是验证帧头提取、CRC校验、OL切分逻辑在真实数据下是否正确。但“正确”这个词太空泛必须把它量化成可统计的指标。我在接收逻辑里面加了三个计数器总帧计数、CRC错误帧计数、OL错误计数。总帧计数统计收到多少个SOF开头且EOF结尾的完整FC帧CRC错误帧计数统计CRC校验失败的帧OL错误计数统计OL解析异常的次数比如EOL和BCL顺序不对、OL长度超限等等。这三个计数器通过UART打印出来测试过程中随时观察。代码思路大概是这样的reg [31:0] frame_cnt; reg [31:0] crc_err_cnt; reg [31:0] ol_err_cnt; // 这里直接用解析IP输出的信号名实际工程以你的模块命名为准 wire rx_frame_start; // 检测到SOF wire rx_frame_end; // 检测到EOF wire rx_crc_fail; // CRC校验失败 wire rx_ol_err; // OL行切分异常 always (posedge rxusrclk) begin if (rx_reset) begin frame_cnt 32d0; crc_err_cnt 32d0; ol_err_cnt 32d0; end else begin if (rx_frame_end) frame_cnt frame_cnt 1b1; if (rx_crc_fail) crc_err_cnt crc_err_cnt 1b1; if (rx_ol_err) ol_err_cnt ol_err_cnt 1b1; end end注意CRC错误帧计数统计的是CRC失败次数如果一个帧中途CRC就开始错可能计数逻辑会连续上报多次。为了让结果更直观我还会在任一计数器非零时点亮一颗LED这样人不在仪器旁边也能知道测试是否出了问题。4.2 72小时跑测稳定性的唯一证据协议解析逻辑上板之后至少要做72小时的连续跑测。理由很简单偶发错误往往比持续错误更可怕。短时间测试看不到一旦系统跑几分钟出现一次CRC错误这种问题在仿真里是永远复现不出来的。我当时在跑测时遇到一个印象很深的现象头两个小时一切正常两个小时后CRC错误帧计数跳了1。只出现了1次然后就再也没有了。这个偶发错误把我折腾了很久。后来定位到原因是FPGA和光模块之间的电源纹波在板卡温度升高后发生变化导致链路上出现了微小抖动而接收端弹性缓冲在某些时候刚好压着极限最终导致一个时钟周期的采样错误反映到协议层就是一个CRC失败。这种问题的修法不一定是改逻辑有时候反而是改PCB布局或电源设计。但作为FPGA工程师你能做的是把错误检测做得足够细记录错误发生时的上下文状态。我后来在错误计数模块旁边加了一个小的状态快照寄存器检测到CRC错误时把当前帧号、OL行号、链路状态寄存器全部打下来这样排查起来就从“大海捞针”变成了“按图索骥”。4.3 OL行错位问题行号字段是最有效的调试线索FC帧层和CRC都通过之后下一层就是OL映像。ARINC818的视频数据是按OL组织的每个OL对应一条视频行OL头部有BCL/BSL这类控制字行尾有EOL。如果你只验证CRC通过就认为解析正确那就漏掉了最容易出错的地方OL切分边界。典型问题是接收端解析器把某个OL的起始位置算错了导致后续一系列行数据全部错位。这种情况CRC可能还是对的因为你OL的字段本身是完整的只是内容对应到视频行时候偏移了。我遇到过一次画面“阶梯状撕裂”每一行都相对上一行右移了一小段看起来像梯田。定位手段就是我在OL解析模块里加了一个行号检测在每一行像素数据里额外插入一个行计数器的值不是协议字段而是我自己加的调试信息。接收端回读数据时检查解析出的行号是否连续递增。一旦发现某一行行号跳变就能精确定位是哪个OL的头部解析出了问题。后来查下来是OL头部的控制字和上一行EOL之间有一个空闲间隔我的状态机在空闲间隔期间提前进入了下一个OL处理状态导致BCL被当成普通数据吞掉了。修法是增加一个“等待BCL确认”的状态收到BCL才能开始新OL的数据装载。5. 带宽预算与OL映射为什么1080p不能随便配颜色格式5.1 8B/10B编码后的有效带宽是硬约束很多第一次接触ARINC818的工程师会忽略带宽预算这件事以为只要光纤连上视频流往里灌就行。实际上链路有效带宽是硬约束算错了直接花屏。ARINC818物理层沿用Fibre Channel的8B/10B编码每传输10bit物理码元只携带8bit有效数据所以链路有效净带宽是线速率乘以0.8。链路线速率有效净带宽并行数据位宽典型用户时钟2.5Gbps2.0Gbps20bit125MHz3.1875Gbps2.55Gbps20bit159.375MHz5.0Gbps4.0Gbps20bit200MHz我做的很多系统里2.5Gbps链路用于720p、1080i这类分辨率足够但1080p60就需要特别注意了。5.2 计算真实视频带宽需求以1920x108060Hz为例我们来算一下不同像素格式的带宽需求。RGB888每像素24bit1920 x 1080 x 60 x 24 ≈ 2.99Gbps。这个数据量连3.1875Gbps线速率下的有效带宽2.55Gbps都超过更不用说2.5G链路。所以在ARINC818里直接用RGB888传1080p60是不现实的除非用压缩算法。YCbCr 4:2:2每像素16bit1920 x 1080 x 60 x 16 ≈ 1.99Gbps。这个数字接近2.0Gbps的有效带宽上限如果再加上OL控制字、帧头帧尾、帧间距这些协议开销2.5G线速率几乎被塞满测试中很容易出现偶发错误。因此实际工程里做1080p60时我宁可选3.1875G线速率留出约20%余量。YCbCr 4:2:2每像素20bit10bit量化1920 x 1080 x 60 x 20 ≈ 2.49Gbps这个也必须用3.1875G线速率才跑得动。表格长这样视频格式分辨率/帧率像素位深视频带宽需求2.5G链路是否够用3.1875G链路是否够用720p60 YCbCr4221280x7206016bit0.88Gbps够够1080i60 YCbCr4221920x108060i16bit1.00Gbps够够1080p60 YCbCr4221920x10806016bit1.99Gbps临界不建议够1080p60 RGB8881920x10806024bit2.99Gbps不够不够需压缩这个预算表要在项目方案阶段就做掉不要等到板子调完了才发现带宽不够。我自己见过有项目在2.5G链路上硬传1080p60 YCbCr422结果在画面高频细节较多的时候偶发花屏原因就是带宽余量不够OL传输时间超过了行消隐时间窗。5.3 行时序窗口为什么OL传输时间必须在Vsync周期内ARINC818的OL映像规则里一行视频数据被打包成一个OL在对应的视频行有效窗口内传输。以1080p60为例一行总周期大约是14.8us其中1920个活动像素占据约87%的时间。如果OL数据量太大在活动行窗口内传不完接收端要么截断要么溢出这比带宽不够更隐蔽。我自己做OL映射时的经验是在发送端把一行视频数据作为但个OL发送OL的字节长度固定为1920像素乘以每像素位数加上EOL控制字。接收端用一个行缓存FIFO接收整个OL再按像素时钟输出到显示侧。行缓存FIFO的深度要按最坏情况设计至少能容纳两行OL数据否则遇到EOL延迟或帧间距变化就会覆盖前一行数据。另外多流复用是ARINC818的一个重要特性一条光纤上可以承载多路视频流或其他数据流。这时带宽预算一定要给每一路流单独留出余量不要把所有带宽都分配给一个流。否则一旦某个流出现瞬时突发数据其他流就会感知到帧延迟抖动在显示端表现为画面卡顿或丢帧。6. 图像内容级验证像素对了协议才是真的对了6.1 用颜色条和灰度渐变图做初步判断协议层全部通过后图像内容验证就是把解析出的视频数据显示出来确认像素内容没有错位、没有偏色。第一轮验证我会在发送端生成几种测试图标准彩条Color Bar从左到右依次是白、黄、青、绿、品红、红、蓝、黑用来快速判断亮度和色度通道是否接反Y/Cb/Cr三个分量是否错位。灰度渐变图从黑到白线性分64级接收端如果看到明显的竖条纹或色带说明色深或位宽处理有问题。交叉线图和网格图用来检查像素是否发生了水平或垂直方向的偏移。这些测试图通过HDMI或者SDI输出到显示器上人眼就能看出大概方向。但人眼只能判断“有问题”很难判断“有多对”。6.2 回读比对把眼睛换成脚本更严格的做法是做数据回读自动比对。我在接收端把解析出的视频帧写入DDR然后通过调试接口把DDR里的数据回读到上位机和发送端产生的预期像素做逐字节对比。发送端测试图案是这样设计的像素值里本身包含行号和列号信息例如把行号的低8位放进R分量列号的低8位放进G分量。这样一旦像素错位回读数据的R/G分量会直接显示出当前像素实际对应的行列坐标。Python脚本做比对非常简单import numpy as np # 读取回读的原始图像数据按 YCbCr422 排列 raw np.fromfile(rx_frame.raw, dtypenp.uint8) yuv raw.reshape(1080, 1920, 2) # 每像素2字节模拟4:2:2 # 提取R通道模拟的“行号”和G通道模拟的“列号” # 这里以发送端生成的图案格式为准具体映射关系按你的实际设计改 row_id yuv[..., 0] 0xFF col_id yuv[..., 1] 0xFF # 预期行号第i行应该全部等于 i 0xFF expected_rows np.tile(np.arange(1080, dtypenp.uint8).reshape(-1, 1), (1, 1920)) row_errors np.where(row_id ! expected_rows) print(行号错误像素数量:, len(row_errors[0])) # 预期列号第j列应该全部等于 j 0xFF expected_cols np.tile(np.arange(1920, dtypenp.uint8).reshape(1, -1), (1080, 1)) col_errors np.where(col_id ! expected_cols) print(列号错误像素数量:, len(col_errors[0]))这套方案的威力在于别管画面看起来多诡异只要行号错误像素和列号错误像素都是0那至少像素级对齐是没问题的。如果行号错误像素集中在某一片区域脚本还能快速给出错误像素的坐标分布帮助定位是哪个OL切分阶段出了问题。6.3 一次画面“阶梯撕裂”的定位过程文章前面提到过的“阶梯状撕裂”问题我用回读比对很快就定位了。当时回读脚本报出行号错误像素从第512行开始出现错误行号全部是511持续32行后又恢复正常。这个规律性很强的错误让我瞬间把目光锁定在OL行号计数器的位宽上。查代码后发现OL解析模块里给DDR写地址的行号字段被错误地截断了原本应该用11bit行号但是我在拼接时用了行号低10bit传给写地址模块。结果是行号从0到1023循环而1080p分辨率实际上只需要1080个行号第1024行重新变成0第1025行变成1以此类推。在显示端这种错位会表现为每1024行出现一次阶梯跳变但因为测试图本身是渐变色肉眼很难发现规律回读比对却一目了然。修掉这个位宽截断之后行号错误像素数归零。这类问题在仿真阶段很难暴露因为仿真里行号循环根本不影响输出结果是否正确只有当你真正把图像数据存入DDR、再按行地址读出来时位宽截断才会显现。所以图像回读自动比对这一层验证绝对不是可有可无的额外工作。6.4 多分辨率、多帧率回归测试图像内容验证通过也不意味着大功告成。ARINC818系统在真实使用中可能会切换分辨率或帧率比如从1080p60切到720p60或者从30Hz切到60Hz。每一次切换链路层的帧结构、OL数量、像素时钟都会变化接收端的行缓存、DDR写地址映射、显示时序参数都跟着变。我习惯在验证阶段做一轮自动化的分辨率切换测试发送端每隔一段时间切一次测试图案参数接收端自动检测OL行宽和帧率变化重新配置后继续回读比对。实测中发现很多“只在切换后前3秒花屏”的问题基本都是接收端参数重配时序和像素时钟切换瞬间没有同步导致的。这类问题只能靠回归测试暴露没有别的捷径。做完了物理层、协议层、OL映像层和图像内容层的验证之后我个人现在接到ARINC818相关任务第一件事不是写解析逻辑而是先看三样东西时钟方案怎么规划、复位顺序怎么处理、带宽预算够不够。这三个底层问题一旦在设计阶段就定了正确方向上板联调的时间至少能少一半。尤其是复位顺序和异步FIFO这两个坑几乎每一个第一次做高速串行视频传输的人都会踩一遍我这次花了大篇幅写它们就是希望你调试的时候能少走一些弯路。
返回列表