ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于FPGA的AFDX高速数据采集器:VL过滤、时间戳与调试实战

基于FPGA的AFDX高速数据采集器:VL过滤、时间戳与调试实战

简介:面向AFDX网络高速数据采集需求,这份PDF资料给出基于FPGA的采集器完整设计方案,适用于航空电子、试飞测试领域的工程师与FPGA开发者。方案围绕ARINC664P7协议,系统阐述完整性检查、余度管理、虚拟链路、带宽隔离与流量整形等关键技术,并覆盖MAC控制、PCI接口、挑参控制等核心模块的软硬件实现思路,对理解AFDX数据采集设备国产化设计有直接参考价值。资源共1个文件,格式为PDF,压缩包大小477KB,内容精炼,适合快速查阅。目前已有349人学习下载。文档还包含基于Cyclone Ⅴ系列FPGA与PHY芯片的硬件选型、数据帧完整性检查和余度管理流程、上层驱动与应用软件架构,以及64B、512B、1518B典型报文下的实测验证结果,可帮助读者掌握从协议分析、模块设计到测试验证的完整技术路径。

1. 为什么AFDX高速数据采集绕不开FPGA:抓包、时间戳和带宽的硬约束

基于FPGA的AFDX网络高速数据采集器,是我调试航电总线这几年最值得投入的一块板子。AFDX链路标称100Mbps,看起来不高,但采集点往往要同时面对几十条虚拟链路、双冗余A/B双网和纳秒级时间戳需求,通用CPU抓包方案在持续大流量下必然丢帧,更扛不住按虚拟链路做并发过滤统计。FPGA在这里的核心价值是线速收、逐帧标时间、并发查过滤表,业内做端系统测试与总线监控的主流方案几乎都是FPGA。这篇文章就把协议拆解、模块实现、参数核算到调试避坑一次讲透,适合正在做或者打算做AFDX采集器的开发者。

2. 从AFDX帧结构到采集器架构:VL、BAG与冗余网怎么拆解

AFDX本质上仍然是带冲突避免机制的全双工以太网,协议栈分层的思路和普通TCP/IP网络没有本质区别,但它为航电确定性引入了三个FPGA必须处理的概念:虚拟链路VL、带宽分配间隔BAG、双冗余网络A/B网。采集器不是端系统,不需要参与发送调度,但接收路径上必须搞清楚帧里哪些字段决定VL身份、哪些字段用于冗余管理和丢包检测,否则后面写Verilog逻辑就是在猜。

AFDX链路速率是100BASE-TX/FX,物理层和普通百兆以太网一样。所谓“高速”是相对于传统1553B而言的,采集器真正困难的不是单条链路的线速,而是多个VL汇聚后的持续写入压力,以及时间戳精度。端系统内部有发送调度表,采集器没有,所以采集器必须被动接收,不能往总线里注入任何数据。这决定了系统架构第一原则:两路物理收发独立,采集器只接RX,处理链路尽量单一方向,从PHY收进来的数据不能回头影响总线。

2.1 采集器必须认识的AFDX帧字段:VL识别位、SN与最大帧长

要写AFDX帧解析,先拿到帧的准确偏移位置。AFDX帧在MAC层仍然是标准的以太网帧,关键差异在于目的MAC地址的低24位携带VL ID,以及UDP负载的第一字节是序列号SN。这一点很容易被第一次做的人忽略,我见过有人拿着UDP目的端口去过滤VL,结果抓到的数据对不上端系统配置,因为VL身份既可能在MAC地址里,也可能在UDP端口里,取决于端系统实现,但规范里目的MAC低24位是最常用的编码位置。

字段偏移(字节)长度说明
MAC目的地址06低24位为VL ID,典型高字节0x03
MAC源地址66端系统唯一源MAC
EtherType122IPv4为0x0800
IP头1420协议字段为0x11表示UDP
UDP头348目的端口常对应采集通道
SN序列号4210~255循环,A/B双网相同
应用数据43可变长度由Lmax决定

