E1--千兆以太网接口测试应用2022-09-07

网口数据收发应用总结

1.概述

基于不同网络设备实现不同应用的场景很多,TCP/IP协议架构十分庞杂,计算机网络知识也很丰富,关于更多的相对成体系的网络知识,敬请期待专栏作品《计算机网络》。本文将阐述FPGA与PC如何实现点对点通信,在“概述”小节讨论三个问题,第一,数据交互的双方都是FPGA(或PC)里面的谁(具体指哪一个协议)?通过解决这个问题,明白当前要建立的数据链路通道从哪里来到哪里去;第二,指明设备硬件的环境,例如,什么接口,什么芯片等,搞清每一个硬件部分发挥的作用,了解应用基于的硬件环境;第三,指明基于这样的数据链路和这样的硬件环境,要创建什么样的应用。

OSI网络模型有七层,但更为人熟知的是五层网络模型。如下图所示,上层的协议对于下层协议而言只是一个“数据段”。以FPGA到PC上行数据为例,FPGA将用户数据(应用层数据)打包,添加传输层协议信息形成传输层数据,依次类推网络层数据和链路层数据(这几个步骤都是要FPGA完成的)。通过物理层传输到PC设备上,PC上边的接收流程对开发者不可见,或者说使用QT中的Socket开发无需关注底层数据,直接在传输层获取应用层数据即可。如第二张图片所示,是一个TCP/IP协议簇的简要示意,下面关注在这个数据链路中到底要实现什么协议?在PC与FPGA连接的场景中,大多是通过网口下发设备运行所需数据,或者通过网口接收设备采集的数据,并不做网络应用,而是偏向于工业控制和数据采集,因此应用层通常是设备的数据,而不去实现某应用层协议。对于传输层通常是TCP和UDP两种,TCP使用单FPGA架构实现的案例很少,主要原因是协议复杂,硬件资源有限,即便实现可靠性和稳定性无法保证。可通过在FPGA内部搭建软核或者使用Soc实现TCP协议,但这种做法与其他的处理器相比不占优势,因此实际应用也不多见。在多数与PC相连用作数据采集的场景中,实现UDP协议能够传输数据即可。网络层将实现ip协议,这是因为UDP协议在ip数据包中打包。还要实现ARP协议,ARP可以根据已知的对端的ip地址广播(指对端mac地址设置为广播地址)ARP请求报文,网络中所有设备收到ARP请求,匹配IP的设备将返回ARP应答包,以此告知自己的MAC地址。实现ARP协议的好处是,PC给FPGA发送数据,需要知道FPGA板卡的MAC地址,FPGA也需要知道PC的MAC地址,实现ARP协议,当切换不同的PC与FPGA通信时,FPGA可识别不同主机的MAC地址(否则需要在命令提示符对话框中使用arp -s命令手动绑定)。在链路层将按照以太网数据帧格式将网络层数据打包即可。

E1--千兆以太网接口测试应用2022-09-07_第1张图片E1--千兆以太网接口测试应用2022-09-07_第2张图片

如下图所示,典型应用的连接是,PC机通过网线与FPGA板卡上的与phy芯片相连的RJ45接口相连,PHY芯片用来实现OSI模型物理层,主要功能是用来发送和接收以太网的数据帧,我使用的是realtek公司的RTL8211芯片,phy芯片与FPGA之间可以用多种接口相连,例如MII,GMII,RGMII,具体的接口要根据芯片的支持、系统设计综合考量来决定,三者之间逻辑上实现的差别不大,此处我用RGMII。可以清晰的看到,链路层网络层传输层数据的打包都要由FPGA实现,物理的传输通过PHY芯片实现,FPGA只需关注RGMII接口的时序即可,同时也要关注PHY芯片的配置。

E1--千兆以太网接口测试应用2022-09-07_第3张图片

本文将要创建的应用是上位机发送数据,下位机接收到数据之后按照指定端口返回。应用搭建的场景是,上位机发送数据,首先发起arp请求,随后下位机给出arp应答响应,上位机get到下位机的mac地址之后,将发送框中的数据打包成udp数据包下发到下位机中,下位机收到udp包,将有效数据保存到fifo中,然后在接收完毕之后,随即发起一次长度与接收长度一致的数据发送操作,在操作无误的情况下,上位机将收到下发的数据。

