Xilinx-AX7103-学习笔记(25):基于UDP的以太网通信

Xilinx-AX7103-学习笔记(25):基于UDP的以太网通信

实验将实现AX7103开发板和PC之间进行以太网数据通信, 通信协议采用Ethernet UDP通信协议。开发板上FPGA通过以太网PHY芯片KSZ9031RNX和网口连接, 通过RGMII接口跟FPGA进行数据通信。

一、基本知识介绍

从硬件角度来看以太网是由CPU,MAC,PHY三部分组成的,如下图:
在这里插入图片描述
上图中DMA集成在CPU,CPU,MAC,PHY并不是集成在同一个芯片内,由于PHY包含大量模拟器件,而MAC是典型的数字电路,考虑到芯片面积及模拟/数字混合架构的原因,将MAC集成进CPU而将PHY留在片外,这种结构是最常见的。

1、MAC

MAC(Media Access Control) 即媒体访问控制层协议。MAC由硬件控制器及MAC通信协议构成。其硬件框架如下图所示:
在这里插入图片描述
一般以太网MAC芯片的一端连接PCI总线,另一端连接PHY芯片上通过MII接口连接。

2、PHY

PHY(Physical Layer)是IEEE802.3中定义的一个标准模块,STA(Station Management Entity,管理实体,一般为MAC或CPU)通过MIIM(MII Manage Interface)对PHY的行为、状态进行管理和控制,而具体管理和控制动作是通过读写PHY内部的寄存器实现的。PHY的基本结构如下图:
在这里插入图片描述

3、MII、GMII和RGMII接口

(1)MII接口
MII(Media Independent interface)即介质无关接口,它是IEEE-802.3定义的行业标准,是MAC与PHY之间的接口。MII数据接口包含16个信号和2个管理接口信号数据接口位宽4bit,时钟周期25Mhz,支持百兆以太网通信。如下图所示:
在这里插入图片描述
(2)GMII接口
GMII(Gigabit Media Independant Interface),千兆MII接口。GMII采用8位接口数据,工作时钟125MHz,因此传输速率可达1000Mbps。同时兼容MII所规定的10/100 Mbps工作方式。GMII接口数据结构符合IEEE以太网标准,该接口定义见IEEE 802.3-2000。信号定义如下:
在这里插入图片描述
(3)RGMII接口

RGMII(Reduced Gigabit Media Independant Interface),精简GMII接口。相对于GMII相比,RGMII具有如下特征:

  • 发送/接收数据线由8条改为4条
  • TX_ER和TX_EN复用,通过TX_CTL传送
  • RX_ER与RX_DV复用,通过RX_CTL传送
  • 1 Gbit/s速率下,时钟频率为125MHz
  • 100 Mbit/s速率下,时钟频率为25MHz
  • 10 Mbit/s速率下,时钟频率为2.5MHz

在这里插入图片描述

4、MAC帧协议

在这里插入图片描述
在物理层上看,一个完整的以太网帧有7个字段,事实上,前两个字段并不能算是真正意义上的以太网数据帧,它们是以太网在物理层上发送以太网数据时添加上去的。

字段字段长度(字节)说明
前导码77个字节的0x55,用于帧同步
帧开始符(SFD)1标明下一个字节为目的MAC字段(0x5D)
目的MAC地址6指明帧接收者
源MAC地址6指明帧发送者
长度/类型2当这两个字节的值小于1518时,那么它就代表其后数据字段的长度;如果这两个字节的值大于1518,则表示该以太网帧中的数据属于哪个上层协议(例如0x800,代表IP数据包;0x806,代表ARP数据包等。
数据和填充46~1500高层的数据,通常为3层协议数据单元。对于TCP/IP是IP数据包
帧校验序列(FCS)4对接收网卡提供判断是否传输错误的一种方法,如果发现错误,丢弃此帧

在以太网帧中,目的MAC地址可以分为三类:单播地址、多播地址和广播地址。广播地址的所有48位全为1(即FF-FF-FF-FF-FF-FF),同一局域网中的所有网卡可以接收广播数据包。

5、UDP协议

UDP 是User Datagram Protocol的简称,中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联)参考模型中一种无连接的传输层协议。

