2284|0

22

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【国产FPGA 正点原子DFPGL22G开发板】二、千兆以太网测评【程序设计篇】 [复制链接]

  本帖最后由 yyliu 于 2023-1-15 11:29 编辑

声明:针对本帖中可能出现的侵权行为,请及时联系本人修改或删除。未经本人允许,请勿转载。若本帖存在错误或不足之处,烦请指正,本人会及时修改。


 

0.说明


1.程序设计篇主要介绍千兆以太网通信的程序框图和代码实现,介绍了FPGA开发板与主机之间网速测试的方法。

2.本帖所做的实验为正点原子提供的案例:以太网UDP实验。任务是上位机通过网口调试助手发送数据给FPGA,FPGA通过以太网接口接收数据并将接收到的数据发送给上位机,完成以太网UDP数据的环回。

3.建议学习正点原子《ATK-DFPGL22G之FPGA开发指南_V1.1》的第49~51章后,再阅读本帖的关键代码分析。

 

1.千兆以太网UDP通信原理


 

首先了解下以太网通信的基本过程,以生活中常见的场景为例,当你使用电脑WEB网页访问网络资源,你的电脑相当于主机A,为你提供数据的远端服务器相当于主机B,你们之间通信的数据流如下图所示:

 应用层:假设你网络请求走的是HTTP协议,那么你的主机将在应用层发出:HTTP数据;

传输层:TCP相对于UDP协议更加可靠,假设传输层采用的是TCP协议,则传输层的数据变为:TCP首部+HTTP数据;

网络层:网络层一般采用IP协议,但是为了获取所访问对象的MAC地址,还有固定采用ARP协议,则网络层传输的数据变为:IP首部+TCP首部+HTTP数据;

数据链路层:数据链路层四个子层为媒体访问控制层(MAC)、无线链路控制层(RLC)、分组数据汇聚协议层(PDCP)和服务数据自适应协议层(SDAP);可以简单认为,数据链路层传输的数据变为:前导码+SFD+以太网帧头+IP首部+TCP首部+HTTP数据+FCS;

 

与上图相比,该实验的用户数据并不是通过应用层的各种协议实现的,而是直接在FPGA代码中产生所需数据。下图是UDP实验以太网数据包格式:

用户数据打包在UDP协议中,UDP协议又是基于IP协议之上的,IP协议又是走MAC层发送的,即从包含关系来说:MAC帧中的数据段为IP数据报,IP报文中的数据段为UDP报文,UDP报文中的数据段为用户希望传输的数据内容。

 

IP协议、UDP协议、ARP协议在《ATK-DFPGL22G之FPGA开发指南_V1.1》中有详细介绍,学习了解这些协议是理解本实验程序的前提,重点需要了解各协议的数据格式,占用字节数和各类型数据的顺序。本帖将三种协议的数据格式截取下来,相关内容请学习正点原子提供的文档。

IP数据格式见下图:

UDP数据格式见下图:

ARP数据格式见下图:

 

2.关键代码分析


下图是UDP通信的系统框图。

 

2.1 GMII TO RGMII 模块:GMII TO RGMII 模块负责将双沿(DDR)数据和单沿(SDR)数据之间的转换。

我们为什么要设计GMII TO RGMII 模块呢?而不是将RGMII接口的数据直接与ARP顶层模块和UDP顶层模块相连?首先,RGMII采用的是双边延采样,我们需要解析RGMII接收到的数据,因此采用GMII TO RGMII 模块去将双边沿数据解析出来,用统单一周期的时钟去表示1bit的数据,与其他模块的时钟更容易同步。其次,RGMII接口的数据直接与ARP顶层模块和UDP顶层模块相连也是可以的,只要处理好RGMI需要发送和接收的数据即可。

 

GMII和RGMII区别:在GMII接口中,它是用8根数据线来传送数据的,这样在传送1000M数据时,时钟就会125MHz。虽然RGMII接口中,信号线减半,同时GTX_CLK和RX_CLK还是125MHz,为了达到1000Mbit的传输速率,TXD和RXD信号线上在时钟的上升沿发送GMII接口中的TXD[3:0]/RXD[3:0],在时钟的下降沿发送GMII接口中TXD[7:4]/RXD[7:4],并且信号TX_CTL反映了TX_EN和TX_ER的状态,即在GTX_CLK上升沿发送TX_EN,下降沿发送TX_ER。同样的道理适用于信号RX_CTL,它反映了RX_EN和RX_ER的状态,即在RX_CLK上升沿发送RX_EN,下降沿发送RX_ER。

 

该模板例化了rgmii_rx和rgmii_tx两个模块,rgmii_rx用于将GMII数据转换为RGMII数据发送出去,rgmii_rx用于将RGMII接收的数据转化为GMII的单边沿数据。本帖只对rgmii_rx进行分析,rgmii_tx和rgmii_rx是类似的。下述代码是rgmii_rx的端口声明。