SN是冗余管理和丢包检测的核心。发送端在A/B两路发送同一帧、同一个SN,接收端先到先得;采集器监听时,应该在A、B两路各自记录SN与时间戳,之后由上位机决定是按双网合并还是按单网统计。Lmax是每个VL允许的最大帧长,规范里按VL配置,常见1518字节、2048字节、4096字节几个档位,FPGA里的解析状态机必须按“变长帧 + 最大长度上限”设计,不能写死一个长度。

BAG则是发送侧调度参数,单位是毫秒,取值是2的幂次,常见1/2/4/8/16/32/64/128ms。每个VL在每BAG周期内最多发一帧,所以一个VL的链路占用率上限等于帧长除以BAG。采集器不需要调度发送,但必须用BAG做接收侧违规统计,这要求FPGA为每个活跃VL维护“上一帧到达时刻”,当前帧到达时间间隔低于BAG减去容差,就计一次BAG违规。这个统计在调试端系统调度表时非常有用,也是采集器区别于普通以太网抓包工具的核心能力。

2.2 整机模块划分:从RGMII到上位机的六级链路

常见的AFDX采集器设计是把整条数据通路拆成六级:物理层PHY、MAC接收、AFDX协议解析、过滤统计、异步FIFO、上行接口。物理层用百兆PHY芯片,通常走RGMII接口进FPGA;A/B两路各自独立,FPGA内做两套相同的接收逻辑,到统计与上报阶段再合并。上行接口按应用场景选USB3.0、PCIe或千兆以太网,如果只是离线记录,UART做低速监控也够,但持续高速采集场景下至少需要千兆以太网上报。

PHY-A -> RGMII -> IDDR转8bit -> 以太网帧对齐 -> AFDX解析 -> 过滤统计 -> 异步FIFO -> 上行接口 -> 上位机 PHY-B -> RGMII -> IDDR转8bit -> 以太网帧对齐 -> AFDX解析 -> 过滤统计 -> 异步FIFO -/

AFDX解析模块内部要完成几个动作:检查EtherType是否为IPv4、IP协议是否为UDP;截取MAC目的地址低24位作为VL身份;提取SN字段;把当前自由运行计数器的值作为时间戳与VL ID、SN拼成一条元数据。这里有一个容易忽略的设计决策:时间戳计数器必须放在接收时钟域,并且不要在跨时钟域时单独同步计数器值。正确做法是把“时间戳 + VL ID + SN + 帧长度”整体打包成一条记录,随帧数据一起写入异步FIFO,读侧拿到什么就是什么,永远不要试图在另一个时钟域采样自由运行的计数器。

过滤统计模块建议按VL表项数做参数化。端系统规模小的时候几十个VL,顺序比较就够;如果采集器要接交换机汇聚口,VL可能上千,顺序比较组合逻辑太大会撑不住时序,这时要换成哈希查表,公共做法是用CRC把24位VL ID折叠成10到12位索引,再查BRAM里的表项。哈希碰撞用多级表或链式桶解决,深度不必太深,实际命中率可以做到很高。

3. 用SystemVerilog实现AFDX帧识别、时间戳与SN连续检测

这一章直接给核心模块的实现思路,代码以SystemVerilog示例给出,可以按自己的FPGA型号移植。设计目标很简单:每帧解析延迟控制在几个时钟周期内,时间戳精度为10ns,VL过滤单周期完成,SN跳变和BAG违规作为统计计数值上报。整个数据通路不收发控制信号,完全被动,保证不影响AFDX网络本身。

3.1 VL过滤表:以目的MAC低24位为索引的单周期查表

VL过滤是所有统计和过滤动作的前提。帧头进解析模块后,先截取目的MAC低24位,与配置的VL表做匹配。小规模场景下直接用寄存器阵列顺序比较,参数化成表项个数,综合工具会展开成组合比较器;VL数量超过128之后建议改成哈希索引,不然路径延迟会明显变差。

