FPGA以太网学习-RGMII与GMII

news/2024/10/6 2:36:22/文章来源:https://www.cnblogs.com/cjl520/p/18229632

以太网口都叫RJ45接口,从功能角度说,网口只是信号连接,本身没有通信能力。

PHY(物理层),这边需要一个芯片,将并行的以太网数据到符合以太网物理层链路数据传输格式的电平信号转换。

上图PHY右边是经过编码后的串行数据信号,左侧是提供多种并行信号。网络变压器连接串行信号和网口。

MII接口(百兆/十兆接口)

MAC向PHY侧传输数据的时序图如下

 


MII 介质无关接口

MAC 介质访问接口

RTL8211F-CG是一款支持 RGMII 接口的以太网物理层收发器,能够工作在 10M、100M 或 1000M Base模式,对 MAC 层可提供 RGMII 接口模式,并提供了标准的 MDIO 管理接口与处理器相连。

以太网物理层芯片都有一个器件地址,该器件地址就是在介绍 PHY 管理接口 MDIO 时所说的 PHY 器件地址,该器件地址用来由 MDIO 主机(如 MAC 或处理器)寻址 MDIO 总线上连接的指定的 PHY 芯片。

对于 RTL8211F-CG 芯片,该地址分为固定部分和硬件可设定两部分。器件地址共有 5 位,其中高 2 位为固定的 00,低三位通过三个地址设置脚在芯片上电或复位时候设置, 这三位分别对应 RTL8211F 芯片的 22、27、26 脚。下表为这三个脚功能说明。

注意:手册里下面这个话好像写错了,PHY_ADDR1通过电阻下拉到低电平,其他两个通过电阻上拉到高电平。

所以器件地址为00101.


以太网MAC帧协议介绍

以太网技术的正式标准是 IEEE802.3 标准,它规定了在以太网中传输的数据帧结构,如下图所示。

从目的地址开始到数据和填充字段的最后一个为止,这些跟CRC进行计算。不包括前同步码和分隔符。

前导码的作用是为了标记一帧以太网帧即将开始传输,分隔符存在的意义是指前导码传输完毕。

MC地址对应,一对一,多播,广播。MAC地址,每个设备都唯一,需要向美国IEEE申请。48位地址,前24位IEEE指定,后24位设备厂商自行定义。

以太网中的数据部分,一般都在另一个上层协议,如TCP/IP协议。用户数据都是包含在该上层协议中。


RGMII 接口信号与时序

这个RGMII和GMII的互转,是因为需要使用RGMII并行传输协议,RGMII是上下沿采样,所以是双倍于GMII的速度

在PHY和MAC层之间传输并行数据的方法。所以从PHY到MAC这边是RGMII转GMII,从MAC到PHY这边是GMII转RGMII

用下面这个回环测试的示意图能看出来。

1、网口连接电脑以太,从电脑这边发一个数据,经过PHY串转并,通过RGMII转GMII进入,然后输出来之后,给GMII转RGMII就行了

RGMII数据在时钟的上升沿和下降沿均进行采样。

数据边沿对齐的形式使得 PCB 设计变得更加的复杂,所以,后来的 PHY 芯片都针对 RGMII接口提供了可选的内部延迟电路。(暂时不理解)

RGMII调用FPGA的ODDR原语,实现输出DDR寄存器,实例化原语就会自动访问该功能。

端口信号

ODDR属性

 

直接看代码(写注释里面)

这个跟TB文件中的代码对应,