(1)IP数据报格式
IP是TCP/IP协议族中最核心的协议,所有的TCP、UDP、ICMP、IGMP数据都以IP数据报的格式传输。IP仅提供尽力而为的传输服务,如果发生某种错误,IP会丢失该数据,然后发送ICMP消息给信源端。
在这里插入图片描述
其中IP报文头部定义如下:

在这里插入图片描述
IP报头详细描述如下表:

字段字段长度(字节)说明
版本+首部长度1IP 协议版本:版本就是IPV4或者IPV6,一般选择IPV4,即版本值为4。IP首部长度:IP首部长度即有多少个32位数,当IP首部长度为20时(即无可选字段),该值为5.(5*4 =20)
服务类型1指示了报文的优先权等,默认全部置0即可
总长度2IP报文长度,包括IP报文报头+IP报数据
分段标识2是否属于同一数据段,IP报文的分段ID
段标识和段偏移2可以设为0
生存周期(TTL)1可以经过的最大路由数,生存时间字段设置了数据报可以经过的最多路由器数,表示数据包在网络上生存多久。TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃。
上层协议类型1指该封包所使用的网络协议类型,如ICMP、DNS等,占8位。常用协议号有00:IP01:ICMP06:TCP17:UDP
报头校验和2IP报头部分数据校验和
源IP地址4发送端的IP地址,如192.168.0.2
目的IP地址4接收端的IP地址,如192.168.0.3
可选字段0~40可选,没有的时候长度可以为0,该字段最大字长度40字节。

(2)UDP数据报格式
UDP数据报分为首部和用户数据部分,整个UDP数据报作为IP数据报的数据部分封装在IP数据报中,UDP报文的以太网帧结构如图所示。
在这里插入图片描述
UDP报文包括UDP报文首部数据和UDP报文数据(数据负载),其中UDP首部有8个字节,由4个字段构成,每个字段都是两个字节。
在这里插入图片描述
UDP报文描述如下:

字段字段长度(字节)说明
源端口2源端口号,需要对方回信时选用,不需要时全部置0
目的端口2目的端口号,在终点交付报文的时候需要用到
长度2UDP的数据报的长度(包括UDP首部和数据)其最小值为8(只有首部)
校验和2检测UDP数据报在传输中是否有错,有错则丢弃。该字段是可选的,当源主机不想计算校验和,则直接令该字段全为0。

二、实验分析

以太网PHY芯片与FPGA的IP接口相连,KSZ9031芯片支持10/100/1000Mbps网络传输速率,通过RGMII接口与FPGA进行数据通信。另外FPGA可以通过MDI/MDIO管理接叔来配置戒读叏PHY芯片内部癿寄存器。
在这里插入图片描述

1、udp通信分析

整个udp发送部分主要由一个顶层模块ethernet_test.v,UDP测试程序udp.v和三个子模块:UDP収送模块(ipsend.v),UDP接收模块(iprecieve.v)和CRC校验模块(crc.v)组成。

(1)ethernet_test.v
其中例化了两个模块,UDP控制模块RAM模块,任务是将通过UDP接收回来的数据包存储在FPGA内部的RAM中,再不断把RAM中的数据包通过网口发送回ethernet网络。

(1.1) 对于双端口RAM来说,共有6根信号线:

ram ram_inst (
	.clka(gmii_rx_clk),    // input clka(时钟上升沿到来时对数据进行写入)
	.wea(wea),             // input [0 : 0] wea (“wea == 1”时只写不读,“wea == 0”时只读不写)
	.addra(addra),         // input [8 : 0] addra (输入地址线)
	.dina(dina),           // input [31 : 0] dina (输入数据线)
	
	.clkb(gmii_tx_clk),    // input clkb(时钟上升沿到来时对数据进行读出)
	.addrb(ram_rd_addr),   // input [8 : 0] addrb (输出地址线)
	.doutb(ram_rd_data)    // output [31 : 0] doutb (输出数据线)
);

对于双端口的时钟来说,数据写入时钟由接收端时钟gmii_rx_clk提供,数据读出时钟由接收端时钟gmii_tx_clk提供。对于使能信号、输入数据和地址需要进行一个判断:

//当ram_wr_finish为1时,将以太网接收回的数据写入到RAM中
//当ram_wr_finish为0时,将预先存好的数据写入到RAM中
assign wea = ram_wr_finish ? data_o_valid : ram_wren_i;
assign addra = ram_wr_finish ? ram_wr_addr : ram_addr_i;
assign dina = ram_wr_finish ? ram_wr_data : ram_data_i;