// afdx_vl_filter.sv // 功能:按目的MAC低24位匹配VL表,输出命中信号 // 参数:VL_TABLE_DEPTH 表项数,按端系统规模设置,通常64~128 module afdx_vl_filter #( parameter VL_TABLE_DEPTH = 128 )( input logic clk, input logic rst_n, input logic [47:0] mac_da, // 帧目的MAC,来自帧对齐模块 input logic hdr_valid, // 帧头字段已锁存,拉高1拍 output logic vl_hit, // 命中输出,与hdr_valid对齐 output logic [23:0] vl_id, // 命中的VL ID input logic [7:0] cfg_addr, // 上位机配置写地址 input logic [23:0] cfg_wdata, // 上位机配置写数据 input logic cfg_wen // 配置写使能 ); logic [23:0] vl_table [VL_TABLE_DEPTH]; logic [23:0] da_id; logic hit_comb; assign da_id = mac_da[23:0]; // AFDX中VL ID编码在目的MAC低24位 // 配置写入:VL表内容由上位机下发,AXI-Lite从口映射 always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin for (int i = 0; i < VL_TABLE_DEPTH; i++) vl_table[i] <= '0; end else if (cfg_wen) begin vl_table[cfg_addr] <= cfg_wdata; // 写入一个新的VL ID end end // 顺序比较:适合VL数<=128,组合路径短 always_comb begin hit_comb = 1'b0; for (int i = 0; i < VL_TABLE_DEPTH; i++) begin if (vl_table[i] == da_id) begin hit_comb = 1'b1; break; end end end // 输出打一拍,保持与hdr_valid对齐,避免竞争 always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) vl_hit <= 1'b0; else begin vl_hit <= hdr_valid & hit_comb; vl_id <= da_id; end end endmodule

逻辑说明:组合比较的结果在hdr_valid拉高时想直接输出,但为了不给后端时序制造麻烦,输出做了打拍对齐。实际使用时,下游模块以vl_hit为写使能,把vl_id和同一拍锁存的SN、时间戳一起写入FIFO。如果VL表项超过128,把中间的for循环换成哈希模块,输入da_id,输出BRAM索引和命中位,其余逻辑不动。

参数说明:VL_TABLE_DEPTH要按采集点实际会出现的VL最大个数设置,端系统单点监听用64足够,交换机汇聚口建议直接按1024设计并用哈希方案。cfg_wdata位宽取了24位,如果后续还要存BAG和Lmax配置,把表项扩展成48位或64位,cfg_wdata跟着扩展。顺序比较的综合结果是一个大的OR树,时钟频率不高于125MHz时一般没事;超过150MHz就要重新考虑。

3.2 时间戳快照:纳秒计数与帧头对齐的写时序

AFDX规范本身不携带全局时间戳,采集器的时间基准只能靠本地自由运行计数器。常见做法是用50MHz或100MHz时钟驱动一个64位计数器,100MHz下每时钟步进10ns,64位可以连续跑几十年不回绕,对调试场景绝对够用。关键不是计数器本身,而是采样时机:必须在帧头字段有效的那一拍把计数器值锁存,并且和VL ID、SN一起打包。

// afdx_ts.sv // 功能:64位纳秒级自由运行计数器,提供全局时间基准 // 参数:CLK_PERIOD_NS 对应接收时钟周期,100MHz时为10 module afdx_ts #( parameter logic [63:0] CLK_PERIOD_NS = 64'd10 )( input logic clk, input logic rst_n, output logic [63:0] ts_value ); logic [63:0] ts_cnt; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) ts_cnt <= '0; else ts_cnt <= ts_cnt + CLK_PERIOD_NS; // 每时钟步进一个周期对应的纳秒数 end assign ts_value = ts_cnt; endmodule

