收尾:李逍遥
本文的内容分为四个部分
接收-RGM二号协议和IDDR原语
接收-数据包验证和数据过滤
发送-设置以太网心跳数据包
Send-ODDR原语和Wireshark捕获工具
接收——RGMII协议和IDDR原语一、项目概述
1.项目流程图
2.模块描述:
PC:带网线槽的个人电脑RJ45接口:板卡上网线槽PHY芯片:板卡上以太网芯片,输入4对差分信号并转换成输出双边沿4-4位数据信号FPGA:现场可编程门阵列,主控制器DDR3芯片:第三代同步动态
上位机通过双绞线将1024*768图片发送到板卡的网络端口,RJ45接口将数据传输到网卡,PHY芯片将差分信号转换为双边数据,IDDR将双边数据转换为单边数据传输到FPGA,FPGA处理后,图像数据缓存在DDR3中,DDR3中的图像数据使用UDP协议传输回PC,DDR3中的数据使用HDMI传输到显示器。
第二,PHY芯片
详见VSC8601-DS-r41-VMDS-10210文件,可从Xilinx官网下载。
1.以太网和RJ45接口
以太网是较早产生并广泛使用的一种局域网。分类标准包括标准以太网、快速以太网和千兆以太网。随着以太网技术的飞速发展,市场上出现了万兆以太网,其技术支持10Gbit/s的传输速率。以太网连接端口:常见的以太网接口类型包括RJ45接口和RJ11接口。SC光纤接口等。RJ45接口是我们常见的网络设备接口。
RJ45接口的定义和每个引脚的功能描述如下图所示。在以太网中,只用四根线1、2、3、6,其中1、2负责传输数据,3、6负责接收数据,其余四根线备用。
一般来说,这部分是马上知道的,不需要自己设计代码。
2.PHY芯片简介:
本项目采用VITESSE VSC8601网卡芯片,支持10/100/1000 Base-T,常用的网卡芯片有VITESSE、高通等产品,俗称PHY芯片。该芯片与我们的计算机、FPGA、MCU等微处理器之间的通信必须遵循RGMII协议。
3.PHY芯片配置
①SMI串行管理接口
VSC8601设备包含一个与IEEE 802.3兼容的串行管理接口,其中MDC和MDIO可以控制芯片。SMI提供对设备控制和状态寄存器的访问。用于控制SMI的寄存器组由32个16位寄存器组成,包括所有必需的IEEE指定寄存器。此外,可以通过设备寄存器31访问寄存器的附加寄存器。SMI是同步串口,配置和IIC差不多。MDIO引脚具有双向数据,在MDC信号的上升沿收集。MDC采集速度应为0 MHz至25mhz。数据通过SMI传输,使用带有可选和任意长度前导码的32位帧。下图显示了读写操作的SMI框架格式。
从图中可以看出,PHY地址有A0-A4,总共5位,所以一个处理器最多可以安装2 5 = 32个这样的PHY芯片。用户可以根据需要通过配置PHY地址或注册地址来配置芯片。
②配置引脚和设备功能表
③相关引脚的功能,用于解释上表
④电阻对应的Pin值表
⑤PHY芯片配置
结合上表和PHY芯片的板卡原理图,可以确定CMODE Pin的具体值。
Iii .PHY芯片初始化和RGMII协议
1.PHY芯片的初始化
VSC8601芯片上电后需要复位,芯片上电一段时间后复位信号需要保持高电平,否则PHY芯片不工作,配置过程如图。PHY的复位信号引脚与FPGA相连,PHY芯片的复位引脚上电后至少4ms就可以置高,从而完成PHY芯片的初始化,相当简单。
2.PHY芯片的RGMII协议
RGMII协议是PHY芯片和FPGA芯片之间的传输协议。RGMII是还原GMII。RGMII采用4位数据接口,工作频率为125MHz,在上升沿和下降沿都传输数据。数据传输速率可达4*125*2=1000Mbps。同时兼容MII规定的10/100 Mbps工作模式,支持10M/100M/1000Mb/s的传输速率,对应的clk信号分别为2.5MHz/25MHz/125MHz。RGMII数据结构符合IEEE以太网标准,接口定义见IEEE 802.3-2000。
PHY芯片与现场可编程门阵列数据交互的端口包括发送端、接收端和HPY复位端口。发射端和接收端分别有6个连接到现场可编程门阵列的引脚、1个时钟引脚、1个数据控制使能引脚和4个数据引脚。当我们想要达到1.0Gb/s的带宽时,对应于HPY的时钟是125兆赫兹。如果是单边沿采样,带宽为125M/s*4=500Mb/s,小于1.0 GB/s,如果我们想在原有硬件的基础上用125M时钟产生1.0Gb/b的带宽,需要双边沿控制采样数据,时钟上升沿为4位,下降沿为4位。协议是RGMII。RGMII采用4位数据接口,工作在125MHz,同时在上升沿和下降沿传输数据,因此传输速率可以达到1000Mbps。RGMII无补偿工作顺序如图。
查看图中的RX_CLK和RX_CLK,RX_CLK为HPY时钟,对应的输出数据为上升沿的RXD[3:0]和RXDV,对应的数据为下降沿的RXD[7:4]和RXERR,一个时钟周期对应8位、一个有效使能和一个误差信号。RX_CLK是在RX_CLK的基础上相移90°左右得到的,所以采集的数据会更稳定。
四.IDDR原语
PHY传输的数据是双边数据,而FPGA通常处理单边数据。因此,FPGA在接收到图像包后,需要使用IDDR原语将双边数据转换为单边数据。FPGA处理数据所用的时钟一般是晶振产生的时钟,而PHY传输的数据和IDDR原语后转换成单沿的数据与PHY时钟同步。因此,如果我们想使用FPGA时钟作为后续的图像数据处理,我们必须跨越时钟域,将PHY时钟同步数据转换为FPGA时钟同步数据。这里双边到单边数据采用Input DDR原语(简称IDDR),将双边4位数据转换为单边8位数据。
IDDR原语参考了7系列FPGA选择资源文档和Xilinx 7系列FPGA库指南,用于HDL设计。
1.访问IDDR原语
2.IDDR原语接口和属性
d为数据输入,CE为IDDR工作使能,C为时钟,S和R分别置位和复位。
3.IDDR原始工作模式
IDDR有三种工作模式,如下图所示:对立_边缘、同一_边缘、同一_边缘_流水线。
通过比较三种图的差异,结合本项目的平台,选择了模式:SAME _ EDGE _ PIPELINED。因为时钟的上升沿和下降沿分别对应一个数据,千兆以太网数据传输:0位和4位为一组,1位和5位为一组,2位和6位为一组,3位和7位为一组。
4、IDDR双边数据到单边数据的使用
根据硬件电路图,PHY向现场可编程门阵列传输一条时钟线、一条使能线和四条数据线,其中使能线和数据线为双边数据。使能线包含DV和ERR,其中上升沿传输DV信号,下降沿传输ERR信号。四条数据线始终包含8位数据,其中上升沿传输8位数据的[3:0],下降沿传输8位数据的[7:4]。我们使用IDDR原语将双边4位数据转换为8位数据,提取8位数据对应的有效DV信号。然后可以建立一个实现双边到单边功能的模块:iddr_ctrl,其中输入输出关系如下图所示。从phy芯片发送的phy_rxd和phy_rx_ctl与phy时钟同步。在图中,phy时钟偏移90度后形成以phy_rx_clk_90为输入的时钟信号,以更稳定地获取phy_rx_rxd和phy_rx_ctl,并对该模块输出的单边沿8-8位数据和相应数据有效使能rx_data和rx_en。
下图为千兆以太网数据传输IDDR后,8位数据rx_data与使能rx_en的对应关系。
从图中可以看出,在IDDR时钟上升沿采集的phy_rx_crl信号为en,表示数据有效,下降沿采集的ERR信号表示数据错误。本项目这里不考虑误差信号,IDDR最终输出的rx_en信号正好对应拼接后的rx_data数据,可以有效使能为8-8位数据。
动词 (verb的缩写)上板验证
代码写完后注意。据说对于PHY芯片的初始化,PHY芯片的复位引脚至少要上电4毫秒后才能置高。因此,PHY芯片的复位引脚必须设置在顶层,延迟4ms后才能产生该信号。有了这个信号,PHY芯片就可以工作了。
//start phy _ rst _ nal way @ begin if begin phy _ rst _ CNT end else if begin phy _ rst _ cntendendedassign phy _ rst _ n = phy _ rst _ CNT[18];这个实验很简单,看不到任何现象。你可以形成一个ila,把rx_data和rx_en放进去观察,最后别忘了绑定管脚。生成位文件后,将其下载到电路板。主板上的网络端口与计算机网络端口相连。单击计算机中的以太网设置-更改适配器选项,您可以看到网卡工作正常。
看ila,使用rx_en的上升沿作为触发信号,获得以下波形:
从图中可以观察到,千兆以太网数据是以包的形式发送的,每次都有一定的数据量,每次传输之前,会有7个0x55s和1个0xd5作为包的针发送。如果是这样的波形,说明这个实验的设计是成功的。
接收——包校验和数据筛选之前我们意识到FPGA板可以接收以太网数据,但是里面的数据比较混乱,可能会出现无效帧。即使是有效的帧也不是我们想要的全部数据,所以我们必须对数据进行过滤。这个博客详细记录了以太网数据的验证和过滤。
一、数据传输
我们用Matlab软件实现计算机向以太网发送数据,FPGA板接收数据。网上有很多具体的节目,我就不贴了。
二、数据验证和筛选
1.UDP以太网结构
以太网是分组发送的,每个分组的结构如下图所示。有帧头、MAC头、IP头、UDP头、用户数据、帧尾等。稍后,我们将使用这些数据来检查和过滤出我们需要的值。
2.包装有效性检查
如上图所示,蓝色部分是我们包裹的有效检查区域。如果包发送数据,并且蓝色位置的5-5字节数据与标准值相同,则包可以被认为是有效的。
总是@ begin if begin pkg _ vld _ value end else if)begin//UDP,端口源,端口目标pkg _ vld _ valueend 总是@ begin if begin pkg _ vld end else if begin pkg _ vld end else begin pkg _ vld end end end 3 .循环冗余校验
CRC校验是为了证明一个数据包是否有错,大部分是8位或者32位。这次用的是32位的CRC校验,但是记住,只能用来验证数据是否有错,不能用来纠正错误。此外,循环冗余校验是在删除帧头的8字节数据后进行的检查。下面是一个32位的CRC校验模块。请注意,用于检查和去检查的电路的默认初始状态是32 ' hffffffff,即所有1状态。千兆以太网验证结果为32'hc704dd7b。模块可以具体情况具体使用,但实际CRC校验的科学原理略超前,这里不做说明。
总是@ begin if begin Crc32 _ value end else if begin Crc32 _ value[0]Crc32 _ value[1]Crc32 _ value[2]Crc32 _ value[3]Crc32 _ value[4]Crc32 _ value[5]Crc32 _ value[6]Crc32 _ value[7]Crc32 _ value[8]Crc32 _ value[9]Crc32 _ value[10]Crc32 _ value[11]Crc32 _ value[12]Crc32 _ value数据过滤
从上图可以看出,只有中间红色部分的“用户数据”才是我们真正需要的,所以最终的输出结果需要筛选,从头到尾都不难。
第三,代码设计
上面贴了一些代码。我必须把所有代码都贴在这里吗?不,粘贴代码没有意义。理解内在含义很重要。我们将这个模块命名为rx_filter。rx_filter的输入是上节课网络端口数据转换后的8-8位数据值和对应的使能,输出是验证过滤后的数据和使能。
代码本身并不难验证上面提到的包有效性和CRC。它可以通过用计数器计算传入的数据,然后比较这些关键节点来启用。但是需要同时检查数据,可能会导致定时错误。因此,需要先建立一个data_fifo缓冲数据,然后进行包有效校验和CRC校验。data_fifo的深度可以更深,例如8192,这样就可以容纳多个帧。验证后,需要判断是否丢弃数据包,因此需要另一个status_fifo来存储验证信息。同时,只要status_fifo从空变为not 空,就意味着包验证信息已经写入,即包验证完成,所以status_fifo的读使能直接设计为让信息数据出来,并使用一个寄存器供以后使用。status_fifo的读使能可用后,应立即设计data_fifo的读使能,以避免各种新的数据包不断进入data_fifo,不会发生猝发。请注意,data_fifo的读取使能持续时间应该与数据进入时的数据使能时间一样长,因此不可能在计数之前进行计数,必须保存完整数据包的长度。怎么存?只需注册长度,并将其与数据包有效性检查和CRC检查一起写入status_fifo,然后status_fifo就可以读出数据供我们使用。现在data_fifo一直在写和读数据,status_fifo一直在写和读信息数据。下一步,我们可以用读取的信息数据来判断里面的信息是否真的OK。如果真的可以,那么data_fifo的数据和它的读使能被消除,留下“用户数据”的中间部分重新传输。如果不正常,则让data_fifo读使能。原理图如下:
波形图如下所示。结合以上,如果你理解了下面的波形图,模块就没事了。
四.波形
要申请一个ila观测数据,Matab可以发一块0-255的数据,看看我们的包有没有问题。波形图如下:
动词 (verb的缩写)以太网+DDR3+HDMI显示器
结合千兆以太网上一讲和本讲,取代之前DDR3项目中的串口发送模块,可以实现以太网+DDR3+HDMI显示,特别注意输出端口、时钟连接和引脚约束。
好了,到目前为止,这个项目已经完成了一半!
发送——组建以太网心跳包心跳包是一个自定义的命令字,在客户端和服务器之间定期通知对方自己的状态,并以一定的时间间隔发送,类似于心跳,所以称为心跳包。心跳包广泛应用于GPRS通信和CDMA通信中。数据网关定期清理没有数据的路由,心跳包通常设置在30-40秒之间。所谓心跳包,就是客户端定期向服务器发送简单的消息,告诉它我还在。代码是每隔几分钟向服务器发送一条固定消息,服务器收到后会回复一条固定消息。如果服务器在几分钟内没有收到客户端消息,客户端将会断开连接。在本设计中,心跳包时间间隔为1秒。
一、心跳包触发
一秒计时器被设计成每隔一秒产生一个心跳包触发脉冲,用于下一个心跳包构造。
二、心跳包的大致框架
该以太网的心跳包结构如下:
这次发送64个全零的数据。当然,这个数据是用户自定义的,所以心跳包的总长度是118。另外,目的/源MAC地址、目的/源IP地址、目的/源端口等。可以用参数的形式写。使用刚刚设计的心跳包触发脉冲,我们可以设置这个心跳包。表格中的黄色部分是需要以后验证的值。可以先填0,后面再补这三个地方。代码没什么好说的,就用参数和case语句。
点按电脑的Win+R键,输入cmd,然后输入并退出ipconfig -all,按回车键查看电脑的MAC地址等参数。
三、心跳包填充:IP校验和UDP校验
1.知识产权验证方法
IP校验就是把IP头20个字节分成2个字节,加上去。如果结果大于16'hffff,超过16'hffff的部分将与加法结果的低16位相加,直到最终结果小于16'hffff。最后,小于16'hffff的结果被否定为ip_checksum。高字节在前,低字节在后。替换之前心跳包里填的0。
校验和字段清零
假设以太网数据包前面的IP校验和字段没有被清除为0,而是分配了其他值,例如,IP报头是:45 00 00 30 80 4C 40 00 80 06 B52ED 3 43 11 7BCB 51 153D,b5 2e字段是IP校验和字段,清除为0后,数据变为:45 00 00 30 80 4C 40 00 80 0600 00D 3 43 11 7BCB 51 153D。
逆求和
4500+0030+804 c+4000+8006+0000+d343+117 b+cb51+153d = 34 ace,超过16 ' hffff的部分加到低16位,结果是:3+4ace=4ad1。因为4ad1比ffff小,所以它被认为是
反转以获得最终结果
将4ad1反相得到b52e,b52e是这个包数据的最终IP校验和,然后将b52e填充到相应的位置。
2.UDP验证方法
验证方法
UDP_checksum计算稍微复杂一点,需要添加IP伪头,将IP伪头、8字节的UDP头和数据包部分除以2字节再相加。如果结果大于16'hffff,超过16'hffff的部分将与加法结果的低16位相加,直到最终结果小于16'hffff。最后,小于16'hffff的结果被否定为UDP_checksum。高字节在前,低字节在后。替换之前心跳包里填的0。
UDP结构
UDP_checksum组成如图。
可以看出,IP伪报头包含IP源地址、IP目的地址、一个字节的0、协议号和UDP_len。之前的千兆以太网镜像传输项目中,IP源地址、IP目的地址、协议号都是固定的,而之前的博客设计的UDP_len是:UDP头8字节+数据长度64字节= 8+64="h0048。设计时,IP伪头可以单独计算。
3.计算时间
Ip_checksum和udp_checksum都是计算出来的,数据填充位置已经过了,所以没有办法将数据填充到原来的填充位置0,但是我们想做成一个完整的以太网包,这是必然的,那么应该怎么解决呢?我们可以考虑设置一个足够大的RAM,在计算ip_checksum和udp_checksum的同时,将之前的心跳包数据存储在RAM中,在这个包中的数据全部计算完之后,读出RAM中的数据。当要用ip_checksum和udp_checksum填充的位置被读出时,将计算出的两个值反转并填充到相应的位置。
4.时间图
四、心跳包填充:CRC校验
1.循环冗余校验范围
循环冗余校验从另一段开始,因为必须首先计算先前的ip校验值和UDP校验值。检查CRC时,需要先去掉帧头和帧尾。当计算循环冗余校验值时,它可以填充到数据的最后4位。
2.循环冗余校验方法
CRC校验初始值和空空闲值都设置为32 ' hffffffff,即所有1状态。
计算结果需要在高位和低位之间切换,因为我们是先从高位输入的,所以最后需要切换高位和低位。
最终结果反转,高低位后的结果反转,即可得到CRC校验值。
第3部分,循环冗余校验代码
总是@ begin if begin Crc32 _ value end else if begin Crc32 _ value[0]Crc32 _ value[1]Crc32 _ value[2]Crc32 _ value[3]Crc32 _ value[4]Crc32 _ value[5]Crc32 _ value[6]Crc32 _ value[7]Crc32 _ value[8]Crc32 _ value[9]Crc32 _ value[10]Crc32 _ value[11]Crc32 _ value[12]Crc32 _ value时间图
由于这次CRC校验值在末尾,所以可以不使用RAM及时填充。
此时,我们设置好以太网发送的心跳包,接下来就可以发送了。
发送——ODDR原语和Wireshark抓包工具I. ODDR原语
FPGA传输的数据是单边数据,而PHY传输的数据是双边数据,所以在FPGA发送心跳包的最后要用ODDR原语把单边数据转换成双边数据。FPGA处理数据所用的时钟一般是晶振产生的时钟,FPGA传输的数据经过ODDR原语转换成双边沿数据,与PHY时钟同步。因此,如果要将FPGA时钟的数据传输到PHY芯片,需要跨时钟域将FPGA时钟同步的数据转换成PHY时钟。这里单边到双边数据采用Output DDR原语(简称ODDR),将单边8位数据转换为双边4位数据。
ODDR原语参考了7系列FPGA选择资源文档和Xilinx 7系列FPGA库指南,用于HDL设计。
1.对ODDR原语的访问
2.ODDR原语接口和属性
D1和D2为数据输入,CE为ODDR操作使能,C为时钟,S和R分别置位和复位,Q为输出。
3.ODDR原始工作模式
ODDR有两种工作模式,如下图所示,分别是对立_边缘和同一_边缘。
在相反_边沿模式下,两个边沿都用于捕获数据,其中上升沿捕获低数据D1,下降沿捕获高数据D2,输出Q在上升沿传输D1,在下降沿传输D2。在SAME_EDGE模式下,仅使用上升沿来捕获低阶数据D1和高阶数据D2,然后在输出Q的下降沿传输D1,在上升沿传输D2。我们采用相同的边缘模式进行传输。
4.ODDR双边数据到单边数据的使用
根据硬件电路图,PHY向现场可编程门阵列传输一条时钟线、一条使能线和四条数据线,其中使能线和数据线为双边数据。使能线包含DV和ERR,其中上升沿传输DV信号,下降沿传输ERR信号。四条数据线始终包含8位数据,其中上升沿传输8位数据的[3:0],下降沿传输8位数据的[7:4]。我们使用ODDR原语,将单边8位数据转换为双边4位数据,提取出4位数据对应的有效DV信号。然后可以建立一个模块,实现单边到双边的功能:oddr_ctrl,其中输入和输出的关系如下。最后,PHY芯片发送的PHY _ txd和PHY_tx_ctl与时钟phy_tx_clk同步。图中,FPGA时钟偏移90度后形成以sclk_90为输入的时钟信号,使得phy_tx_rxd和phy_tx_ctl之间的转换更加稳定,对于该模块输入的单边沿8-8位数据及相应数据,tx_dat和tx_en有效使能。
二、以太网复位信号
之前的博客“千兆以太网”说,PHY芯片的reset引脚至少要上电4ms后才能置高。因此,输出端口不应忘记phy芯片的复位信号phy_rst_n,该信号可以产生4 ms的延迟。有了该信号,PHY芯片就可以工作。
//start phy _ rst _ nal way @ begin if begin phy _ rst _ CNT end else if begin phy _ rst _ cntendendedassign phy _ rst _ n = phy _ rst _ CNT[18];
第三,Wireshark抢了包
打开上层板卡后,点击电脑中的以太网设置-更改适配器选项,可以看到网卡工作正常。
打开Wireshark软件,可以看到以太网的波形在变化。
双击进入,单击编辑-首选项,然后单击NTP查看我们的端口号。这个设计是UDP,为什么是NTP?因为NTP实际上包含UDP,所以可以看作UDP的一种。
点击UDP和IPv4,检查UDP和IP验证,稍后会看到验证是否成功。
然后我们重新捕获以太网,可以看到很多蓝色的部分代表我们传输的心跳包,黑色的不是我们的。它的来源和目的地与我们设定的不同,所以我们不在乎。单击蓝色条纹,相关信息会显示在下面。该信息从报头中删除,因此字节显示为106,这与我们的设计一致。此外,我们可以看到头部检查分别显示[正确]和[良好],表明我们这次检查是正确的。
以上现象说明我们的千兆以太网传输项目已经成功实现。
本文分享自微信官方账号-Digital ICer。如有侵权,请联系support@oschina.cn删除。本文参与“OSC源码创作项目”,欢迎大家加入分享。