(1.2) 对于UDP收发模块来说,其中例化了三个模块,UDP发送模块UDP接收模块CRC校验模块,在进行发送前要进行CRC校验,接收不需要。

(1.2.1) 对于发送模块来说,接口采用GMII接口,整个发送过程通过一个状态机来控制。
在这里插入图片描述

  1. 最开始将状态机进入到idle状态,与此同时将7个前导码55、一个帧开始符d5、目的MAC地址ff-ff-ff-ff-ff-ff(广播包)、源MAC地址00-0A-35-01-FE-C0和IP包类型0800都准备好。
    在这里插入图片描述
    可以看到在刚开始通过一拍时钟将相应的所有寄存器的值都配置好了,包括输入数据datain,前导码和开始符preamble,MAC地址mac_addr.

  2. idle:该状态下将所有信号全部复位并进行一段时间的延时,以控制隔一段时间发送一个数据,延迟完成后将状态过渡到start状态下。
    在这里插入图片描述
    为了仿真方便,这里将计数器的值设为125,换算成16进制为D7,从图中可以看到timer_counter寄存器记到该值,状态切换到start。

  3. start:该状态下将ip报头部分准备好(版本号、报头长度等),并将状态过渡到make状态下。
    在这里插入图片描述
    对IP报头信息ip_header通过一拍进行赋值。

  4. make:根据ip报头部分的内容生成ip报头的校验和,并将状态过渡到send55状态下。
    在这里插入图片描述
    ip校验和计算出来后,对ip_header[2]进行替换,由之前的80110000变为80117966,计算方法如下:
    0x4500 + 0x0030 + 0x0001 + 0x4000 + 0x8011 + 0x0000(计算时置0) + 0xc0a8 + 0x0002 + 0xc0a8 + 0x0003 = 0x28697
    0x0002 + 0x8697 = 0x8699
    checksum = ~0x8699 = 7966(将结果换回到校验和对应的位置处即得到结果)

  5. send55:发送发送8个IP前导码:7个55, 1个d5 ,并将状态过渡到sendmac状态下。
    在这里插入图片描述
    时钟下降沿写入55,55,55,55,55,55,55,d5

  6. sendmac:发送目标MAC address和源MAC address和IP包类型 ,使能crc校验,并将状态过渡到sendheader状态下。
    在这里插入图片描述
    时钟下降沿写入目标MAC地址ff,ff,ff,ff,ff,ff和源MAC地址00-0A-35-01-FE-C0以及IP包类型08,00,同时使能CRC校验,将crcen拉高。

  7. sendheader:发送7个32bit的IP包头,{版本号+包头长度} {包头序列+段偏移} {生存周期+上层协议+校验和} {源IP地址} {目的IP地址} {源端口号+目的端口号} {UDP数据长度+UDP数据校验和},准备要发送的数据,并将状态过渡到senddata状态下。
    在这里插入图片描述
    在这里插入图片描述

  8. senddata:将RAM中的数据作为UDP的数据发送出去,发送完毕将状态过渡到sendcrc状态下。
    在这里插入图片描述
    这里将tx_data_length设为28,tx_total_length设为48(首部长度为20),该状态结束条件为tx_data_counter == tx_data_length-9。此处RAM中存放的数据有20个字节,通过地址=ram_rd_addr==进行索引,共4个地址下的数据,每个地址存放4字节的内容。
    我为了仿真清楚,地址中的数据是自己定的,内容如下:001中存放0x01020304,002中存放0x04050607,003中存放0x04030201,004中存放0x07060504,005中存放0x0a0b0c0d,其余均为0xffffffff
    计数器i的作用是将每个地址中4字节的内容1字节1字节发出去每当i为3时表示1个地址内容发送完成,则将下一个地址的内容给到寄存器datain_reg中,tx_data_counter的作用是记满20个字节的内容,表示将RAM中的数据都发出去。

  9. sendcrc:发送32位的crc校验,并将状态过渡到idle状态下。
    在这里插入图片描述
    当crc计算完成后,crcen拉低,然后将CRC校验结果取反后1字节1字节发送出去。