采样逻辑写在解析模块里,当hdr_valid有效时,把ts_value锁存到元数据寄存器。代码只做这两件事:计数器自由跑,需要时刻快照。真正要小心的是,ts_counter不能异步复位后立刻使用,要等几个时钟周期稳定,所以工程上会给rst_n加同步释放,这个在避坑章节再展开。

参数说明:CLK_PERIOD_NS必须与接收时钟实际频率一致,如果接收侧是125MHz就改成64'd8。计数器位宽64位建议不要缩减,否则长时间跑机会出现时间戳回绕,上位机处理起来很麻烦。A/B两路如果各用各的计数器,两路时间基准会漂,正确做法是只例化一个计数器,把ts_value广播给两路解析模块,保证同一根总线上的事件时间可比较。

3.3 SN跳变检测与BAG违规统计:两个容易被忽略的指标

SN跳变检测的逻辑其实只有一小段:对每个VL维护一个last_sn,帧到达时比较当前SN与last_sn,不等就计一次差值,更新last_sn。由于AFDX帧可以乱序到达吗?AFDX是确定性网络,同一VL的帧在物理链路上不会乱序,所以差值大于1基本可以判定丢帧或发送端异常。BAG违规统计则需要时间戳配合,逻辑上是同一个VL“当前帧时间戳 - 上一帧时间戳”与BAG参数比大小。

// afdx_sn_monitor.sv // 功能:对每个VL检测SN连续性和BAG违规 // 设计:BRAM保存每个VL的last_sn和last_ts,解析模块逐帧查询更新 module afdx_sn_monitor #( parameter VL_NUM = 128 )( input logic clk, input logic rst_n, input logic vl_hit, // VL过滤命中脉冲,1拍有效 input logic [23:0] vl_id, // 当前帧VL ID input logic [7:0] sn_field, // 当前帧SN,来自第43字节 input logic [63:0] ts_field, // 当前帧时间戳 output logic sn_jump, // SN跳变标志,脉冲 output logic bag_violate, // BAG违规标志,脉冲 output logic [31:0] jump_cnt, // 跳变累计计数 output logic [31:0] bag_cnt // BAG违规累计计数 ); logic [7:0] last_sn_table [VL_NUM]; logic [63:0] last_ts_table [VL_NUM]; logic [15:0] idx; assign idx = vl_id[15:0]; // 按VL ID低16位做索引,VL不足65536够用 always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin sn_jump <= 1'b0; bag_violate <= 1'b0; jump_cnt <= '0; bag_cnt <= '0; end else if (vl_hit) begin // SN连续检测:当前SN - last_sn,跳变则计数 if ($unsigned(last_sn_table[idx] - sn_field) != 1) begin sn_jump <= 1'b1; jump_cnt <= jump_cnt + 1; end else sn_jump <= 1'b0; // BAG违规粗判:帧间隔小于BAG且差值超过阈值 if ($unsigned(ts_field - last_ts_table[idx]) < bag_threshold) begin bag_violate <= 1'b1; bag_cnt <= bag_cnt + 1; end else bag_violate <= 1'b0; // 更新表项 last_sn_table[idx] <= sn_field; last_ts_table[idx] <= ts_field; end else begin sn_jump <= 1'b0; bag_violate <= 1'b0; end end endmodule

这段代码里bag_threshold是配置寄存器,单位是纳秒,由上位机按每个VL的BAG参数算好后写入。注意BAG违规的判定要留容差,A/B双网场景下先到先得的帧到达间隔可能刚好卡在BAG边界,容差给一个时钟周期数量级即可,不然正常帧会被误判成违规。SN跳变计数和BAG违规计数都做成32位,长时间跑机时可以通过计数是否持续增长判断链路健康状态。

逻辑说明:这个模块本质是“按VL ID寻址的查表更新”,BRAM端口读改写冲突在FPGA里很常见。上述代码用同步读BRAM,读出的旧值在当前时钟沿更新,下一拍才能读出新值。如果一个VL的帧间隔恰好只有一拍,那后一帧会在旧表项上比较,这在AFDX里不会发生,因为BAG最小是1ms,而接收时钟是纳秒级,中间隔着上万拍,不存在背靠背更新同一个VL表项的问题。