rgmii_to_gmii.v
module rgmii_to_gmii(reset,            //复位信号rgmii_rx_clk,     //接收数据参考时钟,由PHY输出过来的rgmii_rxd,        //PHY传向MAC的数据[3:0]rgmii_rxdv, //在RX_CTL里面的,传输GMII中的RX_DV和RX_ER信号gmii_rx_clk,  //gmii的参考时钟,跟RGMII的对应就行了gmii_rxdv,    //Reveive Data Valid,接收数据有效信号,作用类似于发送通道的TX_ENgmii_rxd,    //接收数据gmii_rxer     //接收错误error,高电平有效
);input         reset;input         rgmii_rx_clk;input  [3:0]  rgmii_rxd;input         rgmii_rxdv;output        gmii_rx_clk;output [7:0]  gmii_rxd;output        gmii_rxdv;output        gmii_rxer;wire          gmii_rxer_r;assign gmii_rx_clk = rgmii_rx_clk;   //时钟狠狠同步genvar i;generatefor(i=0;i<4;i=i+1)begin: rgmii_rxd_iIDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // "OPPOSITE_EDGE", "SAME_EDGE" // or "SAME_EDGE_PIPELINED" Q1Q2变化发生在同一个上升沿,都是下一个.INIT_Q1(1'b0   ),  // Initial value of Q1: 1'b0 or 1'b1,默认0.INIT_Q2(1'b0   ),  // Initial value of Q2: 1'b0 or 1'b1.SRTYPE ("SYNC" )   // Set/Reset type: "SYNC" or "ASYNC" ,这是默认) IDDR_rxd (.Q1   (gmii_rxd[i]   ), // 1-bit output for positive edge of clock,低4位.Q2   (gmii_rxd[i+4] ), // 1-bit output for negative edge of clock,高4位.C    (rgmii_rx_clk  ), // 1-bit clock input,rgmii参考时钟.CE   (1'b1          ), // 1-breset_nit clock enable input.D    (rgmii_rxd[i]  ), // 上升沿传GMII的RXD的低4位,下降沿传高4位.R    (reset         ), // 1-bit reset.S    (1'b0          )  // 1-bit set,复位,高电平有效);endendgenerateIDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // "OPPOSITE_EDGE", "SAME_EDGE" // or "SAME_EDGE_PIPELINED" //Q1Q2变化发生在同一个上升沿,但是都是下一个上升沿.INIT_Q1(1'b0   ),  // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2(1'b0   ),  // Initial value of Q2: 1'b0 or 1'b1.SRTYPE ("SYNC" )   // Set/Reset type: "SYNC" or "ASYNC" ) IDDR_rxdv (.Q1   (gmii_rxdv), // 1-bit output for positive edge of clock.Q2   (gmii_rxer_r), // 1-bit output for negative edge of clock.C    (rgmii_rx_clk ), // 1-bit clock input.CE   (1'b1         ), // 1-breset_nit clock enable input.D    (rgmii_rxdv   ), // 1-bit DDR data input,这个就对应RX_CTL的,因为上升沿传DV,下降沿传ER//.R    (reset        ), // 1-bit reset.S    (1'b0         )  // 1-bit set);assign gmii_rxer = gmii_rxer_r^gmii_rxdv; //异或,相异为1.
endmodule
rgmii_to_gmii_tb.v
 `timescale 1ns / 1ps
`define CLK_PERIOD 8module rgmii_to_gmii_tb();reg  reset;wire gmii_rx_clk;reg [3:0] rx_byte_cnt;//接收比特计数wire [7:0] gmii_rxd;wire gmii_rxdv;wire gmii_rxer;wire rgmii_rx_clk;reg [3:0] rgmii_rxd;reg rgmii_rxdv;reg rx_clk;wire locked;rgmii_to_gmii rgmii_to_gmii(.reset(reset),.gmii_rx_clk(gmii_rx_clk),  .gmii_rxdv(gmii_rxdv),.gmii_rxd(gmii_rxd),.gmii_rxer(gmii_rxer),.rgmii_rx_clk(rgmii_rx_clk),.rgmii_rxd(rgmii_rxd),.rgmii_rxdv(rgmii_rxdv)  //RX_CTL);//对rgmii_rx_clk时钟进行90度相位调制,以保证该时钟到达IDDR时候//与rgmii_rxd和rgmii_rxdv信号成中心对齐关系。//其实就是为了能够在对rgmii_rx_clk上升沿和下降沿的时候,正好处在rgmii_rxd的值的中心位置采样。rx_pll rx_pll(// Clock out ports.clk_out1(rgmii_rx_clk),     // output clk_out1,90度相位调制// Status and control signals.reset(reset), // input reset.locked(locked),       // output locked,是时钟稳定的信号// Clock in ports.clk_in1(rx_clk)      // input clk_in1);//clock generateinitial rx_clk = 1'b1;always #(`CLK_PERIOD/2)rx_clk = ~rx_clk;  //每4ns转,周期8nsalways@(rx_clk or posedge reset)if(reset)rx_byte_cnt <= 4'd0;else if(rgmii_rxdv && locked)   //RX_CTL的rx_byte_cnt <= rx_byte_cnt + 1'b1;   //16个数据elserx_byte_cnt <= 4'd0;always@(*)begincase(rx_byte_cnt)16'd0  : rgmii_rxd = 12;16'd1  : rgmii_rxd = 7;16'd2  : rgmii_rxd = 9;16'd3  : rgmii_rxd = 6;16'd4  : rgmii_rxd = 11;16'd5  : rgmii_rxd = 15;16'd6  : rgmii_rxd = 0;16'd7  : rgmii_rxd = 8;16'd8  : rgmii_rxd = 4;16'd9  : rgmii_rxd = 2;16'd10 : rgmii_rxd = 5;16'd11 : rgmii_rxd = 1;16'd12 : rgmii_rxd = 3;16'd13 : rgmii_rxd = 10;16'd14 : rgmii_rxd = 14;16'd15 : rgmii_rxd = 13;endcaseendinitialbeginreset = 1;rgmii_rxdv = 0;#201;reset = 0;   //因为PLL时钟的RESET信号,高电平有效rgmii_rxdv = 1;#2000; $stop;endendmodule