(1.2.2) 对于接收模块来说,接口采用GMII接口,整个接收过程仍通过一个状态机来控制。
在这里插入图片描述

  1. idle:该状态下将所有信号全部复位并等待接收数据有效信号e_rxdv的到来,当输入数据为0x55,将数据保存到寄存器mydata中,同时将状态过渡到six_55。
  2. six_55:该状态下接收剩余6个0x55,通过计数器state_counter进行6个的计数,接收过程同样在e_rxdv为1时进行,接收完成后将状态过渡到spd_d5,如果中途不是0x55则重新跳回idle状态。
  3. spd_d5:该状态下用来检测帧开始符0xd5,同样在e_rxdv为1时进行,接收完成后将状态过渡到rx_mac,如果中途出现问题则重新跳回idle状态。
  4. rx_mac:该状态下接收目标MAC地址和源MAC地址,并将接收到的内容保存到寄存器mymac中,将mymac中的值与0x000a_3501_fec0进行对比,相同证明是本FPGA,则将状态过渡到rx_ip_protocol,否则回到idle。
  5. rx_IP_Protocol:该状态下接收2个字节的IP类型,并将数据保存到寄存器myIP_Prtcl中,并将状态过渡到rx_IP_layer。(之后一直都是在e_rxdv为1下进行的,否则回到idle状态)
  6. rx_IP_layer:该状态下接收20字节的ip报头,并将数据保存到寄存器myIP_layer中,并将状态过渡到rx_UDP_layer。
  7. rx_UDP_layer:该状态下接收8字节UDP的端口号及UDP数据包长,并将数据保存到寄存器myUDP_layer中,并将状态过渡到rx_data。
  8. rx_data:该状态下接收UDP数据(真正的UDP数据需要减去8字节的UDP包头),每接收到4字节的内容就通过mydata寄存器拼在一起,同时使能data_o_valid信号以完成RAM的写入,每写完4个字节数据RAM地址加1,直到写完要求长度的数据停止,对于最后的数据若不足4字节,通过补0来完成。完成后将状态过渡到rx_finish。
  9. rx_finish:写完RAM数据后的状态,该状态下将data_o_valid信号拉低,标志写完;将data_receive信号拉高,标志接收完成。并将状态过渡到idle状态,等待下一次接收。
对于接收一侧来说,仿真结果与发送类似,并且testbench需要大量封装数据,意义不大,这里不再做波形演示。

(1.2.3) 对于CRC校验来说,可以通过网站自动生成,这里不赘述。

2、MDC/MDIO通信时序分析

参考:

https://blog.csdn.net/qq_35569806/article/details/84949741

  • 8
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DDS(Direct Digital Synthesis)直接数字合成技术是一种数字信号处理技术,用于产生高精度、高稳定度、高分辨率的周期性信号。DDS技术的主要思路是:将一个固定的参考频率信号和一个可变的相位调制信号相乘,从而产生所需频率的输出信号。 在MATLAB中,我们可以通过使用内置函数sin()来生成正弦波信号。例如,我们可以生成一个频率为10 Hz,振幅为1的正弦波信号,并将其绘制成图形: ``` t = 0:0.001:1; x = sin(2*pi*10*t); plot(t,x); ``` 在Verilog中,我们可以使用DDS模块来生成正弦波信号。以下是一个简单的DDS模块: ``` module dds( input clk, //时钟信号 input reset, //复位信号 output reg [7:0] sin_out //正弦波输出信号 ); reg [31:0] phase_acc; //相位累加器 reg [7:0] sin_lut [0:255]; //正弦波查找表 //初始化正弦波查找表 initial begin for (i = 0; i < 256; i = i + 1) begin sin_lut[i] = $signed(127*sin(2*3.14159*i/256)); end end always @(posedge clk) begin if (reset) begin phase_acc <= 0; sin_out <= 0; end else begin phase_acc <= phase_acc + 100; //相位累加器步进为100 sin_out <= sin_lut[phase_acc[31:24]]; //从查找表中读取正弦波值 end end endmodule ``` 在这个DDS模块中,我们使用相位累加器来控制正弦波的频率,使用查找表来存储正弦波的值。在时钟上升沿时,相位累加器步进100,从查找表中读取正弦波值,并将其输出。 需要注意的是,在这个DDS模块中,我们使用了固定的步进值100。如果我们想要生成不同频率的正弦波信号,我们需要改变步进值。例如,如果我们想要生成频率为1 kHz的正弦波信号,我们需要将步进值改为1000*256/时钟频率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值