基于FPGA的UDP实现(包含源工程文件)

您所在的位置:网站首页 udp协议的主要功能是 基于FPGA的UDP实现(包含源工程文件)

基于FPGA的UDP实现(包含源工程文件)

2024-04-18 13:46| 来源: 网络整理| 查看: 265

1、概括

前文通过FPGA实现了ARP和ICMP协议,ARP协议一般用来获取目的IP地址主机的MAC地址,ICMP通过回显请求和回显应答来判断以太网链路是否通畅,这两个协议都不是用来传输用户数据的。如果用户需要向PC端传输大量数据,那么就必须使用TCP或者UDP协议了。

网上关于UDP和TCP的优缺点对比其实很多,可以自行搜索,本文简要概括一下优缺点。

TCP优点是稳定,接收端接收到TCP数据报文后会回复发送端,如果接收的报文有误,发送端会把错误的报文重新发送一遍。而且TCP本来就有握手机制,所以数据的传输会更可靠。正是由于握手机制,导致实现的TCP协议的逻辑比较复杂,传输速度也不会很高,还需要更多存储资源取存储已经发送的数据,直到收到该数据传输无误后才能丢弃。因此FPGA一般不会采用该协议进行大量数据的传输(当然如果通过Verilog HDL实现可靠的TCP协议,那还是很有用的,毕竟这块的代码很贵)。

UDP优点是协议简单,没有握手机制,传输数据的速度就很快,这对于FPGA传输图像数据之类的设计比较实用。由于UDP没有握手机制,可靠性相比TCP就会低很多,有得必有失嘛。

因此,FPGA一般通过UDP协议向PC端发送大量数据,所以本文通过FPGA实现UDP协议。

2、UDP协议讲解

UDP协议的框图如下所示,与前文的ICMP协议构成类似,UDP协议数据报文位于IP的数据段,IP首部只有协议类型与ICMP协议类型参数不一致,ICMP的IP协议类型编号为1,UDP的IP协议类型编号为17。

图1 UDP协议框图

前导码、帧起始符、以太网帧头、IP首部、FCS校验在前文讲解ARP协议和ICMP协议的时候都详细讲解过,所以本文就不再赘述了。

UDP的首部组成如下所示,包括源UDP源端口地址、UDP目的端口地址、UDP长度、UDP校验码。

图2 UDP首部组成

源端口号:2个字节的发送端端口号,用于区分不同的发送端口。

目的端口号:2个字节的接收端端口号。

UDP长度:UDP首部和数据段的长度,单位字节,对于接收方来说该长度其实作用不大,因为UDP数据段的长度可以通过IP首部的总长度和IP首部长度计算出来。

UDP校验和:计算方式与IP首部校验和一致,需要对UDP伪首部、UDP首部、UDP数据进行校验。伪首部包括源IP地址、目的IP地址、协议类型、UDP长度。

这种校验方式其实对于FPGA来说很麻烦,因为校验码需要在数据之前发送,而计算校验码有需要得到数据,就意味着如果想要计算校验码,就必须使用存储资源把待发送的数据存起来,计算出校验码以后,才开始传输数据。比较友好的是该校验码可以直接置零处理(如果不做校验,该值必须为0,否则校验失败的数据报文会被直接丢弃)。不校验数据的UDP协议变得特别简单。

UDP协议的数据组成如下所示:

图3 以太网UDP协议帧组成

以太网的协议组成就介绍这么多了,最后注意在发送数据时,数据段必须大于等于18字节,少于18字节数据时,应补零凑齐18字节数据发送。

3、UDP顶层模块

UDP的设计与前文的ARP、ICMP模块设计差不多,UDP顶层模块如下图所示,包括UDP接收模块udp_rx、UDP接收的CRC校验模块、UDP的发送模块udp_tx、UDP发送的CRC校验模块。