2.原理

2.1PHY芯片的配置

实现以太网PHY功能的芯片有很多,不同的芯片的数据接口,支持的特性,配置都略有不同,但相差不大。通常可以通过MDIO接口对PHY芯片内部的寄存器进行配置,MDIO 接口也称为 SMI 接口(Serial Management Interface,串行管理接口)。它是由一个时钟信号线和一根数据线组成,与IIC接口的时序相差不大。RTL8211这款芯片可以不做任何配置直接使用,因此对这款芯片的配置、寄存器的用法未做深入研究。通常PHY芯片都有两种工作模式,延时模式和正常模式。其区别如下:

RGMII接口发送端口,左边是正常模式,数据在TCK的中心位置对齐,TCK周期为8ns,即数据提前2ns;右边是延时模式,数据与TCK对齐。对于TX_CTL信号也是一样的。

E1--千兆以太网接口测试应用2022-09-07_第4张图片E1--千兆以太网接口测试应用2022-09-07_第5张图片

 RGMII接口接收端口,左边是正常模式随路时钟与数据边沿对齐,右边是延时模式,数据先于随路时钟2ns处在数据中心位置到来。由此可以看到,采用正常模式接收数据容易出现亚稳态现象。

E1--千兆以太网接口测试应用2022-09-07_第6张图片E1--千兆以太网接口测试应用2022-09-07_第7张图片

在芯片手册中,提到了设置发送和接收延时模式的发放,即将TXDLY和RXDLY端口做上拉处理。

 

 

而在我的硬件环境中,原理图如下,pin24 TXDLY和pin25 RXDLY均未做上拉处理,因此芯片工作在正常模式。结合上面的分析,处于正常模式的芯片应该在接收是添加idelay原语避免亚稳态出现,在发送模式时应该让发送的随路时钟与数据和数据有效信号之间有90°的时钟延迟。

 

2.2RGMII接口介绍

以太网的通信离不开物理层 PHY 芯片的支持,以太网 MAC 和 PHY 之间有一个接口,常用的接口有MII、RMII、GMII、RGMII 等。RGMII(Reduced Gigabit Medium Independent Interface)即吉比特介质独立接口,数据位宽为 4 位,在 1000Mbps 传输速率下,时钟频率为 125Mhz,在时钟的上下沿同时采样数据。在 100Mbps 和 10Mbps 通信速率下,为单个时钟沿采样。RGMII 接口的优势是同时适用于10M/100M/1000Mbps 通信速率,同时占用的引脚数较少。但 RGMII 接口也有其缺点,就是在 PCB 布线时需要尽可能对时钟、控制和数据线进行等长处理,且时序约束相对也更为严格。RGMII接口如下图所示,(关于RGMII接口的时序在2.1节所示的工作模式图中可直观看到)

E1--千兆以太网接口测试应用2022-09-07_第8张图片

  1. ETH_RXC:接收数据参考时钟,1000Mbps 速率下,时钟频率为 125MHz,时钟为上下沿同时采样;100Mbps 速率下,时钟频率为 25MHz;10Mbps 速率下,时钟频率为 2.5MHz,ETH_RXC 由 PHY 侧提供。由此可以看出数据是双沿DDR模式发送的。
  2. ETH_RXCTL(ETH_RX_DV):接收数据控制信号。
  3. ETH_RXD:四位并行的接收数据线。
  4. ETH_TXC:发送参考时钟,1000Mbps 速率下,时钟频率为 125MHz,时钟为上下沿同时采样;100Mbps速率下,时钟频率为 25MHz;10Mbps 速率下,时钟频率为 2.5MHz,ETH_TXC 由 MAC 侧提供。
  5. ETH_TXCTL(ETH_TXEN):发送数据控制信号。
  6. ETH_TXD:四位并行的发送数据线。
  7. ETH_RESET_N:芯片复位信号,低电平有效。
  8. ETH_MDC:数据管理时钟(Management Data Clock),该引脚对 ETH_MDIO 信号提供了一个同步的时钟。
  9. ETH_MDIO:数据输入/输出管理(Management Data Input/Output),该引脚提供了一个双向信号用于传递管理信息。ETH_MDC和ETH_MDIO信号共同组成了MDIO接口,用于配置PHY芯片的寄存器。通常芯片的默认配置可使芯片正常工作。

