• 千兆以太网传输层 UDP 协议原理与 FPGA 实现(UDP接收)


    相关文章:
    (1)千兆以太网网络层 ARP 协议的原理与 FPGA 实现
    (2)千兆以太网硬件设计及链路层 MAC 协议格式
    (3)CRC校验原理及实现
    (4)RGMII 与 GMII 转换电路设计
    (5)千兆以太网网络层 IP 协议介绍与 IP 校 验和算法实现
    (6)千兆以太网传输层 UDP 协议原理与 FPGA 实现(UDP发送)
    (7)千兆以太网传输层 UDP 协议原理与 FPGA 实现(UDP接收)
    (8)千兆以太网传输层 UDP 协议原理与 FPGA 实现(UDP回环)
    (9)以太网初始化设计(MDIO 控制器)
    (10)添加基于 OV2640 的以太网 RGMII 图像传输系统设计


    前言

    在前面我们对以太网 UDP 帧格式做了讲解,UDP 帧格式包括前导码+帧界定符、以太网头部数据、IP 头部数据、UDP 头部数据、UDP 数据、FCS 数据,以太网接收模块同样是按照该格式接收数据。

    提示:任何文章不要过度深思!万事万物都经不起审视,因为世上没有同样的成长环境,也没有同样的认知水平,更「没有适用于所有人的解决方案」 ;不要急着评判文章列出的观点,只需代入其中,适度审视一番自己即可,能「跳脱出来从外人的角度看看现在的自己处在什么样的阶段」才不为俗人 。怎么想、怎么做,全在乎自己「不断实践中寻找适合自己的大道」

    心得体会

    (1)UDP接收数据,无论是MAC地址,还是IP地址,或者UDP端口,其源端口都为计算机;
    (2)在接收数据时不关心源端口(计算机)的MAC地址,还是IP地址,或者UDP端口,只关心目的地址,也就是说接收数据时可以将源端口MAC地址,IP地址,UDP端口全部置 0;
    (3)验证时一定要弄清目的地址(开发板)的MAC和IP地址,这里与UDP发送中目的MAC、IP(计算机)是相反的,此处需要注意;
    (4)本实验针对千兆网,注意查看电脑是否支持。

    一、 UDP 协议简单回顾

    以太网 UDP 帧的用户数据是打包在 UDP 协议中,而 UDP 协议又是基于 IP 协议之上的,IP 协议又是走 MAC 层发送的,即从包含关系来说:MAC 帧中的数据段为 IP 数据报文,IP 报文中的数据段为 UDP 报文,UDP 报文中的数据段为用户希望传输的数据内容下图为使用 UDP 协议发送数据的层层打包示意图。
    在这里插入图片描述
    其中,和以太网帧、IP 报文具有帧头一样,UDP 数据报也包含了一个 UDP 报头部分,与 UDP 协议相关的一些信息如端口号,数据包长度等会被打包进 UDP 报头中,然后再与需要传输的 UDP 报文数据一起,作为 IP 报文的数据段送往 IP 层发送。

    二、UDP接收实现

    GMII 接口信号连接关系及各信号的介绍如下。
    1
    (注:表格中的方向是站在 MAC 侧角度看的)

    在这里插入图片描述
    此处给出GMII 接口信号连接关系及各信号的介绍,是为了明确UDP发送与接收需要什么输入与输出。

    下面将对各个状态的实现及功能进行简要介绍。

    1. IDLE
      空闲状态,当产生接收数据有效信号时,进入PREAMBLE_CODE状态,否则处于 IDLE 状态,代码如下所示:
     IDLE:     begin
    							    GMII_RX_DONE <= 0;
    							    crc_en <= 0;
    								if(GMII_DV_reg1 && !GMII_DV_reg2)
    									begin
    										  curr_state <= PREAMBLE_CODE;
    										  
    									end
    								else
    								  curr_state <= curr_state;
    							end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    上述代码中的GMII_DV_reg1 信号是将接收数据有效信号GMII_DV寄存之后打一拍得到的,GMII_DV_reg2 信号是将GMII_DV_reg1信号打一拍得到的,将GMII_DV_reg2 信号取反与
    GMII_DV_reg1 相与得到接收数据有效脉冲,得到该信号之后,进入到PREAMBLE_CODE 状态,
    在这里插入图片描述

    GMII_DV_reg1 信号和GMII_DV_reg2 信号的实现代码如下所示,代码中对GMII_TXD 信号也进行了寄存和打拍操作,

    //输入数据寄存
    	always @ (posedge clk125m_o  or  negedge reset_n)
    		if(!reset_n)
    			begin
    				GMII_ER_reg <= 0;
    				GMII_DV_reg <= 0;
    				GMII_TXD_reg<= 0;
    			end
    		else begin
    		        GMII_ER_reg <= GMII_ER;
    				GMII_DV_reg <= GMII_DV;
    				GMII_TXD_reg<= GMII_TXD;
    		     end
    			
    	
    	
    	
    	//数据打两拍判断接收起始
    	always @ (posedge clk125m_o  or negedge reset_n)
    	    if(!reset_n)
    			begin
    			
    				GMII_DV_reg1 <= 0;
    				GMII_DV_reg2 <= 0;
    				
    				GMII_TXD_reg1<= 0;
    				GMII_TXD_reg2<= 0;
    				crc_data        <= 0;
    			
    			end
    		else
    			begin
    					GMII_DV_reg1 <= GMII_DV_reg;
    					GMII_DV_reg2 <= GMII_DV_reg1;
    					
    					GMII_TXD_reg1<= GMII_TXD_reg;
    					GMII_TXD_reg2<= GMII_TXD_reg1;
    					crc_data     <= GMII_TXD_reg2;  
    					
    			end
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1. PREAMBLE_CODE 状态
      处于 PREAMBLE_CODE状态的时候,当以太网接收到帧界定符(D5)和 7 个的前导码(55)
      时,进入到ETH_HEADER 状态,代码如下所示:
    PREAMBLE_CODE:
    								begin
    									crc_init <= 0;
    									if(cnt_preamble == 4'd7)
    									  begin
    										  curr_state <= ETH_HEADER;
    										  cnt_preamble <= 0;
    									  end
    									  
    									
    									else
    										begin
    											cnt_preamble <= cnt_preamble + 1'b1;
    											curr_state <= curr_state;
    										end
                                    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. ETH_HEADER
      处于 ETH_HEADER 状态时,接收以太网头部数据,当接收完 14 个以太网头部数据之后,进入到 IP_HEADER 状态,如果接收不是7个55和一个D5,则表明此时数据接收错误,进入 IDLE 状态,然后当处于该状态的时候,根据 cnt_eth_header 的值,依次得到 14 个字节的以太网头部数据,分别是 MAC 目的地址(6 个字节)、MAC 源地址(6 个字节)和以太网类型(2 个字节),代码如下所示:
     ETH_HEADER:begin
    								crc_en <= 1;
    								if(cnt_eth_header == 4'd13)
    									begin
    										curr_state <= IP_HEADER;
    										cnt_eth_header <= 0;
    									end
    								else if((cnt_eth_header == 4'd0) && (preamble_code_check_ok == 1'b0))
    									begin
    										curr_state <= IDLE;
    										cnt_eth_header <= 0;
    									end	
    								else
    									begin
    										cnt_eth_header <= cnt_eth_header + 1'b1;
    										curr_state <= curr_state;
    									end
    								
    								case(cnt_eth_header)
    									 
    									  4'd0 :dst_mac_reg[47:40] <= GMII_TXD_reg2;   
    									  4'd1 :dst_mac_reg[39:32] <= GMII_TXD_reg2;
    									  4'd2 :dst_mac_reg[31:24] <= GMII_TXD_reg2;
    									  4'd3 :dst_mac_reg[23:16] <= GMII_TXD_reg2;
    									  4'd4 :dst_mac_reg[15:8]  <= GMII_TXD_reg2;
    									  4'd5 :dst_mac_reg[7:0]   <= GMII_TXD_reg2;
    
    									  4'd6 :src_mac_reg[47:40] <= GMII_TXD_reg2;
    									  4'd7 :src_mac_reg[39:32] <= GMII_TXD_reg2;
    									  4'd8 :src_mac_reg[31:24] <= GMII_TXD_reg2;
    									  4'd9 :src_mac_reg[23:16] <= GMII_TXD_reg2;
    									  4'd10:src_mac_reg[15:8]  <= GMII_TXD_reg2;
    									  4'd11:src_mac_reg[7:0]   <= GMII_TXD_reg2;
    
    									  4'd12:eth_type[15:8] <= GMII_TXD_reg2;
    									  4'd13:eth_type[7:0]  <= GMII_TXD_reg2;
    									  default: ;	
    									
    								endcase
    						    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    其中preamble_code_check_ok为:

    always @ (posedge clk125m_o  or negedge reset_n)
    		if(!reset_n)
    			preamble_code_check_ok <= 1'b0;
    		else if((GMII_TXD_reg2 == 8'hd5) && (cnt_preamble == 4'd7))
    			preamble_code_check_ok <= 1'b1;
    		else
    			preamble_code_check_ok <= 1'b0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. IP_HEADER
      (1)接收以太网 IP 头部数据状态IP_HEADER,首先得对接收的以太网 IP 头部数据进行计数,定义一个计数器 cnt_ip_header,当处于该状态的时候进行计数,否则清零,
      (2)然后当处于 IP_HEADER 状态时,获取以太网 IP 头部数据,根据 cnt_ip_header 的值,一共需要获取 20 个字节的数据,分别为 IP 版本(ip_ver)、首部长度(ip_hdr_len)、服务类型(ip_tos)、数据报总长度(total_len)、标识主机发送的每一份数据报(ip_id)、标志位(ip_rsv、ip_df、ip_mf)、段偏移量(ip_frag_offset)、生存期(ip_ttl)、IP 的协议封装类型(ip_protocol)、头部校验和(ip_check_sum)、源 IP 地址(src_ip)和目的 IP 地址(dst_ip),代码如下所示:
    IP_HEADER:begin
    									if(cnt_ip_header == 5'd19)
    									    begin
    										    curr_state <= UDP_HEADER;
    											udp_data_length_reg <= ip_total_len - 16'd20 - 16'd8;
    											cnt_ip_header <= 5'd0;
    											ip_cal_en     <= 1;
    											
    										end
    									else if(cnt_ip_header >= 5'd1 && eth_header_check_ok == 1'b0)
    									    begin
    											curr_state <= IDLE;
    											cnt_ip_header <= 0;
    											
    										end
    									else
    										begin
    											cnt_ip_header <= cnt_ip_header + 1'b1;
    											curr_state <= curr_state;
    										end
    									case (cnt_ip_header)
    										          5'd0:   {
       ip_ver,ip_hdr_len}                       <= GMII_TXD_reg2;
    												  5'd1:   ip_tos                                    <= GMII_TXD_reg2;
    												  5'd2:   ip_total_len[15:8]                        <= GMII_TXD_reg2;
    												  5'd3:   ip_total_len[7:0]                         <= GMII_TXD_reg2;
    												  5'd4:   ip_id[15:8]                               <= GMII_TXD_reg2;
    												  5'd5:   ip_id[7:0]                                <= GMII_TXD_reg2;
    												  5'd6:   {
       ip_rsv,ip_df,ip_mf,ip_frag_offset[12:8]} <= GMII_TXD_reg2;
    												  5'd7:   ip_frag_offset[7:0]                       <= GMII_TXD_reg2;
    												  5'd8:   ip_ttl                                    <= GMII_TXD_reg2;
    												  5'd9:   ip_protocol                               <= GMII_TXD_reg2;
    												  5'd10:  ip_check_sum[15:8]                        <= GMII_TXD_reg2;
    												  5'd11:  ip_check_sum[7:0]                         <= GMII_TXD_reg2;
    												  5'd12:  src_ip_reg[31:24]                         <= GMII_TXD_reg2;
    												  5'd13:  src_ip_reg[23:16]                         <= GMII_TXD_reg2;
    												  5'd14:  src_ip_reg[15:8]                          <= GMII_TXD_reg2;
    												  5'd15:  src_ip_reg[7:0]                           <= GMII_TXD_reg2;
    												  5'd16:  dst_ip_reg[31:24]                         <= GMII_TXD_reg2;
    												  5'd17:  dst_ip_reg[23:16]                         <= GMII_TXD_reg2;
    												  5'd18:  dst_ip_reg[15:8]                          <= GMII_TXD_reg2;
    												  5'd19:  dst_ip_reg[7:0]                           <= GMII_TXD_reg2;      
    												  defaul
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
  • 相关阅读:
    图片矫正
    java 多线程&wait/notify机制的原理——62
    JVM GC与频繁GC
    Python Linux下编译
    探店通系统源码,短视频矩阵源码,抖音矩阵系统源码。
    TSINGSEE青犀/视频分析/边缘计算/AI算法·人员/区域入侵功能——多场景高效运用
    数据库基础(二)【MySQL】
    【经典算法学习-排序篇】顺序查找
    this的四个绑定规则
    我的家乡潍坊HTML静态网页 学生个人网页设计作品 学生家乡网页模板 简单个人主页成品
  • 原文地址:https://blog.csdn.net/wd12306/article/details/133683821