UDP接收模块内部没有做IP首部校验,只做了CRC校验模块,在加上FPGA逻辑判断,基本上都能判断对错了,最后把接收的数据和数据个数输出。发送模块检测到开始发送信号后,开始发送信号,当发送到数据段之后,把数据请求信号拉高,从外部输入需要发送的数据流。

图4 UDP顶层模块

UDP顶层模块的参考代码如下所示:

//例化udP接收模块; udp_rx #( .BOARD_MAC ( BOARD_MAC ),//开发板MAC地址 00-11-22-33-44-55; .BOARD_IP ( BOARD_IP ) //开发板IP地址 192.168.1.10; ) u_udp_rx ( .clk ( gmii_rx_clk ),//时钟信号; .rst_n ( rst_n ),//复位信号,低电平有效; .gmii_rx_dv ( gmii_rx_dv ),//GMII输入数据有效信号; .gmii_rxd ( gmii_rxd ),//GMII输入数据; .crc_out ( rx_crc_out ),//CRC校验模块输出的数据; .rx_done ( udp_rx_done ),//UDP接收完成信号,高电平有效; .rx_data_vld ( rx_data_vld ),//以太网接收到有效数据指示信号; .rx_data ( rx_data ),//以太网接收数据。 .data_byte_num ( udp_rx_byte_num ),//以太网接收的有效数据字节数 单位:byte .des_port ( ),//UDP接收的目的端口号; .source_port ( ),//UDP接收到的源端口号; .crc_data ( rx_crc_data ),//需要CRC模块校验的数据; .crc_en ( rx_crc_en ),//CRC开始校验使能; .crc_clr ( rx_crc_clr ) //CRC数据复位信号; ); //例化接收数据时需要的CRC校验模块; crc32_d8 u_crc32_d8_rx ( .clk ( gmii_rx_clk ),//时钟信号; .rst_n ( rst_n ),//复位信号,低电平有效; .data ( rx_crc_data ),//需要CRC模块校验的数据; .crc_en ( rx_crc_en ),//CRC开始校验使能; .crc_clr ( rx_crc_clr ),//CRC数据复位信号; .crc_out ( rx_crc_out ) //CRC校验模块输出的数据; ); //例化UDP发送模块; udp_tx #( .BOARD_MAC ( BOARD_MAC ),//开发板MAC地址 00-11-22-33-44-55; .BOARD_IP ( BOARD_IP ),//开发板IP地址 192.168.1.10; .DES_MAC ( DES_MAC ),//目的MAC地址 ff_ff_ff_ff_ff_ff; .DES_IP ( DES_IP ),//目的IP地址 192.168.1.102; .BOARD_PORT ( BOARD_PORT ),//板子的UDP端口号; .DES_PORT ( DES_PORT ),//源端口号; .ETH_TYPE ( ETH_TYPE ) //以太网帧类型,16'h0806表示ARP协议,16'h0800表示IP协议; ) u_udp_tx ( .clk ( gmii_tx_clk ),//时钟信号; .rst_n ( rst_n ),//复位信号,低电平有效; .udp_tx_start ( udp_tx_start ),//UDP发送使能信号; .tx_byte_num ( udp_tx_byte_num ),//UDP数据段需要发送的数据。 .des_mac ( des_mac ),//发送的目标MAC地址; .des_ip ( des_ip ),//发送的目标IP地址; .crc_out ( tx_crc_out ),//CRC校验数据; .crc_en ( tx_crc_en ),//CRC开始校验使能; .crc_clr ( tx_crc_clr ),//CRC数据复位信号; .crc_data ( tx_crc_data ),//输出给CRC校验模块进行计算的数据; .tx_data_req ( tx_data_req ),//需要发送数据请求信号; .tx_data ( tx_data ),//需要发送的数据; .gmii_tx_en ( gmii_tx_en ),//GMII输出数据有效信号; .gmii_txd ( gmii_txd ),//GMII输出数据; .rdy ( udp_tx_rdy ) //模块忙闲指示信号,高电平表示该模块处于空闲状态; ); //例化发送数据时需要的CRC校验模块; crc32_d8 u_crc32_d8_tx ( .clk ( gmii_tx_clk ),//时钟信号; .rst_n ( rst_n ),//复位信号,低电平有效; .data ( tx_crc_data ),//需要CRC模块校验的数据; .crc_en ( tx_crc_en ),//CRC开始校验使能; .crc_clr ( tx_crc_clr ),//CRC数据复位信号; .crc_out ( tx_crc_out ) //CRC校验模块输出的数据; );