1、这边看到计数0的时候,RGMII_RXD的值是12(C),在RGMII_RX_CLK的上升沿传输低4位,下降沿传输高四位

2、以第一个GMII的数据为例,上升沿C,下降沿7,因为是SAME_EDGE_PIPELINED,所以Q1Q2在下一个上升沿发生变化,在GMII_RXD这边就是7C的呈现。

3、时钟偏90度相位,我的理解就是方便采样取值

 

下面是GMII转RGMII接口。

gmii_to_rgmii.v
 /*例化6个ODDR就可以实现,其中4个用来发送4个TXD信号
一个用来发送TXEN和TXER信号
一个用来输出TX_CLK信号*/
module gmii_to_rgmii(reset_n,gmii_tx_clk,   //gmii发送参考时钟,mac提供gmii_txd,      //gmii_txd[7:0]gmii_txen,    //发送使能gmii_txer,    //发送错误信息rgmii_tx_clk,rgmii_txd,     rgmii_txen     //tx_ctl,上升沿传tx_en,下降沿传tx_er
);input        reset_n;input        gmii_tx_clk;input  [7:0] gmii_txd;input        gmii_txen;input        gmii_txer;output       rgmii_tx_clk;output [3:0] rgmii_txd;output       rgmii_txen;genvar i;  //generate必须是用这个genvar定义参数generatefor(i=0;i<4;i=i+1)begin: rgmii_txd_oODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT  (1'b0   ),          // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC" )          // Set/Reset type: "SYNC" or "ASYNC" ) ODDR_rgmii_txd (.Q   (rgmii_txd[i]     ), // 输出RGMII的TXD.C   (gmii_tx_clk      ), // gmii的发送时钟.CE  (1'b1             ), // 使能.D1  (gmii_txd[i]      ), // GMII_TXD的低4位.D2  (gmii_txd[i+4]    ), // GMII_TXD的高4位.R   (~reset_n         ), // 复位,因为复位reset跟set,高电平有效,所以reset=0的时候,这边才复位.S   (1'b0             )  // 高电平有效,不设置);endendgenerateODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT  (1'b0   ),           // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC" )            // Set/Reset type: "SYNC" or "ASYNC" ) ODDR_rgmii_txd (.Q   (rgmii_txen          ), // 1-bit DDR output.C   (gmii_tx_clk         ), // 1-bit clock input.CE  (1'b1                ), // 1-bit clock enable input.D1  (gmii_txen           ), // 上升沿采集txen信号.D2  (gmii_txen^gmii_txer ), // RGMII的TX_CTL传输GMII的TX_EN 和 TX_ER 两种信息,TX_CLK 的上升沿发送 TX_EN,下降沿发送 TX_ER//.D2  (gmii_txer ),//所以这边D2应该GMII_TXER也可以,等会仿真看看.R   (~reset_n            ), // 1-bit reset.S   (1'b0                )  // 1-bit set);//这边对于RGMII_TX_CLK的输出,也是用ODDR输出,而不是PLL产生。
//优势在于最大程度保证输出的RGMII_TX_CLK与RGMII_TXD[3:0]保持边缘对齐
//前面的TXD和CLK都能ODDR输出,可以保证传输路径的时序模型完全一致ODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT  (1'b0   ),           // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC" )            // Set/Reset type: "SYNC" or "ASYNC" ) ODDR_rgmii_clk (.Q   (rgmii_tx_clk  ), // 1-bit DDR output.C   (gmii_tx_clk   ), // 1-bit clock input.CE  (1'b1          ), // 1-bit clock enable input.D1  (1'b1          ), // 1-bit data input (positive edge).D2  (1'b0          ), // 1-bit data input (negative edge).R   (~reset_n      ), // 1-bit reset.S   (1'b0          )  // 1-bit set);endmodule
gmii_to_rgmii_tb.v
 `timescale 1ns / 1ps
`define CLK_PERIOD 8module gmii_to_rgmii_tb();reg  reset_n;reg gmii_tx_clk;reg [3:0] tx_byte_cnt;  //发送数据计数reg [7:0] gmii_txd;    //发送数据reg gmii_txen;reg gmii_txer;wire rgmii_tx_clk;wire [3:0] rgmii_txd;wire rgmii_txen;gmii_to_rgmii gmii_to_rgmii(.reset_n(reset_n),.gmii_tx_clk(gmii_tx_clk),.gmii_txd(gmii_txd),.gmii_txen(gmii_txen),.gmii_txer(gmii_txer),.rgmii_tx_clk(rgmii_tx_clk),.rgmii_txd(rgmii_txd),.rgmii_txen(rgmii_txen));//clock generate//每4ns翻转一次,周期8nsinitial gmii_tx_clk = 1'b1;always #(`CLK_PERIOD/2)gmii_tx_clk = ~gmii_tx_clk;always@(posedge gmii_tx_clk or negedge reset_n)if(!reset_n)tx_byte_cnt <= 4'd0;else if(gmii_txen) //如果gmii的发送使能,计数开始tx_byte_cnt <= tx_byte_cnt + 1'b1;elsetx_byte_cnt <= 4'd0;always@(*)begincase(tx_byte_cnt)  //计数16次,分别赋值的发送数据16'd0  : gmii_txd = 25;16'd1  : gmii_txd = 34;16'd2  : gmii_txd = 18;16'd3  : gmii_txd = 96;16'd4  : gmii_txd = 78;16'd5  : gmii_txd = 29;16'd6  : gmii_txd = 63;16'd7  : gmii_txd = 42;16'd8  : gmii_txd = 51;16'd9  : gmii_txd = 74;16'd10 : gmii_txd = 39;16'd11 : gmii_txd = 60;16'd12 : gmii_txd = 27;16'd13 : gmii_txd = 36;16'd14 : gmii_txd = 145;16'd15 : gmii_txd = 231;endcaseendinitialbeginreset_n = 0;gmii_txen = 0;gmii_txer = 0;#201;reset_n = 1;gmii_txen = 1;#2000; $stop;endendmodule