2.3ARP原理

地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。ARP 协议的基本功能是通过目的设备的 IP 地址,查询目的设备的 MAC 地址,以保证通信的顺利进行。MAC 地址在网络中表示网卡的 ID,每个网卡都需要并有且仅有一个 MAC 地址。在获取到目的 MAC 地址之后,将目的 MAC 地址更新至 ARP 缓存表中,称为 ARP 映射,下次通信时,可以直接从 ARP 缓存表中获取,而不用重新通过 ARP 获取 MAC 地址。但一般 ARP 缓存表会有过期时间,过期后需要重新通过 ARP协议进行获取。ARP 协议分为 ARP 请求和 ARP 应答,源主机发起查询目的 MAC 地址的报文称为 ARP 请求目的主机响应源主机并发送包含本地 MAC 地址的报文称为 ARP 应答。当主机需要找出这个网络中的另一个主机的物理地址时,它就可以发送一个 ARP 请求报文,这个报文包含了发送方的 MAC 地址和 IP 地址以及接收方的 IP 地址。因为发送方不知道接收方的物理地址,所以这个查询分组会在网络层中进行广播,即 ARP 请求时发送的接收方物理地址为广播地址,用48’hff_ff_ff_ff_ff_ff 表示。

关于ARP数据包的格式如下图所示,关于各字段的含义以及如何填充,网上资源丰富。图一为以太网帧格式,图二为ARP数据包格式,图三为具体的ARP字段。

E1--千兆以太网接口测试应用2022-09-07_第9张图片

E1--千兆以太网接口测试应用2022-09-07_第10张图片

E1--千兆以太网接口测试应用2022-09-07_第11张图片

关于后续涉及的ip包格式,udp数据包格式请自行查阅。关于ip与udp更为复杂的理论敬请期待后续专栏《计算机网络》。

2.4CRC校验代码

生成的代码(有生成工具)里面仅为一个计算 CRC32 的一个函数 function。CRC 的计算与除了与生成多项式相关外,还与 CRC 的初始值,输入输出数据是否位反向以及计算结果是否取反等操作相关。上面生成的 CRC 计算的 Verilog 代码仅仅是与多项式有关的计算过程,未涉及到初始值等因素,所以要实现符合以太网要求的CRC32 的完整计算需要添加一些计算操作。例如, 算法开始时,CRC 的初始化预置值(十六进制表示);待测数据的每个字节是否按位反转;在计算后之后,异或输出之前,整个数据是否按位反转;计算结果与此参数异或后得到最终的 CRC 值;等等,这些规则都应与以太网的校验规则一致才行。调整好的代码如下所示,这个代码输入8bit数据和数据同步信号,在一个周期后才能出现32bit的crc校验值。

module crc32_d8
(
  input           clk         ,
  input           reset_n     ,

  input    [7:0]  data        ,
  input           crc_init    ,
  input           crc_en      ,
  output   [31:0] crc_result
);
wire   [7:0]   data_i;
reg    [31:0]  crc_result_o;
assign data_i = {data[ 0],data[ 1],data[ 2],data[ 3], data[ 4],data[ 5],data[ 6],data[ 7]};
assign crc_result = ~{crc_result_o[00],crc_result_o[01],crc_result_o[02],crc_result_o[03],crc_result_o[04],crc_result_o[05],crc_result_o[06],crc_result_o[07],
                      crc_result_o[08],crc_result_o[09],crc_result_o[10],crc_result_o[11],crc_result_o[12],crc_result_o[13],crc_result_o[14],crc_result_o[15],
                      crc_result_o[16],crc_result_o[17],crc_result_o[18],crc_result_o[19],crc_result_o[20],crc_result_o[21],crc_result_o[22],crc_result_o[23],
                      crc_result_o[24],crc_result_o[25],crc_result_o[26],crc_result_o[27],crc_result_o[28],crc_result_o[29],crc_result_o[30],crc_result_o[31]};
always @(posedge clk or negedge reset_n)
begin
  if(!reset_n)
    crc_result_o <= 32'hffff_ffff;
  else if(crc_init)
    crc_result_o <= 32'hffff_ffff;
  else if(crc_en)
    crc_result_o <= nextCRC32_D8( data_i, crc_result_o);
  else
    crc_result_o <= crc_result_o;