4. 参数设计与带宽核算:BAG、FIFO深度与时钟约束怎么定

采集器的参数设计直接决定能不能持续不丢帧。这一章给三个关键参数的计算方法:VL表与BAG映射、FIFO深度与背压阈值、RGMII时钟约束。这三个参数在综合前就要算明白,等板子回来在调试器里改就晚了。

4.1 VL表与BAG参数:按2的幂配置采样窗口和容差

每个VL在系统里都用一条配置记录表示,至少包含四项:VL ID、使能位、BAG值、Lmax值。上位机下发这些配置时,BAG和Lmax要换算成采集器内部能直接比较的格式,BAG换算成纳秒,Lmax换算成字节数。带宽估算则用帧开销模型,AFDX物理帧除了Lmax数据外还包含前导码、帧开始符和帧间隙,规范里公共做法是每帧加20字节额外开销再乘8转成比特。

VL号BAG(ms)Lmax(字节)每帧总开销(字节)单VL理论带宽(kbps)
VL1815181538约1.5
VL24512532约1.1
VL31640964116约2.1

单VL带宽计算公式是:(Lmax + 20) × 8 / (BAG × 0.001) / 1000,单位取kbps。三个例子算出来都不高,但一个采集口如果挂了几十个VL,汇聚带宽就可能到几十Mbps,再加上非AFDX管理帧和广播帧,链路实际利用率可以到70%以上。计算采样窗口时同样用BAG做依据:统计模块里配置寄存器存的是“BAG对应纳秒数”,比如8ms就是8_000_000ns,容差默认加2个时钟周期。

4.2 FIFO深度与背压设计:按VL汇聚带宽算突发

FIFO深度不能靠拍脑袋。先算最坏情况:同一BAG窗口内,所有使能VL的帧恰好都在同一时刻到达,这在实际总线上不太会发生,但背压设计必须按这个上界留余量。公式是FIFO最小深度(字节)= Σ(每个VL的Lmax) + 最大单帧长度,这是“一个窗口内全部VL各来一帧”的理论峰值。

更实际的做法是把读侧带宽也考虑进来。假设上行接口是千兆以太网,读侧带宽1000Mbps,写侧是AFDX百兆链路,平均看读远大于写,但瞬时突发时写侧可能连续写入几帧,读侧一次只能读一个接口位宽。所以FIFO深度按“写侧瞬时突发量 + 读侧响应延迟 × 读带宽”计算。举个实例:假设20个VL,Lmax都取1518,一个窗口内全到达,突发量约30KB;千兆读侧响应延迟若为10us,读侧在这段时间只能读约10us × 1000Mbps / 8 ≈ 1250字节;FIFO取32KB就足够。

深度确定后必须设置水线而非全满才丢。常见做法是当FIFO占用超过水线时,按VL优先级丢弃后续到达的低优先级帧,同时计丢弃计数上报。全满再丢会造成写侧反压,反压一旦传递到解析模块,后续帧的接收时序全部打乱,时间戳也不再准确。

4.3 时钟约束与复位:RGMII源同步采样和异步FIFO

RGMII是源同步接口,时钟由PHY提供,数据在时钟的双沿变化,所以FPGA里必须先做IDDR把双沿数据转成单沿8bit,再做跨时钟域处理。综合工具里要给RGMII输入时钟和输入数据分别加约束:输入延迟通常按PHY数据手册的tclk-to-data范围设置,没有约束文件时工具默认路径是理想情况,板子上一跑就会出现偶发错帧。

复位策略上,A/B两路解析模块各自用自己的接收时钟域复位,异步FIFO读侧用系统侧复位;全局异步复位直接驱动所有触发器,会有严重的恢复/移除时间违例,工程上统一用“异步复位同步释放”模板,并且每个时钟域单独生成一份复位信号。时间戳计数器上电后不能立即作为有效时间基准,要等计数器稳定和FIFO清空完成后再使能报文上报,这一步可以做成状态机:上电→清FIFO→等100us→置valid。