1、gmii_txd的第一个数据是19(其实是0001 1001)换算十进制就是25,用的SAME_EDGE,所以是时钟上升沿取D1D2(低四位高四位),然后依次在一个时钟周期内赋值给Q

2、可以看到RGMII_TXD是先9再1,而9是上面的低4位,1是上面的高4位,且是在同一个时钟周期。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/739836.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络通信系统的voronoi图显示与能耗分析matlab仿真

1.程序功能描述两层基站(BS)组成整个通讯网络,第 1 层为 Macro 基站记为 ,第 2 层为 Micro 基站记为 ,均服从泊松分布,相互独立,在坐标为 1010km 的面积内、按照泊松分布随机生成若干个点(随机抛洒两遍 nodes,两层叠加起来)。然后画成 voronoi 图: 也就是在相邻两个…

Django详细笔记

django 学习 特点快速开发 安全性高 可伸缩性强URL 组成部分 URL: 同意资源定位符 一个URL由以下几部分组成 scheme://host:port/path/?query-string=xxx#anchorscheme: 代表的是访问的协议,一般为http或https协议 host: 主机名,域名 port: 端口 http 默认:80端口 …

关于虚拟机的使用

1、从网上下载了Centos7 2024年CentOS镜像下载地址,包括CentOS官网、国内镜像下载,超详细教学,小白也能学会。-CSDN博客 2、通过VMware添加了该iso文件,打开虚拟机之后安装该系统就可以了 3、进入之后我们需要进行软件安装、安装位置、KDUMP、网络和主机名的修改操作其中,…