end
  // polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  // data width: 8
  // convention: the first serial bit is D[7]
  function [31:0] nextCRC32_D8;
    input [7:0] Data;
    input [31:0] crc;
    reg [7:0] d;
    reg [31:0] c;
    reg [31:0] newcrc;
  begin
    d = Data;
    c = crc;
    newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30];
    newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31];
    newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31];
    newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31];
    newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30];
    newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
    newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
    newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31];
    newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
    newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29];
    newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29];
    newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
    newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30];
    newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31];
    newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31];
    newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31];
    newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29];
    newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30];
    newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31];
    newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31];
    newcrc[20] = d[4] ^ c[12] ^ c[28];
    newcrc[21] = d[5] ^ c[13] ^ c[29];
    newcrc[22] = d[0] ^ c[14] ^ c[24];
    newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30];
    newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31];
    newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27];
    newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30];
    newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31];
    newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30];
    newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31];
    newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31];
    newcrc[31] = d[5] ^ c[23] ^ c[29];
    nextCRC32_D8 = newcrc;
  end
  endfunction
endmodule

2.5ip校验和的计算

UDP的字段中含有UDP校验和,但在大多数使用场景中接收端并不检测 UDP 校验和,因此这里不做过多介绍。16 位ip首部校验和(Header Checksum),该字段只校验ip数据报的首部,不包含数据部分,校验 IP 数据报头部是否被破坏、篡改和丢失等。其计算步骤如下:①将 16 位检验和字段置为 0,然后将 IP 首部按照 16 位分成多个单元;②对各个单元采用反码加法运算(即高位溢出位会加到低位,通常的补码运算是直接丢掉溢出的高位);③此时仍然可能出现进位的情况,将得到的和再次分成高 16 位和低 16 位进行累加;④最后将得到的和的反码填入校验和字段。注意,这种校验方法称为16bit累加和校验算法,在自定义协议实现的时候常常用到,可以对照代码理解记忆应用。

3.工程验证思路

3.1单独创建ARP应答工程

创建一个ARP应答工程,当PC发出ARP请求的时候,手动按下板卡指定按键,将会响应ARP应答。以此验证phy芯片的配置正常,硬件链路正常,也验证了CRC32bit 校验代码。判断和验证步骤如下。

1.打开本地“网络和Internet设置”,选择“更改适配器选项”,右键以太网选择“属性”,双击“Internet协议版本4”,配置ip地址为192.168.1.102。关于以太网组网,设备应该在同一个网段中,通常是192.168.x.x或者10.0.x.x。此处配置为192.168.1.102指在FPGA记录了PC机的IP地址为192.168.1.102,另外,任何与此FPGA板卡网口的主机应该配置为该ip地址。

E1--千兆以太网接口测试应用2022-09-07_第12张图片

E1--千兆以太网接口测试应用2022-09-07_第13张图片

2.命令提示符输入 ipconfig /all查看主机MAC地址

E1--千兆以太网接口测试应用2022-09-07_第14张图片

3.连接设备,并且上电,烧入FPGA程序。使用ping命令或者通过上位机向FPGA板卡发送数据,因为本地ARP映射表中没有对应ip地址的mac地址,因此都会下发ARP请求报文。实践中通过在命令提示符中ping 192.168.1.10,即可产生PC到FPGA的ARP报文,与此同时观察已打开的wireshark可抓取到请求包,与此同时按下指定板卡按键,则可收到ARP应答报文如步骤4所示。 

E1--千兆以太网接口测试应用2022-09-07_第15张图片

Ping命令使用的网络层的ICMP协议,因为该工程并没有实现这个协议,所以他ping不同是正常现象,此处用它是为了让PC发出ARP请求。

4.打开wireshark(提前打开),选择与板卡相连的以太网卡。

E1--千兆以太网接口测试应用2022-09-07_第16张图片

在与步骤3同步的时刻,即使用ping后,接着按下板卡按键(不同的板子可以自己指定)观察到ARP请求和应答报文如下。

(下图为ARP请求包wireshark抓包状态)

E1--千兆以太网接口测试应用2022-09-07_第17张图片