module rgmii_rx(
    //以太网RGMII接口
    input              rgmii_rxc      , //RGMII接收时钟
    input              rgmii_rx_ctl   , //RGMII接收数据控制信号
    input       [3:0]  rgmii_rxd      , //RGMII接收数据    

    //以太网GMII接口
    output             gmii_rx_clk    , //GMII接收时钟
    output  reg        gmii_rx_dv     , //GMII接收数据有效信号
    output  reg [7:0]  gmii_rxd       , //GMII接收数据 
    output             gmii_tx_clk_deg,
    output             pll_lock
    );

rgmii_rx模块的rgmii用于接收上位机发送过来的数据,在上升下降沿进行采样,gmii用于将双边沿数据转化为单边沿数据,送到ARP或者UDP模块。

 

该模块的核心是使用了PDS原语GTP_ISERDES;不同于RTL级设计可以通过综合变成门级电路,原语也就是门级语言,可以直接自定义数字电路以达到对指定电路的设计。

wire [5:0] nc1;
GTP_ISERDES #(
    .ISERDES_MODE    ("IDDR"),  //"IDDR","IMDDR","IGDES4","IMDES4","IGDES7","IGDES8","IMDES8"
    .GRS_EN          ("TRUE"),  //"TRUE"; "FALSE"
    .LRS_EN          ("TRUE")   //"TRUE"; "FALSE"
) igddr1(         
    .DI              (rgmii_rxd[0]),
    .ICLK            (1'd0        ),
    .DESCLK          (gmii_rx_clk ),
    .RCLK            (gmii_rx_clk ),
    .WADDR           (3'd0        ),
    .RADDR           (3'd0        ),
    .RST             (1'b0        ),
    .DO              ({gmii_rxd_s[4],gmii_rxd_s[0],nc1})
);

其中,IDDR工作模式的时序图如下:

 当配置成IDDR模式时,DO[5:0]是无效数据,因此赋值给nc1;DO[7:6]是有效数据,因此将RGMII的四根数据线的其中一根的上升下降沿数据赋值给GMII的两个bit;也就是rgmii_rxd[0]在上升沿的数据赋值给gmii_rxd_s[0],在下降沿的数据赋值给gmii_rxd_s[4]。不理解的可以看下RGMII接收端的接口时序图,就容易理解了。

 

 

2.2 ARP模块:知道目标主机的IP后,本地主机是不知道目标主机的MAC地址,这样就无法完成以太网数据的发送和请求。ARP模块的目的是为了自动获取目标主机的MAC地址。整个以太网帧格式与ARP协议的实现由ARP顶层模块完成;ARP控制模块负责检测输入的触摸按键是否被按下,控制ARP顶层模块发起请求与产生应答等操作。

ARP模块的接口见代码:GMII收到数据以后,会将数据传送给ARP模块;ARP模块根据对方的数据请求类型,决定是否需要返回自己的MAC地址。因此ARP模块也分为发送模块arp_tx和接收模块arp_rx。

module arp(
    input                rst_n      , //复位信号,低电平有效
    //GMII接口
    input                gmii_rx_clk, //GMII接收数据时钟
    input                gmii_rx_dv , //GMII输入数据有效信号
    input        [7:0]   gmii_rxd   , //GMII输入数据
    input                gmii_tx_clk, //GMII发送数据时钟
    output               gmii_tx_en , //GMII输出数据有效信号
    output       [7:0]   gmii_txd   , //GMII输出数据          

    //用户接口
    output               arp_rx_done, //ARP接收完成信号
    output               arp_rx_type, //ARP接收类型 0:请求  1:应答
    output       [47:0]  src_mac    , //接收到目的MAC地址
    output       [31:0]  src_ip     , //接收到目的IP地址    
    input                arp_tx_en  , //ARP发送使能信号
    input                arp_tx_type, //ARP发送类型 0:请求  1:应答
    input        [47:0]  des_mac    , //发送的目标MAC地址
    input        [31:0]  des_ip     , //发送的目标IP地址
    output               tx_done      //以太网发送完成信号    
    );

理解ARP发送模块和接收模块的代码,需要根据ARP协议规范的格式,明白先发什么数据,后发什么数据,总体来说难度不大,但是需要花一些时间去理解代码状态机的跳转。本帖不再介绍。

 

ARP模块还包括了CRC校验模块crc32_d8。

//输入待校验8位数据,需要先将高低位互换
wire    [7:0]  data_t;

assign data_t = {data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]};

//CRC32的生成多项式为:G(x)= 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

assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];
assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31] 
                     ^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];
assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30] 
                     ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6] 
                     ^ data_t[7];
assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31] 
                     ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];
......

CRC码是由两部分组成的,前部分是信息字段,就是需要校验的信息,后部分是校验字段,如果CRC码共长n个bit,信息字段长k个bit,就称为(n,k)码。因此crc32_d8相当于n=32,k=8。

它的编码规则是:

  1. 首先将信息字段值(k bit)左移r位(k+r=n)
  2. 运用一个生成多项式g(x) (也可看成二进制数) 模2除上面的式子,得到的余数就是校验字段值。
  3. 生成的CRC码值为:信息字段值+校验字段值(单位:位bit,次序:高位到低位),例如字段值为1001,校验字段值为110,则CRC码为1001110