LSTUR论文阅读笔记

Neural News Recommendation with Long- and Short-term User Representations论文阅读笔记 这个同样是一篇很老但是比较经典的文章,这里来读一下 Abstract 存在的问题: ​ 用户通常既有长期偏好,也有短期兴趣。然而,现有的新闻推荐方法通常只学习用户的单一表征,这可能是…

实战篇——文件包含漏洞一

实战篇——文件包含漏洞(1) 本地文件包含 本地文件包含一般需要依赖文件上传漏洞。如果文件上传漏洞限制上传文件的后缀必须为.jpg,那么配合本地文件包含,就可以通过上传图片木马获得服务器权限。 上传图片木马:利用本地文件包含,成功连接一句话木马:可见本地文件包含最大…

XShell连接失败解决

实现:宿主机的 Windows 和虚拟机的 Linux 能够进行网络连接,同时虚拟机的 Linux 可 以通过宿主机的 Windows 进入互联网简而言之:Windows 和虚拟机的 Linux能够互相ping成功解决的问题:XShell连接不成功第一步:编辑 VMware 的网络配置然后全部点击确定,VMware 的网络配置…

基于负相关误差函数的4集成BP神经网络matlab建模与仿真

1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 MATLAB2022a3.部分核心程序while(Index<=Max_iteration) Indexjj=1; error2 = zeros(Len,KER);while(jj<=Len) for k=1:No;d(k)=T(jj); endfor i=1:NI;x(i)=P(jj,i);end%集成多个BP神经…

9、flask-会话-cookie

Cookie 客户端的会话技术: - cookie本身由浏览器保存,通过response将cookie写道浏览器上、下一次访问时、浏览器会根据不同的规则携带cookie过来特点: - 客户端的会话技术、浏览器的会话技术 - 数据全都是存储在客户端中 - 存储使用的键值对结构进行的存储 - 特性:- 支持过…

# Day02

1. #盘符转换 2. #查看当前目录下的所有文件 dir 3. #切换目录 cd change directory 4. #返回上一级 cd.. 5. #进入目录下的一级文件 先用第二步查看目录下的文件 然后cd+空格+一级文件名称 6 .#进入一级文件下的二级文件 方法同第五步 7. #清理屏幕 cls (简记clear screen) 8.…

dotnet WinUI3 Win2D 翻转图片

本文将告诉大家如何在 WinUI3 里面使用 Win2D 进行图片的翻转,本文的方法也适用于 UWP 框架图片的翻转在 Win2D 里面,可以使用 Transform2DEffect 特效来辅助实现,核心逻辑就是通过缩放矩阵当成2D翻转矩阵,将缩放的 X 和 Y 传入负数即可分别实现对应方向的翻转。比如左右水…

UWP WinUI 制作一个路径矢量图标按钮样式入门

本文将告诉大家如何在 UWP 或 WinUI3 或 UNO 里,如何制作一个路径按钮。路径按钮就是使用几何路径轮廓表示内容的按钮,常见于各种图标按钮,或 svg 系贴图矢量图按钮在网上有非常多矢量图库,其中免费的图库也非常多,比如 https://www.iconfont.cn/ 等等。在咱的应用程序里面…