对应的TestBench文件如下所示:

`timescale 1 ns/1 ns module test(); localparam CYCLE = 8 ;//系统时钟周期,单位ns,默认8ns; localparam RST_TIME = 10 ;//系统复位持续时间,默认10个系统时钟周期; localparam STOP_TIME = 1000 ;//仿真运行时间,复位完成后运行1000个系统时钟后停止; localparam BOARD_MAC = 48'h00_11_22_33_44_55 ; localparam BOARD_IP = {8'd192,8'd168,8'd1,8'd10} ; localparam BOARD_PORT = 16'd1234 ;//开发板的UDP端口号; localparam DES_PORT = 16'd5678 ;//UDP目的端口号; localparam DES_MAC = 48'h23_45_67_89_0a_bc ; localparam DES_IP = {8'd192,8'd168,8'd1,8'd23} ; localparam ETH_TYPE = 16'h0800 ;//以太网帧类型 IP reg clk ;//系统时钟,默认100MHz; reg rst_n ;//系统复位,默认低电平有效; reg [7 : 0] tx_data ; reg udp_tx_start ; reg [15 : 0] udp_tx_byte_num ; wire [7 : 0] gmii_rxd ; wire gmii_rx_dv ; wire gmii_tx_en ; wire [7 : 0] gmii_txd ; wire udp_rx_done ; wire [15 : 0] udp_rx_byte_num ; wire udp_tx_rdy ; wire tx_data_req ; wire rx_data_vld ; wire [7 : 0] rx_data ; assign gmii_rx_dv = gmii_tx_en; assign gmii_rxd = gmii_txd; udp #( .BOARD_MAC ( BOARD_MAC ), .BOARD_IP ( BOARD_IP ), .DES_MAC ( DES_MAC ), .DES_IP ( DES_IP ), .BOARD_PORT ( BOARD_PORT),//板子的UDP端口号; .DES_PORT ( DES_PORT ),//源端口号; .ETH_TYPE ( ETH_TYPE ) ) u_udp ( .rst_n ( rst_n ), .gmii_rx_clk ( clk ), .gmii_rx_dv ( gmii_rx_dv ), .gmii_rxd ( gmii_rxd ), .gmii_tx_clk ( clk ), .udp_tx_start ( udp_tx_start ), .udp_tx_byte_num ( udp_tx_byte_num ), .des_mac ( BOARD_MAC ), .des_ip ( BOARD_IP ), .gmii_tx_en ( gmii_tx_en ), .gmii_txd ( gmii_txd ), .udp_rx_done ( udp_rx_done ), .udp_rx_byte_num ( udp_rx_byte_num ), .udp_tx_rdy ( udp_tx_rdy ), .rx_data ( rx_data ), .rx_data_vld ( rx_data_vld ), .tx_data_req ( tx_data_req ), .tx_data ( tx_data ) ); //生成周期为CYCLE数值的系统时钟; initial begin clk = 0; forever #(CYCLE/2) clk = ~clk; end //生成复位信号; initial begin #1;udp_tx_start = 0; udp_tx_byte_num = 19;tx_data = 0; rst_n = 1; #2; rst_n = 0;//开始时复位10个时钟; #(RST_TIME*CYCLE); rst_n = 1; #(20*CYCLE); repeat(3)begin udp_tx_start = 1'b1; udp_tx_byte_num = {$random} % 64;//只产生64以内随机数,便于测试,不把数据报发的太长了; #(CYCLE); udp_tx_start = 1'b0; #(CYCLE); @(posedge udp_tx_rdy); #(100*CYCLE); end #(20*CYCLE); $stop;//停止仿真; end always@(posedge clk)begin if(tx_data_req)begin//产生0~255随机数作为测试; tx_data 图5 状态转换图

需要注意判断UDP首部的目的端口地址是不是开发板的端口地址,其余部分与ICMP的接收模块差不多,不在赘述了。

该模块对应的代码如下所示:

//The first section: synchronous timing always module, formatted to describe the transfer of the secondary register to the live register ? always@(posedge clk)begin if(!rst_n)begin state_c = MIN_DATA_NUM)//如果需要发送的数据多余以太网最短数据要求,则发送指定个数数据。 cnt_num 图12 顶层模块框图

该模块暂存UDP数据和ICMP数据的FIFO设置如下所示,使用一般模式即可,对应的需要提前产生数据请求输入信号。

图13 FIFO配置

该模块对应核心代码如下所示:

//例化锁相环,输出200MHZ时钟,作为IDELAYECTRL的参考时钟。 clk_wiz_0 u_clk_wiz_0 ( .clk_out1 ( idelay_clk),//output clk_out1; .resetn ( rst_n ),//input resetn; .clk_in1 ( clk ) //input clk_in1; ); //例化按键消抖模块。 key #( .TIME_20MS ( TIME_20MS ),//按键抖动持续的最长时间,默认最长持续时间为20ms。 .TIME_CLK ( TIME_CLK ) //系统时钟周期,默认8ns。 ) u_key ( .clk ( gmii_rx_clk ),//系统时钟,125MHz。 .rst_n ( rst_n ),//系统复位,低电平有效。 .key_in ( key_in ),//待输入的按键输入信号,默认低电平有效; .key_out ( key_out ) //按键消抖后输出信号,当按键按下一次时,输出一个时钟宽度的高电平; ); //例化ARP和ICMP的控制模块 arp_icmp_udp_ctrl u_arp_icmp_udp_ctrl ( .clk ( gmii_rx_clk ),//输入时钟; .rst_n ( rst_n ),//复位信号,低电平有效; .key_in ( key_out ),//按键按下,高电平有效; .des_mac ( des_mac ),//发送的目标MAC地址。 .des_ip ( des_ip ),//发送的目标IP地址。 //ARP .arp_rx_done ( arp_rx_done ),//ARP接收完成信号; .arp_rx_type ( arp_rx_type ),//ARP接收类型 0:请求 1:应答; .src_mac ( src_mac ),//ARP接收到目的MAC地址。 .src_ip ( src_ip ),//ARP接收到目的IP地址。 .arp_tx_rdy ( arp_tx_rdy ),//ARP发送模块忙闲指示信号。 .arp_tx_start ( arp_tx_start ),//ARP发送使能信号; .arp_tx_type ( arp_tx_type ),//ARP发送类型 0:请求 1:应答; .arp_gmii_tx_en ( arp_gmii_tx_en ), .arp_gmii_txd ( arp_gmii_txd ), //ICMP .icmp_rx_done ( icmp_rx_done ),//ICMP接收完成信号; .icmp_rx_byte_num ( icmp_rx_byte_num ),//以太网接收的有效字节数 单位:byte。 .icmp_tx_rdy ( icmp_tx_rdy ),//ICMP发送模块忙闲指示信号。 .icmp_gmii_tx_en ( icmp_gmii_tx_en ), .icmp_gmii_txd ( icmp_gmii_txd ), .icmp_tx_start ( icmp_tx_start ),//ICMP发送使能信号; .icmp_tx_byte_num ( icmp_tx_byte_num ),//以太网发送的有效字节数 单位:byte。 //udp .udp_rx_done ( udp_rx_done ),//UDP接收完成信号; .udp_rx_byte_num ( udp_rx_byte_num ),//以太网接收的有效字节数 单位:byte。 .udp_tx_rdy ( udp_tx_rdy ),//UDP发送模块忙闲指示信号。 .udp_gmii_tx_en ( udp_gmii_tx_en ), .udp_gmii_txd ( udp_gmii_txd ), .udp_tx_start ( udp_tx_start ),//UDP发送使能信号; .udp_tx_byte_num ( udp_tx_byte_num ),//以太网发送的有效字节数 单位:byte。 .gmii_tx_en ( gmii_tx_en ), .gmii_txd ( gmii_txd ) ); //例化ARP模块; arp #( .BOARD_MAC ( BOARD_MAC ),//开发板MAC地址 00-11-22-33-44-55; .BOARD_IP ( BOARD_IP ),//开发板IP地址 192.168.1.10; .DES_MAC ( DES_MAC ),//目的MAC地址 ff_ff_ff_ff_ff_ff; .DES_IP ( DES_IP ),//目的IP地址 192.168.1.102; .ETH_TYPE ( 16'h0806 ) //以太网帧类型,16'h0806表示ARP协议,16'h0800表示IP协议; ) u_arp ( .rst_n ( rst_n ),//复位信号,低电平有效。 .gmii_rx_clk ( gmii_rx_clk ),//GMII接收数据时钟。 .gmii_rx_dv ( gmii_rx_dv ),//GMII输入数据有效信号。 .gmii_rxd ( gmii_rxd ),//GMII输入数据。 .gmii_tx_clk ( gmii_tx_clk ),//GMII发送数据时钟。 .arp_tx_en ( arp_tx_start ),//ARP发送使能信号。 .arp_tx_type ( arp_tx_type ),//ARP发送类型 0:请求 1:应答。 .des_mac ( des_mac ),//发送的目标MAC地址。 .des_ip ( des_ip ),//发送的目标IP地址。 .gmii_tx_en ( arp_gmii_tx_en ),//GMII输出数据有效信号。 .gmii_txd ( arp_gmii_txd ),//GMII输出数据。 .arp_rx_done ( arp_rx_done ),//ARP接收完成信号。 .arp_rx_type ( arp_rx_type ),//ARP接收类型 0:请求 1:应答。 .src_mac ( src_mac ),//接收到目的MAC地址。 .src_ip ( src_ip ),//接收到目的IP地址。 .arp_tx_rdy ( arp_tx_rdy ) //ARP发送模块忙闲指示指示信号,高电平表示该模块空闲。 ); //例化ICMP模块。 icmp #( .BOARD_MAC ( BOARD_MAC ),//开发板MAC地址 00-11-22-33-44-55; .BOARD_IP ( BOARD_IP ),//开发板IP地址 192.168.1.10; .DES_MAC ( DES_MAC ),//目的MAC地址 ff_ff_ff_ff_ff_ff; .DES_IP ( DES_IP ),//目的IP地址 192.168.1.102; .ETH_TYPE ( 16'h0800 ) //以太网帧类型,16'h0806表示ARP协议,16'h0800表示IP协议; ) u_icmp ( .rst_n ( rst_n ),//复位信号,低电平有效。 .gmii_rx_clk ( gmii_rx_clk ),//GMII接收数据时钟。 .gmii_rx_dv ( gmii_rx_dv ),//GMII输入数据有效信号。 .gmii_rxd ( gmii_rxd ),//GMII输入数据。 .gmii_tx_clk ( gmii_tx_clk ),//GMII发送数据时钟。 .gmii_tx_en ( icmp_gmii_tx_en ),//GMII输出数据有效信号。 .gmii_txd ( icmp_gmii_txd ),//GMII输出数据。 .icmp_tx_start ( icmp_tx_start ),//以太网开始发送信号. .icmp_tx_byte_num ( icmp_tx_byte_num ),//以太网发送的有效字节数 单位:byte。 .des_mac ( des_mac ),//发送的目标MAC地址。 .des_ip ( des_ip ),//发送的目标IP地址。 .icmp_rx_done ( icmp_rx_done ),//ICMP接收完成信号。 .icmp_rx_byte_num ( icmp_rx_byte_num ),//以太网接收的有效字节数 单位:byte。 .icmp_tx_rdy ( icmp_tx_rdy ) //ICMP发送模块忙闲指示指示信号,高电平表示该模块空闲。 ); //例化UDP模块。 udp #( .BOARD_MAC ( BOARD_MAC ),//开发板MAC地址 00-11-22-33-44-55; .BOARD_IP ( BOARD_IP ),//开发板IP地址 192.168.1.10; .DES_MAC ( DES_MAC ),//目的MAC地址 ff_ff_ff_ff_ff_ff; .DES_IP ( DES_IP ),//目的IP地址 192.168.1.102; .BOARD_PORT ( BOARD_PORT),//板子的UDP端口号; .DES_PORT ( DES_PORT ),//源端口号; .ETH_TYPE ( 16'h0800 ) //以太网帧类型,16'h0806表示ARP协议,16'h0800表示IP协议; ) u_udp ( .rst_n ( rst_n ),//复位信号,低电平有效。 .gmii_rx_clk ( gmii_rx_clk ),//GMII接收数据时钟。 .gmii_rx_dv ( gmii_rx_dv ),//GMII输入数据有效信号。 .gmii_rxd ( gmii_rxd ),//GMII输入数据。 .gmii_tx_clk ( gmii_tx_clk ),//GMII发送数据时钟。 .gmii_tx_en ( udp_gmii_tx_en ),//GMII输出数据有效信号。 .gmii_txd ( udp_gmii_txd ),//GMII输出数据。 .udp_tx_start ( udp_tx_start ),//以太网开始发送信号. .udp_tx_byte_num ( udp_tx_byte_num ),//以太网发送的有效字节数 单位:byte。 .des_mac ( des_mac ),//发送的目标MAC地址。 .des_ip ( des_ip ),//发送的目标IP地址。 .udp_rx_done ( udp_rx_done ),//UDP接收完成信号。 .udp_rx_byte_num ( udp_rx_byte_num ),//以太网接收的有效字节数 单位:byte。 .udp_tx_rdy ( udp_tx_rdy ),//UDP发送模块忙闲指示指示信号,高电平表示该模块空闲。 .rx_data ( udp_rx_data ), .rx_data_vld ( udp_rx_data_vld ), .tx_data ( udp_tx_data ), .tx_data_req ( udp_tx_data_req ) ); //例化FIFO; fifo_generator_0 u_fifo_generator_0 ( .clk ( gmii_rx_clk ),//input wire clk .srst ( ~rst_n ),//input wire srst .din ( udp_rx_data ),//input wire [7 : 0] din .wr_en ( udp_rx_data_vld ),//input wire wr_en .rd_en ( udp_tx_data_req ),//input wire rd_en .dout ( udp_tx_data ),//output wire [7 : 0] dout .full ( ),//output wire full .empty ( ) //output wire empty ); //例化gmii转RGMII模块。 rgmii_to_gmii u_rgmii_to_gmii ( .idelay_clk ( idelay_clk ),//IDELAY时钟; .rst_n ( rst_n ), .gmii_tx_en ( gmii_tx_en ),//GMII发送数据使能信号; .gmii_txd ( gmii_txd ),//GMII发送数据; .gmii_rx_clk ( gmii_rx_clk ),//GMII接收时钟; .gmii_rx_dv ( gmii_rx_dv ),//GMII接收数据有效信号; .gmii_rxd ( gmii_rxd ),//GMII接收数据; .gmii_tx_clk ( gmii_tx_clk ),//GMII发送时钟; .rgmii_rxc ( rgmii_rxc ),//RGMII接收时钟; .rgmii_rx_ctl ( rgmii_rx_ctl ),//RGMII接收数据控制信号; .rgmii_rxd ( rgmii_rxd ),//RGMII接收数据; .rgmii_txc ( rgmii_txc ),//RGMII发送时钟; .rgmii_tx_ctl ( rgmii_tx_ctl ),//RGMII发送数据控制信号; .rgmii_txd ( rgmii_txd ) //RGMII发送数据; ); 8、上板测试

将顶层模块中的ILA注释取消,然后将程序综合、实现,最后下载到开发板中进行测试。打开电脑的控制面板->网络和Internet->网络连接,鼠标右击以太网,双击Internet协议版本4,进行如下设置,与代码顶层模块设置的目的IP一致,具体步骤可以查看前文。

图14 电脑IP设置

然后把wirrshark和网络调试助手打开,如下所示:

图15 wireshark与网络调试助手

网络调试助手需要设置协议类型为UDP,PC端的IP地址和UDP地址,需要与顶层文件的数值保持一致。然后打开连接,就会显示出FPGA的IP地址和UDP端口地址,如果该地址与开发板的地址不一样,可以手动进行修改。

图16 网络调试助手的设置

之后将ILA设置为gmii_rx_dv的上升沿触发,连续抓取32个数据报文,然后wireshark也运行,最后点击网络调试助手的发送指令,即可抓取相关数据。网络调试助手发送三帧数据,如下图所示,FPGA向PC端返回接收到的三帧数据(蓝色数据是PC端通过UDP向FPGA发送的数据,绿色数据是FPGA通过UDP向PC端发送的数据)。

图17 网络调试助手收发数据

对比网络调试助手收发数据一致,由此证明FPGA接收和发送数据无误。

然后查看wireshark在这段时间抓取的数据报文,如下图所示。

PC端在通过UDP向FPGA发送数据报文之前,先通过广播的形式发送了一个ARP请求指令,去获取开发板的MAC地址,FPGA接收到ARP请求后,也是向PC端返回了ARP应答数据报文。

然后PC端通过UDP向FPGA发送三个数据报文,如下图所示,FPGA也对该报文进行了应答。

图18 wireshark抓取数据报文

前文对ARP的报文已经做了详细讲解,所以此处不对其报文进行分析了,我们双击UDP报文,查看其发送的数据段,如下图蓝色背景文字部分,与图17中第一帧数据保持一致。

图19 wireshark抓取发送的第一帧数据报文

如下图是wirshark抓取的FPGA通过UDP给PC端发送的第一帧报文,可以从红框处得知源MAC和源IP地址为开发板,目的MAC和目的IP都是PC端的地址。接收的UDP数据就是蓝色文字,与图19PC端发送的数据保持一致。

图20 wireshark抓取接收的第一帧数据报文

上述的数据报文通过ILA抓取如下所示,紫红色信号就是接收的报文数据信号。

图21 ILA抓取接收的第一帧数据报文

将接收的UDP数据段放大后如下图所示,与图19和图17PC端发送的第一帧数据保持一致,因此FPGA这边接收数据没有问题。

图22 UDP数据段放大

当FPGA接收到UDP数据包后,立马回复一帧UDP数据,如下所示,紫红色信号是接收的数据报文,橙色信号是发送的数据报文。

图23 UDP接收和发送报文

将发送报文的数据段放大,结果如下所示,与图17和图20wireshark抓取的数据一致,由此证明该设计接收和发送数据均没有问题。

图24 发送报文数据段

最后就是验证ICMP的问题了,直接打开命令提示符,然后输入ping 192.168.1.10指令,运行结果如下所示:

图25 ping指令验证

上图表示FPGA接收到PC端的回显请求时,能够向PC端发送回显应答数据报文,以此验证以太网链路是否通畅。

关于UDP的发送和接收本文就做这么多讲解,当然这并不是我们最终想要使用的模块,因为ARP、UDP、ICMP这三个模块其实很多地方都是类似的,使用三个独立的模块完全没有必要,会额外消耗很多资源。

后文会把这三个模块进行整合设计,将模块合成一个eth模块,该模块可以实现对ARP、ICMP、UDP报文的接收,并根据需要发送相应报文。

获取本文工程的方式是在公众号后台回复“基于FPGA的UDP回环设计”(不包括引号)。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3