(下图为ARP请求包wireshark请求包与fpga接收时序图对比)

E1--千兆以太网接口测试应用2022-09-07_第18张图片

(下图为ARP应答包wireshark应答包与fpga发送时序图对比)

E1--千兆以太网接口测试应用2022-09-07_第19张图片

 

5.使用arp -a查看ARP映射表,已更新IP与MAC的映射,说明ARP应答实现成功,说明硬件电路正确。(使用管理员方式运行)

E1--千兆以太网接口测试应用2022-09-07_第20张图片

3.2UDP接收验证

基于3.1成功获取ARP应答之后(3.1节的工程主要基于某FPGA开发板厂商代码修改以验证当前硬件环境正常),创建UDP工程(里面含ARP的实现,该工程的ARP实现验证过程与3.1节一致,在第5节附上下载链接),其代码搭建的思路按照第四节,此处先介绍使用这个代码该如何一步步验证。

首先要关注上位机到下位机的UDP数据是否发送成功,下图以此展示了上位机的发送状态,上位机单击发送之后wireshark的抓包状态,以及抓到的UDP下行包的具体内容与上位机发送的数据一致。然后使用ILA抓取到的接收到的数据与上位机的发送数据一致,证明接收链路与接收逻辑都正确。

E1--千兆以太网接口测试应用2022-09-07_第21张图片

上位机发送

E1--千兆以太网接口测试应用2022-09-07_第22张图片

UDP下行包wireshark

E1--千兆以太网接口测试应用2022-09-07_第23张图片

Wireshark显示UDP下行包内容

FPGA接收下行数据 

3.3UDP发送验证

此处用到的工程与3.2节为同一个工程。首先,通过ILA抓取到FPGA发送出来的数据,数据帧格式各字段都正确。然后看到wireshark找到UDP上行数据,显示上行数据内容与FPGA发送数据一致,最后在网口调试助手中看到,接收数据与FPGA发送数据一致,也与上位机下发数据一致。

FPGA上行数据时序 

​​​​​​​E1--千兆以太网接口测试应用2022-09-07_第24张图片

UDP上行包状态

E1--千兆以太网接口测试应用2022-09-07_第25张图片

         UDP上行包内容

E1--千兆以太网接口测试应用2022-09-07_第26张图片

上位机接收数据

4.UDP工程搭建思路解读与注意事项

从前面的描述可以看到,不论经过什么硬件回路,不论是什么样的协议实现,对于FPGA逻辑的开发,本质上是实现与PHY芯片的读写操作。对于ARP协议,接收ARP请求,发送ARP应答;对于UDP协议,接收UDP数据包,发送UDP数据包。因此将所有的逻辑整合到一起,为后续在此基础上开发应用打好基础。将读写操作分离,整个逻辑分为三个子模块,一个是pll模块,为其他模块生成用户时钟;一个是writeOnly模块,负责向PHY芯片写数据;另一个是readOnly模块,负责读取PHY芯片的数据。架构简单使用,如下图所示。

E1--千兆以太网接口测试应用2022-09-07_第27张图片

 Readonly模块负责接收UDP数据包和ARP请求报文,其他的报文一概忽略。将eth_rd_clk源同步接口的随路时钟接入BUFG全局网络,在模块内,使用该时钟作为用户时钟。rd_ctrl信号经过idelay固定延时15*78ps=1170ps,这是因为RTL8211芯片没有采用延时模式(见2.1节),实际测试中采用这个延时数据接收稳定。对数据信号rd_data做同样的处理。Rd_ctrl经IDELAYE2输出ctrl_delay信号,该信号进入IDDR原语模块,输出SDR信号iddr_ctrl[1:0],由iddr_ctrl[1]&iddr_ctrl[0]生成数据有效信号eth_sdr_valid。对于数据信号rd_data,也是先经过IDELAYE2调整数据窗口,然后经过IDDR变成SDR信号eth_sdr_data。获取到数据同步信号eth_sdr_valid和有效数据eth_sdr_data之后,按照前导码、定界符等一系列帧格式,解析出ARP请求报文跳入ARP处理段(sequence_cnt22-50),根据ARP请求报文的ip地址和mac地址作为Writeonly模块的对端地址;同时生成arp_req_done信号,指示WriteOnly模块发起一次ARP响应。当收到UDP报文转到UDP处理段(sequence_cnt71-100),并将解析到的应用层数据保存到fifo中,输出有效字节个数信号rec_byte_num,输出rec_pkt_done信号指示WriteOnly信号发起一次UDP包传输。