5. 板级调试常见的4类问题排查:从抓不到帧到时间戳跳变

这一章是我实际调试采集板时踩得最深的几个坑,都按“现象→原因→解决”写成排查笔记。这些坑的共同特点是:波形仿真全对,一到板子上就翻车,十有八九是时序约束、跨时钟域或字段取值的问题,而不是逻辑功能本身错。

5.1 抓不到帧:RGMII时序约束没给够,ILA看到全0

现象:逻辑分析仪ILA以接收时钟作为触发时钟,触发条件设为rx_valid上升沿,但一直显示waiting;把触发条件去掉改为无条件采样,看到数据总线全是0。这时软件工程师会怀疑是帧格式不对,但问题往往在物理层。

原因:RGMII的时钟和数据是源同步关系,如果综合约束没有声明输入延迟,工具按理想时钟布线,IDDR采样位置落在数据跳变沿附近,采出来的数据随机且大部分是0。另一个常见原因是PHY的复位时序和时钟就绪信号没处理,PHY还没完成配置,RGMII时钟根本没起来。

解决:先在综合约束里给RGMII输入时钟和输入数据加上set_input_delay,数值参考PHY数据手册的tclk-to-data典型值;再加一条伪路径约束,避免工具把PHY到IDDR的路径按跨时钟域处理。板级验证先让PHY工作在环回模式,发送端从FPGA灌测试码流,如果环回能收到,再断开环回接入AFDX总线。检查PHY配置时用ILA抓MDIO接口,确认寄存器读回值符合预期。

5.2 时间戳跳变:跨时钟域打拍不到位的玄学

现象:上位机解析出的相邻两帧时间戳差值偶尔出现异常,比如突然差了几万纳秒,过一会又恢复;统计时间长,异常点没有规律。最早我以为是PHY链路问题,换过时钟源也没解决。

原因:时间戳计数器在接收时钟域自由运行,上位机读侧是另一个时钟域。如果直接把64位计数器总线跨时钟域打拍,多位信号同时变化时采样会抓到中间态组合,读出的值既不是旧值也不是新值,表现出来就是时间戳偶尔跳变。这是教科书上都写过但实际最容易犯的问题。

解决:不要跨时钟域读计数器。把时间戳连同VL ID、SN、帧长度打包成一条元数据,和帧数据一起写入异步FIFO;FIFO读侧读出来的元数据本身已经位于读时钟域,不存在多位同步问题。A/B两路共用同一个计数器、各自打包,两路之间不直接比较计数器总线。改完之后时间戳异常点彻底消失,这条经验后来我用在好几个采集项目里。

5.3 VL漏检翻车:VL ID掩码取错导致一半链路失效

现象:配置了全部VL表项,但上位机只能看到大约一半VL的帧;反复核对配置数据没有语法错误,过滤逻辑仿真也正确。A同学帮我查了很久,最后抓原始帧头才发现问题出在掩码取值上。

原因:AFDX目的MAC的低24位是VL ID,但实际抓到的帧里,高字节是0x03,低三字节是VL ID。代码里有一处寄存器赋值把mac_da[23:0]写成了mac_da[31:8],相当于把MAC地址的第4到第2字节当成VL ID,高位地址段为0的VL全部被截错,表现为部分VL永远查不到。仿真里用的激励MAC地址恰好低16位非0,掩盖了这个问题。

解决:在解析模块里单独定义da_id = mac_da[23:0],所有VL查表、SN检测统一使用这个信号;在testbench里随机生成多个VL ID,覆盖高字节为0x03、VL ID低位为0的边界情况。另外建议在帧元数据里保留完整的MAC目的地址,上位机可以按原始MAC地址交叉验证VL ID解析结果。