关于CRC校验的原理,可以参考博客园的帖子:https://www.cnblogs.com/masonzhang/p/10261855.html;写的比较清晰。

 

3.3 UDP模块:UDP顶层模块实现了以太网UDP数据包的接收、发送以及CRC校验的功能。

UDP模块和ARP模块类似,包括发送模块、接收模块和CRC校验模块。需根据UDP通信协议去理解状态机的跳转,分析用户数据是如何被解析出来的。

 

3.Modelsim仿真


本实验仿真的原理是开发板的udp的环回,既将udp的发送数据直接发送给udp的接收数据。由于FPGA开发板的发送和接收的MAC地址都是相同的,因此不需要调用ARP模块去获取目的主机的MAC地址。

下述代码可以看出时钟周期为8ns,等价于RGMII和GMII的125MHz时钟频率。

//parameter  define
parameter  T = 8;                       //时钟周期为8ns
parameter  OP_CYCLE = 100;              //操作周期(发送周期间隔)

//开发板MAC地址 00-11-22-33-44-55
parameter  BOARD_MAC = 48'h00_11_22_33_44_55;     
//开发板IP地址 192.168.1.10     
parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192168.1.10
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd10};

下述是例化UDP模块的代码:

  1. tx_data是需要发送的数据,testbench定初始化该数据为32'h_00_11_22_33;

  2. gmii_rxd是环回的接收数据,

大家在做Modelsim仿真时,可以着重注意发送和接收的数据。

//例化UDP模块
udp                                             
   #(
    .BOARD_MAC     (BOARD_MAC),      //参数例化
    .BOARD_IP      (BOARD_IP ),
    .DES_MAC       (DES_MAC  ),
    .DES_IP        (DES_IP   )
    )
   u_udp(
    .rst_n         (sys_rst_n   ),  
    
    .gmii_rx_clk   (gmii_rx_clk ),           
    .gmii_rx_dv    (gmii_rx_dv  ),         
    .gmii_rxd      (gmii_rxd    ),                   
    .gmii_tx_clk   (gmii_tx_clk ), 
    .gmii_tx_en    (gmii_tx_en),         
    .gmii_txd      (gmii_txd),  

    .rec_pkt_done  (),    
    .rec_en        (),     
    .rec_data      (),         
    .rec_byte_num  (),      
    .tx_start_en   (tx_start_en),        
    .tx_data       (tx_data    ),         
    .tx_byte_num   (tx_byte_num),  
    .des_mac       (des_mac    ),
    .des_ip        (des_ip     ),    
    .tx_done       (tx_done    ),        
    .tx_req        (tx_req)           
    ); 

配置好Modelsim和PDS联合仿真后,执行下图操作,查看仿真代码:

 大家可以看到该实验发送的数据如下:

 接收的数据如下:

另外,根据时钟周期和波形图,大家可以对着波形图、MAC层协议,分析数据传输过程是否和状态机跳转过程一致。

 

4.实物仿真和网速测试


实物仿真包括两个部分,一是正点原子教程上的上位机网络调试助手与FPGA通信实验;大家可以自行参考手册;

另一部分是正点原子没提到的,如何进行网速测试,使用抓包工具wireshark测试FPGA通信时以太网的速率。

 

我们可以通过抓包工具wireshark测量以太网部分的数据发送的速度,因为千兆以太网理想模式网络的速度可以达到1Gbps,但实际因为每个数据包中有包头,CRC等非数据字符,而且每包之间有空隙,一般千兆以太网的数据传输速度最高在950Mbps左右。传输是上下对称传输,就是说上行和下行都能达到950Mbps左右。在这里,因为抓包wireshark只能统计接收的数据包,而不会发送数据,所以只是测试FPGA发给电脑的输送数据的速度。

 

使用抓包工具wireshark 测试PGA通信时以太网的速率,需要重新编写testbench文件,由于本人电脑无法使用网线和开发板相连,因此编写testbench文件和网速测试的工作留个尾巴。如果大家有需求,后续有时间可以将这块内容补上。网速测试相关细节可参考资料:https://www.cnblogs.com/alinx/p/14605179.html。

 

5.提出建议


正点原子的UDP通信实验例程下载完成后,红框所示的黄色指示灯一直是亮的。在没插网线时,黄色灯长灭比较合理

这个黄色等表示的是ACT灯,一般在没插网线是不会亮的。一般网络指示灯包括LINK灯和ACT灯,常用规范如下:

  1. 连接指示灯(绿色)。
    连接指示灯亮就代表线路连接正常。
  2. 信号指示灯(黄色)。
    在连接指示灯亮的情况下,信号指示灯的含义如下:
    a) 如果信号指示灯闪烁,代表信号正常,正在通信;
    b) 如果信号指示灯灭,代表没有通信;
    c) 如果信号指示灯长亮,代表网线短路。

 

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表