Readonly模块负责发送UDP数据包和ARP应答报文。当收到ARP应答指示时,按照接收的ip地址和mac地址打包ARP应答数据,并在最后添加FCS校验字段,将生成的SDR的数据同步信号port_end和数据信号port_data_d分别进入ODDR生成DDR信号发送到RGMII接口上。收到UDP发送指示的时候,则按照UDP数据包格式打包,与ARP处某些固定字段不同之外,多了一个IP首部校验和字段(见2.6节),还涉及发送字节有效个数的问题,当不足18字节时,要补全。另外,校验模块输入有效信号和有效数据延迟一个周期才能出现校验值,为了将这个校验数据准确的打包到UDP数据包中还是做了一点处理,需要注意。写数据的用户时钟直接由pll提供,千兆模式RGMII对应125MHz,RGMII接口上的时钟也是由pll提供,与用户时钟同频率,不同的是相位有90°的偏差(由于未采用延时模式)。

关于代码中用到的原语的具体的配置将在系列文章的原语部分做介绍,本文不在做解释。如下图所示,为接收到小于18Bytes数据时,采用dummy数据填充至18字节产生的正确的效果。

E1--千兆以太网接口测试应用2022-09-07_第28张图片

 当自己构建逻辑代码时,应该注意以下几点,①芯片延时模式未设置带来的时钟与数据的相位关系不同,在我的硬件环境中明确了发送数据为pll出来的125MHz作为用户时钟,125MHz偏差90°的相位时钟作为源同步时钟。②FCS采用CRC校验算法,是发送过程中很重要的一环,一旦出错,上位机将丢弃这个数据。③RGMII时序简单,但也应该稍微注意,例如在校验字段若数据有效信号拉低,则会导致校验数据无法正确发送,以至于上位机无法收到数据包。④关于ip首部校验,是在被校验的数据还没有填充完毕的时候就填出,因此需要单独的逻辑进行ip首部的16bit累加和校验。⑤现在的回环程序是在一帧之内的数据完成的,如果要是多帧连续发送,应该注意,两针之间千兆网的速度应该是有960ns 的间隔的。⑥接收数据因为时钟与数据的对应关系不对齐,因此需要添加idelay原语进行延迟,使数据对齐,目前程序中使用了200MHz的参考时钟,使用了15个抽头指,15*78ns的延迟,当数据不对齐的时候,明显的错误是把a4变成了f4等,大部分数据对,小部分数据异常的情况。⑦注意ODDR的ddr-sdr转换为i与i+4。

5.工程链接与思考

1.网口上位机开发

关于上位机的开发非常简单,需要三个动作。①第一个动作是根据协议和ip地址以及当前的端口获取该端口的监控权。②通过检测readready信号,当数据来临的时候,通过readDatagram获取网口的数据到QByteArray。③通过writeDatagram函数向指定的ip和端口发送数据。与自己开发的上位机的联调结果如下,

E1--千兆以太网接口测试应用2022-09-07_第29张图片

2.工程工具链接如下:

网口调试工具wireshark

网口调试助手netassist

手动ARP应答工程

UDP工程链接

3.思考:

①在实际应用场景中,多是大量数据的发送,如何对该模块进行调用值得思考,这种场景可以是采集视频数据上行,或者发送图片数据下行,可以尝试构建如采集摄像头数据进入SDRAM,再通过网口回传到上位机显示的应用。或者通过以太网下发图片到DDR,然后在显示到TFT上。

②xilinx官方提供了一个用于实现以太网应用的ip核叫做TEMAC,Tri Mode Ethernet MAC,可以尝试通过这个IP实现数据收发功能。

③数据收发模块从逻辑上将可以有多种实现方式,综合考虑时序优化,资源节约的情况下可以做不同的尝试。

④如果工程复杂,可以考虑实现FPGA可以主动的发起ARP请求,在现有程序的基础上,做到这一点并不复杂。

你可能感兴趣的:(FPGA积累——基础篇,fpga开发,千兆网,eth)