5.4 高负载丢帧:不是FIFO不够深,是背压策略不合理

现象:长时间跑机测试时,丢帧计数持续增长,把FIFO深度从32KB加到64KB后,丢帧数只是减少了一些,没有完全消失。继续加大深度,改善越来越不明显,说明不是容量问题。

原因:写侧瞬时汇聚速率在高负载窗口超过读侧带宽,FIFO即使未满,读侧背压信号已经拉高,解析模块还在写入,水位持续上涨直到全满丢弃。加大深度只是把“到达全满”的时间点往后推迟,负载波形是持续突发型时,推到最后还是会丢。根因是没有按优先级做选择性丢弃,高优先级帧和低优先级帧一起被挤掉。

解决:把“全满丢弃”改成“水线+优先级丢弃”。FIFO水位超过水线后,解析模块根据VL优先级过滤,低优先级帧直接不写入并计丢弃计数,高优先级帧正常写入。水线值设为FIFO深度的70%到80%,这样读侧总有机会把水位压下去。实测同样的负载模型,丢帧计数降到了可用范围,高优先级链路零丢帧。

6. 验证采集器的三个实用技巧:从仿真激励到长时间跑机

验证AFDX采集器,不能只靠逻辑仿真,因为帧到达的时序分布、跨时钟域行为和PHY物理特性在仿真里都过于理想。我一般按三层验证走:首先用SystemVerilog testbench生成带随机VL ID和SN的AFDX帧序列,验证解析和过滤模块的功能;然后在板级用PHY环回做通路自检;最后做72小时长时间跑机,重点看统计计数和时间戳单调性。

testbench里生成AFDX帧序列的核心是一个task,它按参数拼出MAC头、IP/UDP头、SN字段和有效载荷。要注意随机覆盖VL ID边界值,包括VL ID低24位全0和全1的场景,尤其是很多采集器的过滤逻辑会在边界上出错。

// tb_afdx_pkt_gen.sv 测试平台片段 // 功能:生成指定VL ID和SN的AFDX帧,驱动RGMII接口 task automatic gen_afdx_frame( input logic [23:0] vld_id, input logic [7:0] sn, input logic [15:0] payload_len ); logic [7:0] pkt[]; int idx; pkt = new[payload_len + 43]; // MAC目的地址:高字节0x03,低24位为VL ID pkt[0] = 8'h03; pkt[1] = vld_id[23:16]; pkt[2] = vld_id[15:8]; pkt[3] = vld_id[7:0]; // 后续字段按IP/UDP顺序填充,SN放pkt[42] pkt[42] = sn; // 通过任务驱动RGMII总线... endtask

仿真通过后,板级验证把PHY配成环回模式,FPGA侧发送一段自定义码流,接收侧统计帧数、CRC错误计数和SN跳变计数,三者在长时间下都应为0。然后接入真实AFDX总线,先只开一个VL,确认计数正确后再逐步增加VL数量,同时观察时间戳差值的分布;差值应该集中在BAG附近,如果出现半规整的跳变,优先级检查跨时钟域处理和FIFO接口时序。

长时间跑机最值得盯的三个指标分别是丢弃计数、BAG违规计数和时间戳单调性。我自己的习惯是让采集器连续跑满72小时,每15分钟记录一次统计快照,对比各时段计数是否随时间线性增长;时间戳则写成文件做单调性校验,一旦发现回绕或倒序,基本可以判定时间戳采样或FIFO读时序还有问题。温度变化对百兆PHY影响不大,但对FPGA内部时序裕量有影响,条件允许的话在最大环境温度下再补跑24小时。

做AFDX采集器这几年,最大的教训就是“仿真过不等于板子过,短时跑过不等于长时跑过”。所有看似玄学的偶发问题,最后都能追到时序约束、跨时钟域打拍或参数边界这三件事上。希望这篇笔记能帮你少走一圈弯路,把精力放在真正值得投入的统计分析和交付质量上。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进