【正点原子FPGA连载】第二十七章 MDIO接口读写测试实验 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

news2024/10/7 20:29:50

1)实验平台:正点原子MPSoC开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html

第二十七章 MDIO接口读写测试实验

在以太网通信中,设备之间的物理层链路均由PHY芯片(物理层芯片,本文指YT8521)建立。PHY芯片有一个配置接口,即MDIO接口,可以配置PHY芯片的工作模式以及获取PHY芯片的若干状态信息。本章我们来学习如何通过DFZU2EG/4EV MPSoC开发板实现对PHY芯片的MDIO接口进行读写测试。
本章分为以下几个章节:
212727.1简介
27.2实验任务
27.3硬件设计
27.4程序设计
27.5下载验证

27.1简介

以太网概述
以太网(Ethernet)是当今现有局域网采用的最通用的通信协议标准,该标准定义了在局域网中采用的电缆类型和信号处理方法。以太网凭借其成本低、通信速率高、抗干扰性强等优点被广泛应用在网络远程监控、交换机、工业自动化等对通信速率要求较高的场合。
以太网是一种产生较早,使用相当广泛的局域网。其最初是由Xerox(施乐)公司创建并由Xerox、Intel和DEC公司联合开发的基带局域网规范,后来被电气与电子工程师协会(IEEE)所采纳作为802.3的标准。
以太网的分类有标准以太网(10Mbit/s),快速以太网(100Mbit/s)和千兆以太网(1000Mbit/s)。随着以太网技术的飞速发展,市场上也出现了万兆以太网(10Gbit/s),它扩展了IEEE802.3协议和MAC规范,使其技术支持10Gbit/s的传输速率。在实际应用中,千兆以太网理论上最高通信速率为1000Mbit/s,可以胜任大部分的使用场景。
以太网通信离不开连接端口的支持,网络数据连接的端口就是以太网接口。以太网接口类型有RJ45接口,RJ11接口(电话线接口),SC光纤接口等。其中RJ45接口是我们现在最常见的网络设备接口(如:电脑网口),我们开发板使用的就是这种接口。
RJ45接口俗称“水晶头”,专业术语为RJ45连接器,由插头(接头、水晶头)和插座(母座)组成,属于双绞线以太网接口类型。RJ45插头只能沿固定方向插入,设有一个塑料弹片与RJ45插槽卡住以防止脱落。
RJ45接口样式如图 27.1.1所示:
在这里插入图片描述

图 27.1.1 RJ45插头(左)、插座(右)
RJ45接口定义以及各引脚功能在不同通信速率下的定义有区别,图 27.1.2是在10M/100M通信速率下的定义,由下图可知,RJ45插座只使用了1、2、3、6这四根线,其中1、2这组负责传输数据(TX+、TX-),而3、6这组负责接收数据(RX+、RX-),另外四根线是备用的。
在这里插入图片描述

图 27.1.2 RJ45插座10M/100M接口定义
而在1000M的通信速率下,RJ45插座的8根线都有用到,且都是双向引脚。需要说明的是,支持千兆网通信的RJ45接口是向下兼容的,即也支持10M/100M通信速率,只不过不同的通信速率,其引脚功能有区别。千兆网各引脚功能如下图所示:
在这里插入图片描述

图 27.1.3 RJ45插座1000M接口定义
从硬件的角度来说,以太网接口电路主要由MAC(Media Access Control)控制器和物理层接口PHY(Physical Layer,PHY)两大部分构成。MAC指媒体访问控制子层协议,它和PHY接口既可以整合到单颗芯片内,也可以独立分开,对于本次设计来说,MAC控制器由FPGA实现,PHY芯片指开发板板载的以太网芯片。
PHY在发送数据的时候,接收MAC发过来的数据(对PHY来说,没有帧的概念,都是数据而不管什么地址,数据还是CRC),把并行数据转化为串行流数据,按照物理层的编码规则把数据编码转换为模拟信号发送出去,接收数据时的流程反之。PHY还提供了和对端设备连接的重要功能,并通过LED灯显示出自己目前的连接状态和工作状态。当我们给网卡接入网线的时候,PHY芯片不断发出脉冲信号来检测对端是否有设备,它们通过标准的“语言”交流,互相协商并确定连接速度、双工模式、是否采用流控等。通常情况下,协商的结果是两个设备中能同时支持的最大速度和最好的双工模式。这个技术被称为Auto Negotiation,即自协商。
MDIO接口
MAC和PHY芯片有一个配置接口,即MDIO接口,可以配置PHY芯片的工作模式以及获取PHY芯片的若干状态信息。PHY芯片内部包含一系列寄存器,用户通过这些寄存器来配置PHY芯片的工作模式以及获取PHY芯片的若干状态信息,如连接速率、双工模式、自协商状态等。FPGA通过MDIO接口对PHY芯片内部的寄存器进行配置。通常情况下,PHY芯片在默认状态下也可以正常工作,在做以太网通信实验时,对MDIO接口的配置不是必须的,本章旨在向大家介绍MDIO接口以及如何对MDIO接口进行读写操作。MAC和PHY连接示意图如下图所示。
在这里插入图片描述

图 27.1.4 MDIO接口示意图
MDIO接口也称为SMI接口(Serial Management Interface,串行管理接口),包括ETH_MDC(数据管理时钟)和ETH_MDIO(数据管理输入输出)两条信号线。ETH_MDC为ETH_MDIO提供时钟,ETH_MDC的最大时钟不能超过12.5Mhz。ETH_MDIO为双向数据引脚,既用于发送数据,也用于接收数据。
MDIO接口的读写通信协议如下图所示:
在这里插入图片描述

图 27.1.5 MDIO接口通信协议
Preamble:32位前导码,由MAC端发送32位逻辑“1”,用于同步PHY芯片。
ST(Start of Frame):2位帧开始信号,用01表示。
OP(Operation Code):2位操作码,读:10写:01。
PHYAD(PHY Address):5位PHY地址,用于表示与哪个PHY芯片通信,因此一个MAC上可以连接多个PHY芯片。
REGAD(Register Address):5位寄存器地址,可以表示共32位寄存器。
TA(Turnaround):2位转向,在读命令中,MDIO在此时由MAC驱动改为PHY驱动,在第一个TA位,MDIO引脚为高阻状态,第二个TA位,PHY将MDIO引脚拉低,准备发送数据;在写命令中,不需要MDIO方向发生变化,MAC固定输出2’b10,随后开始写入数据。
DATA:16位数据,在读命令中,PHY芯片将读到的对应PHYAD的REGAD寄存器的数据写到DATA中;在写命令中,PHY芯片将接收到的DATA写入REGAD寄存器中。需要注意的是,在DATA传输的过程中,高位在前,低位在后。
IDLE:空闲状态,此时MDIO为无源驱动,处于高阻状态,但一般用上拉电阻使其上拉至高电平。
MDIO接口读时序图如下图所示:
在这里插入图片描述

图 27.1.6 MDIO接口读时序图
上图是以PHY地址为0x01,从寄存器地址0x00读出数据为例。整个读操作过程的MDC时钟由MAC驱动,同时MAC驱动MDIO引脚输出前导码+帧开始+操作码+PHY地址+寄存器地址,随后MDIO引脚切换至PHY驱动。在第一个TA位,MDIO引脚为高阻状态,第二个TA位为低电平,表示PHY芯片成功响应,并且接下来会输出16位寄存器数据;而如果第二个TA位处于高电平,则PHY芯片响应失败,有可能PHY地址不正确或者其它时序的错误。
需要注意的是,PHY在MDC时钟的上升沿采集数据,为保证数据的稳定传输,MAC在MDC的下降沿更新MDIO引脚的数据。当MDIO引脚切换至PHY驱动时,MDIO数据在MDC时钟的下降沿更新,因此MAC在MDC时钟的上升沿采集数据。在读操作结束后,MAC将MDIO引脚输出高阻,此时MDIO引脚的外部上拉电阻会将MDIO引脚拉高,此时MDIO接口处于空闲状态。
MDIO接口写时序图如下图所示:
在这里插入图片描述

图 27.1.7 MDIO接口写时序图
上图是以PHY地址为0x01,向寄存器地址0x00写入0x1340为例,在整个写操作过程中,MDC时钟和MDIO引脚一直由MAC端驱动,按照MDIO接口写通信协议开始传输数据。需要注意的是,PHY在MDC时钟的上升沿采集数据,为保证数据的稳定传输,MAC在MDC的下降沿将数据更新至MDIO引脚。在写操作结束后,MAC将MDIO引脚输出高阻,此时MDIO引脚的外部上拉电阻会将MDIO引脚拉高,此时MDIO接口处于空闲状态。
以太网PHY芯片(YT8521)
1)PHY地址
YT8521芯片的PHY地址由PHYAD[2:0]生成,如下图所示:由芯片手册的引脚分配表可知PHYAD[2:0]三位引脚从低位到高位分别对应LED0和RX_CLK、RX_CTL,我们可以通过硬件电路设置LED0和RX_CLK、RX_CTL引脚为上拉或者下拉,即分配为高低电平,0或1,从而表示不同的地址。
在这里插入图片描述

图 27.1.8 YT8521芯片引脚分配表
LED0和RX_CLK、RX_CTL取不同的值表示的地址范围从001到111。开发板上的以太网PHY芯片RX_CTL接上拉电阻,LED0和RX_CLK接下拉电阻,因此PHY地址为3’b100。
2)复位
YT8521芯片复位后,PHY内部寄存器的数据会恢复默认的状态,并且重新开始和MAC进行自协商。YT8521支持两种复位方式,一种是硬件复位,另外一种是软件复位。硬件复位时通过ETH_RST_N引脚实现对PHY芯片的复位,当ETH_RST_N引脚持续10ms的低电平时,即可实现对PHY芯片的复位。软件复位通过向寄存器地址0x00的Bit[15]写入1进行复位,并且在完成复位后,该位会自动清零。
3)寄存器
YT8521共有22位寄存器,这里我们仅介绍本实验用到的三个寄存器,控制寄存器、状态寄存器以及PHY芯片具体状态寄存器。
控制寄存器(Basic Mode Control Register, Address 0x00),简写为:BMCR,用于芯片的复位和其它功能的控制,各个位的说明如下图所示:

在这里插入图片描述
在这里插入图片描述

图 27.1.9 控制寄存器说明
部分常用位的说明如下:
Bit[15]:软件复位,1:PHY复位 0:正常模式;
Bit[14]:内部环回模式,1:内部环回模式 0:正常模式;
Bit[6] Bit[13]:选择网速带宽只有在自动协商使能不开启的情况下有效,10:1000Mb/s 01:100Mb/s 00:10Mb/s;
Bit[12]:自动协商使能,1:自动协商使能 0:禁止自动协商;
Bit[9]:重启自协商,1:重新开始自协商 0:自协商重启完成。
基本状态寄存器(Basic Mode Status Register, Address 0x01),简写为:BMSR,各个位的说明如下图所示:

在这里插入图片描述
在这里插入图片描述

图 27.1.10 状态寄存器说明
对我们用位的说明如下:
Bit[5]:自协商完成 1:自协商完成 0:正在进行自协商;
Bit[2]:连接状态, 1:连接成功 0:连接失败。
PHY特定状态寄存器(PHY Specific Status Register ,Address 0x11),简写为:PHYSR,各个位的说明如下图所示:

在这里插入图片描述
在这里插入图片描述

图 27.1.11 特定状态寄存器
Bit[15:14]:连接速度
11:保留
10:1000Mbps
01:100Mbps
00:10Mbps
27.2实验任务
本节实验任务是使用DFZU2EG/4EV MPSoC开发板上的以太网接口,完成MDIO接口的读写测试实验。板载的PL按键(PL_KEY1)控制MDIO接口进行软复位,并通过两个LED灯实时指示当前网口的连接速度。
27.3硬件设计
DFZU2EG/4EV MPSoC开发板上有两个千兆网口,一个是PL端网口,另一个是PS端网口,本次实验使用PL端网络进行试验。RJ45接口用于连接网线,其原理图如下图所示。
在这里插入图片描述

图 27.3.1 RJ45接口原理图
上图中的PHY2_LED1和PHY2_LED2是PHY输出的LED信号,用于控制RJ45接口上的LED灯, PHY2_MDI0_P/N~ PHY2_MDI3_P/N是PHY和RJ45接口间的差分信号线,用于传输数据。
以太网的数据传输离不开以太网PHY(物理层)芯片的支持,物理层定义了数据发送与接收所需要的电信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。我们的DFZU2EG/4EV MPSoC开发板上使用的PHY芯片为裕太车通公司的YT8521,其原理图如下图所示:
在这里插入图片描述

图 27.3.2 以太网接口原理图
YT8521是一个千兆以太网物理层收发器,支持1000/100/10Mbps通信速率,该芯片内部的参数可以通过MDIO接口进行配置。由上图可知,开发板上的以太网PHY芯片PHYAD2接上拉电阻,PHYAD [1:0] 接下拉电阻,因此PHY地址为5’h04。
原理图中的MDIO引脚连接了上拉电阻,在空闲状态下,当FPAG控制ETH_MDIO引脚输出高阻状态时,ETH_MDIO会被上拉至高电平。
本章主要完成MDIO接口的读写测试功能,因此以太网的引脚只用到了PHY2_MDC和PHY2_MDIO引脚。本实验中,各端口信号的管脚分配如下表所示:
表 27.3.1 MDIO接口读写测试实验管脚分配
在这里插入图片描述

对应的XDC约束语句如下所示:
#时钟周期约束
create_clock -name sys_clk_p -period 10.000 [get_ports sys_clk_p]

#IO管脚约束
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_n]
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
set_property PACKAGE_PIN AF5 [get_ports sys_clk_n]
set_property -dict {PACKAGE_PIN AH11 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

set_property -dict {PACKAGE_PIN E7 IOSTANDARD LVCMOS18} [get_ports eth_mdc]
set_property -dict {PACKAGE_PIN C7 IOSTANDARD LVCMOS18} [get_ports eth_mdio]

set_property -dict {PACKAGE_PIN AD11 IOSTANDARD LVCMOS33} [get_ports key]

set_property -dict {PACKAGE_PIN AE10 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN AF10 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
27.4程序设计
根据实验任务,我们可以大致规划出系统的控制流程:首先每隔一段时间通过MDIO接口从PHY内部寄存器中读取基本状态寄存器(BMSR)和特定状态寄存器(PHYSR)的值,从而获取到自协商完成状态、连接状态和连接速度,将网口的连接速度通过LED灯进行指示;当FPGA检测到PL Key1按键按下时,开始通过MDIO接口对PHY进行软复位,在软复位完成后,PHY会重新开始自协商,此时LED灯仍然会每隔一段时间获取当前网口的连接状态以及连接速度。由此画出系统的功能框图如下图所示:

在这里插入图片描述

图 27.4.1 MDIO接口读写测试系统框图
MDIO接口驱动模块实现了对MDIO接口的读写驱动。MDIO接口控制模块根据输入的PL Key1按键,实现了对MDIO接口驱动模块的写操作,并每隔一段时间对MDIO接口驱动模块进行读操作,将获取到的网口连接状态与速度通过LED灯进行指示。
各模块端口及信号连接如下图所示:
在这里插入图片描述

图 27.4.2 顶层模块原理图
由上图可知,FPGA顶层模块例化了以下两个模块,MDIO接口控制模块(mdio_ctrl)和MDIO接口驱动模块(mdio_dri),实现了各模块之间的数据交互。其中MDIO接口驱动模块预留了用户接口,方便对MDIO接口进行读写操作。
当FPGA通过MDIO控制模块向MDIO驱动模式读写数据时,拉高触发控制信号op_exec来触发MDIO驱动模块,op_rh_wl用于表示读或者写操作,当op_rh_wl为低电平时,MDIO驱动模块执行写操作,当op_rh_wl为高电平时,MDIO驱动模块执行读操作。op_addr表示读写寄存器地址,op_wr_data信号表示写入的数据,op_rd_data信号表示从MDIO接口的寄存器中读到的数据。当读或者写操作完成时,MDIO驱动模块会产生一个时钟周期的op_done信号,表示MDIO驱动模块读或者写操作完成。
顶层模块的代码如下:

1  module mdio_rw_test(
2      input          sys_clk_p,
3      input          sys_clk_n,
4      input          sys_rst_n,
5      //MDIO接口
6      output         eth_mdc  , //PHY管理接口的时钟信号
7      inout          eth_mdio , //PHY管理接口的双向数据信号
8      input          key      , // PL Key1按键
9      output  [1:0]  led        //LED连接速率指示
10     );
11 
12 //转换差分信号
13 IBUFDS diff_clock
14 (
15     .I (sys_clk_p),    //系统差分输入时钟    
16     .IB(sys_clk_n),    //系统差分输入时钟
17     .O (sys_clk)       //输出系统时钟
18 ); 
19 
20 //wire define
21 wire          op_exec    ;  //触发开始信号
22 wire          op_rh_wl   ;  //低电平写,高电平读
23 wire  [4:0]   op_addr    ;  //寄存器地址
24 wire  [15:0]  op_wr_data ;  //写入寄存器的数据
25 wire          op_done    ;  //读写完成
26 wire  [15:0]  op_rd_data ;  //读出的数据
27 wire          op_rd_ack  ;  //读应答信号 0:应答 1:未应答
28 wire          dri_clk    ;  //驱动时钟
29 
30 //MDIO接口驱动
31 mdio_dri #(
32     .PHY_ADDR    (5'h04),    //PHY地址 3'b100
33     .CLK_DIV     (6'd16)     //分频系数
34     )
35     u_mdio_dri(
36     .clk        (sys_clk   ),
37     .rst_n      (sys_rst_n ),
38     .op_exec    (op_exec   ),
39     .op_rh_wl   (op_rh_wl  ),   
40     .op_addr    (op_addr   ),   
41     .op_wr_data (op_wr_data),   
42     .op_done    (op_done   ),   
43     .op_rd_data (op_rd_data),   
44     .op_rd_ack  (op_rd_ack ),   
45     .dri_clk    (dri_clk   ),  
46                  
47     .eth_mdc    (eth_mdc   ),   
48     .eth_mdio   (eth_mdio  )   
49 );      
50 
51 //MDIO接口读写控制    
52 mdio_ctrl  u_mdio_ctrl(
53     .clk           (dri_clk),  
54     .rst_n         (sys_rst_n ),  
55     .key           (key       ),  
56     .op_done       (op_done   ),  
57     .op_rd_data    (op_rd_data),  
58     .op_rd_ack     (op_rd_ack ),  
59     .op_exec       (op_exec   ),  
60     .op_rh_wl      (op_rh_wl  ),  
61     .op_addr       (op_addr   ),  
62     .op_wr_data    (op_wr_data),  
63     .led           (led       )
64 );      
65 
66 endmodule

顶层模块主要完成对其余模块的例化。在程序的第32行和33行代码例化了两个参数,分别表示PHY地址和ETH_MDC相对于输入时钟的分频系数。这里将PHY地址设置为5’h04,如果PHY地址设置错误,会导致对MDIO接口的读写操作失败。另外需要注意的是,ETH_MDC的时钟频率不能超过12.5Mhz。
由前面的MDIO接口读写时序图我们可以发现,MDIO驱动模块非常适合采用状态机来编写。状态机的状态跳转图如图 27.4.3所示,总共有6个状态,分别为st_idle(空闲状态)、st_pre(发送前导码状态)、st_start(发送帧开始+操作码)、st_addr(发送PHY地址+寄存器地址)、st_wr_data(发送TA+写入数据)和st_rd_data(接收TA+接收数据)。当状态机处于空闲状态时,如果触发信号拉高(op_exec=1),状态机进入发送前导码状态。另外当状态机处于st_addr时,在发送完PHY地址和寄存器地址之后,接下来状态机根据读或者写操作来跳转至st_wr_data状态或者st_rd_data状态。在读或者写完数据后,状态机重新跳转至空闲状态。
在这里插入图片描述

图 27.4.3 状态跳转图
程序中我们采用的是三段式状态机,由于代码较长,这里仅贴出部分代码,代码如下:

65  //wire define
66  wire          mdio_in    ; //MDIO数据输入
67  wire   [5:0]  clk_divide ; //PHY_CLK的分频系数
68  
69  assign eth_mdio = mdio_dir ? mdio_out : 1'bz; //控制双向io方向
70  assign mdio_in = eth_mdio;                    //MDIO数据输入
71  //将PHY_CLK的分频系数除以2,得到dri_clk的分频系数,方便对MDC和MDIO信号操作
72  assign clk_divide = CLK_DIV >> 1;
73  
74  //分频得到dri_clk时钟
75  always @(posedge clk or negedge rst_n) begin
76      if(!rst_n) begin
77          dri_clk <=  1'b0;
78          clk_cnt <= 1'b0;
79      end
80      else if(clk_cnt == clk_divide[5:1] - 1'd1) begin
81          clk_cnt <= 1'b0;
82          dri_clk <= ~dri_clk;
83      end
84      else
85          clk_cnt <= clk_cnt + 1'b1;
86  end
87  
88  //产生PHY_MDC时钟
89  always @(posedge dri_clk or negedge rst_n) begin
90      if(!rst_n)
91          eth_mdc <= 1'b1;
92      else if(cnt[0] == 1'b0)
93          eth_mdc <= 1'b1;
94      else    
95          eth_mdc <= 1'b0;  
96  end
省略部分代码……
225             st_wr_data : begin
226                 case(cnt)
227                     7'd1 : mdio_out <= 1'b1;         //发送TA,写操作(2'b10)
228                     7'd3 : mdio_out <= 1'b0;
229                     7'd5 : mdio_out <= wr_data_t[15];//发送写寄存器数据
230                     7'd7 : mdio_out <= wr_data_t[14];
231                     7'd9 : mdio_out <= wr_data_t[13];
232                     7'd11: mdio_out <= wr_data_t[12];
233                     7'd13: mdio_out <= wr_data_t[11];
234                     7'd15: mdio_out <= wr_data_t[10];
235                     7'd17: mdio_out <= wr_data_t[9];
236                     7'd19: mdio_out <= wr_data_t[8];
237                     7'd21: mdio_out <= wr_data_t[7];
238                     7'd23: mdio_out <= wr_data_t[6];
239                     7'd25: mdio_out <= wr_data_t[5];
240                     7'd27: mdio_out <= wr_data_t[4];
241                     7'd29: mdio_out <= wr_data_t[3];
242                     7'd31: mdio_out <= wr_data_t[2];
243                     7'd33: mdio_out <= wr_data_t[1];
244                     7'd35: mdio_out <= wr_data_t[0];
245                     7'd37: begin
246                         mdio_dir <= 1'b0;
247                         mdio_out <= 1'b1;
248                     end
249                     7'd39: st_done <= 1'b1;           
250                     7'd40: begin
251                                cnt <= 7'b0;
252                                op_done <= 1'b1;      //写操作完成,拉高op_done信号 
253                            end    
254                     default : ;
255                 endcase    
256             end
257             st_rd_data : begin
258                 case(cnt)
259                     7'd1 : begin
260                         mdio_dir <= 1'b0;            //MDIO引脚切换至输入状态
261                         mdio_out <= 1'b1;
262                     end
263                     7'd2 : ;                         //TA[1]位,该位为高阻状态,不操作             
264                     7'd4 : op_rd_ack <= mdio_in;      //TA[0]位,0(应答) 1(未应答)
265                     7'd6 : rd_data_t[15] <= mdio_in; //接收寄存器数据
266                     7'd8 : rd_data_t[14] <= mdio_in;
267                     7'd10: rd_data_t[13] <= mdio_in;
268                     7'd12: rd_data_t[12] <= mdio_in;
269                     7'd14: rd_data_t[11] <= mdio_in;
270                     7'd16: rd_data_t[10] <= mdio_in;
271                     7'd18: rd_data_t[9] <= mdio_in;
272                     7'd20: rd_data_t[8] <= mdio_in;
273                     7'd22: rd_data_t[7] <= mdio_in;
274                     7'd24: rd_data_t[6] <= mdio_in;
275                     7'd26: rd_data_t[5] <= mdio_in;
276                     7'd28: rd_data_t[4] <= mdio_in;
277                     7'd30: rd_data_t[3] <= mdio_in;
278                     7'd32: rd_data_t[2] <= mdio_in;
279                     7'd34: rd_data_t[1] <= mdio_in;
280                     7'd36: rd_data_t[0] <= mdio_in;
281                     7'd39: st_done <= 1'b1;
282                     7'd40: begin
283                         op_done <= 1'b1;             //读操作完成,拉高op_done信号          
284                         op_rd_data <= rd_data_t;
285                         rd_data_t <= 16'd0;
286                         cnt <= 7'd0;
287                     end
288                     default : ;
289                 endcase  

在程序的第69行,通过mdio_dir(MDIO引脚方向选择)信号控制eth_mdio引脚的方向,当设置成输入时,FPGA将该引脚输出高阻(1’bz);当设置成输出时,将FPGA驱动的mdio_out信号连接至eth_mdio。
由于eth_mdc需要在输入时钟的基础上进行分频,为了方便操作,这里先对输入的时钟进行分频,得到一个dri_clk时钟,作为MDIO驱动模块和MDIO控制模块的操作时钟。eth_mdc在dri_clk的基础上进行2分频,由于输入的参数CLK_DIV为eth_mdc相对于输入时钟的分频系数,因此为了得到dri_clk的分频系数,需要将CLK_DIV除以2,如代码中第72行所示。
程序中第74行至第86行根据分频系数(clk_divide),得到dri_clk的时钟。在程序的第88行至第96行代码,当cnt一直累加时,eth_mdc的时钟相当于对dri_clk进行2分频。当开始对MDIO接口进行读写操作时,cnt累加,此时才会产生eth_mdc时钟;当读写操作结束后,cnt等于0,eth_mdc将一直处于高电平。
需要说明的是,由于clk_divide等于CLK_DIV除以2,程序中第74行至第86行代码只支持偶数分频,所以最终生成的eth_mdc的时钟频率相比于输入的CLK_DIV可能产生偏差。本次实验中,CLK_DIV等于16,因此clk_divide等于8,dri_clk的时钟频率为12.5Mhz,eth_mdc为6.25‬Mhz。‬
程序的第255行至289行代码为状态机的st_wr_data(发送TA+写入数据)和st_rd_data(接收TA+接收数据)状态。在st_wr_data状态下,数据是在eth_mdc的下降沿写入,而在st_rd_data状态,数据在erth_mdc的上升沿读出。值得一提是,在st_rd_data状态下,程序中根据TA的第二位,判断PHY芯片有没有应答,如果没有应答,则说明读取数据失败,如程序中第264行代码所示。
MDIO接口读PHYSR寄存器的ILA波形图如下图所示:
在这里插入图片描述

图 27.4.4 MDIO接口读操作ILA波形图
由上图可知,op_exec的脉冲信号作为MDIO接口读写的触发信号,图中op_rh_wl为高电平,表示读操作,op_addr寄存器地址为5’h11。在TA位时,mdio_dir由高电平切换至低电平,表示MDIO引脚由输出切换至输入,随后op_rd_ack变为低电平,说明PHY芯片应答成功。在整个读操作结束后,MDIO驱动模块产生一个脉冲的op_done信号,此时从状态寄存器中读出的数据为0x796d。
MDIO控制模块代码如下:

1   module mdio_ctrl(
2       input                clk           ,
3       input                rst_n         ,
4       input                soft_rst_trig , //软复位触发信号
5       input                op_done       , //读写完成
6       input        [15:0]  op_rd_data    , //读出的数据
7       input                op_rd_ack     , //读应答信号 0:应答 1:未应答
8       output  reg          op_exec       , //触发开始信号
9       output  reg          op_rh_wl      , //低电平写,高电平读
10      output  reg  [4:0]   op_addr       , //寄存器地址
11      output  reg  [15:0]  op_wr_data    , //写入寄存器的数据
12      output       [1:0]   led             //LED灯指示以太网连接状态
13      );
14  
15  //reg define
16  reg          rst_trig_d0;    
17  reg          rst_trig_d1;    
18  reg          rst_trig_flag;   //soft_rst_trig信号触发标志
19  reg  [23:0]  timer_cnt;       //定时计数器 
20  reg          timer_done;      //定时完成信号
21  reg          start_next;      //开始读下一个寄存器标致
22  reg          read_next;       //处于读下一个寄存器的过程
23  reg          link_error;      //链路断开或者自协商未完成
24  reg  [2:0]   flow_cnt;        //流程控制计数器 
25  reg  [1:0]   speed_status;    //连接速率 
26  
27  //wire define
28  wire         pos_rst_trig;    //soft_rst_trig信号上升沿
29  
30  //采soft_rst_trig信号上升沿
31  assign pos_rst_trig = ~rst_trig_d1 & rst_trig_d0;
32  //未连接或连接失败时led赋值00
33  // 01:10Mbps  10:100Mbps  11:1000Mbps 00:其他情况
34  assign led = link_error ? 2'b00: speed_status;
35  //对soft_rst_trig信号延时打拍
36  always @(posedge clk or negedge rst_n) begin
37      if(!rst_n) begin
38          rst_trig_d0 <= 1'b0;
39          rst_trig_d1 <= 1'b0;
40      end
41      else begin
42          rst_trig_d0 <= soft_rst_trig;
43          rst_trig_d1 <= rst_trig_d0;
44      end
45  end
46  
47  //定时计数
48  always @(posedge clk or negedge rst_n) begin
49      if(!rst_n) begin
50          timer_cnt <= 1'b0;
51          timer_done <= 1'b0;
52      end
53      else begin
54          if(timer_cnt == 24'd1_000_000 - 1'b1) begin
55              timer_done <= 1'b1;
56              timer_cnt <= 1'b0;
57          end
58          else begin
59              timer_done <= 1'b0;
60              timer_cnt <= timer_cnt + 1'b1;
61          end
62      end
63  end    
64  
65  //根据软复位信号对MDIO接口进行软复位,并定时读取以太网的连接状态
66  always @(posedge clk or negedge rst_n) begin
67      if(!rst_n) begin
68          flow_cnt <= 3'd0;
69          rst_trig_flag <= 1'b0;
70          speed_status <= 2'b00;
71          op_exec <= 1'b0; 
72          op_rh_wl <= 1'b0; 
73          op_addr <= 1'b0;       
74          op_wr_data <= 1'b0; 
75          start_next <= 1'b0; 
76          read_next <= 1'b0; 
77          linkerro <= 1'b0;
78      end
79      else begin
80          op_exec <= 1'b0; 
81          if(pos_rst_trig)                      
82              rst_trig_flag <= 1'b1;             //拉高软复位触发标志
83          case(flow_cnt)
84              2'd0 : begin
85                  if(rst_trig_flag) begin        //开始对MDIO接口进行软复位
86                      op_exec <= 1'b1; 
87                      op_rh_wl <= 1'b0; 
88                      op_addr <= 5'h00; 
89                      op_wr_data <= 16'hB100;    //Bit[15]=1'b1,表示软复位
90                      flow_cnt <= 3'd1;
91                  end
92                  else if(timer_done) begin      //定时完成,获取以太网连接状态
93                      op_exec <= 1'b1; 
94                      op_rh_wl <= 1'b1; 
95                      op_addr <= 5'h01; 
96                      flow_cnt <= 3'd2;
97                  end
98                  else if(start_next) begin       //开始读下一个寄存器,获取以太网通信速度
99                      op_exec <= 1'b1; 
100                     op_rh_wl <= 1'b1; 
101                     op_addr <= 5'h1A; 
102                     flow_cnt <= 3'd2;
103                     start_next <= 1'b0; 
104                     read_next <= 1'b1; 
105                 end
106             end    
107             2'd1 : begin
108                 if(op_done) begin              //MDIO接口软复位完成
109                     flow_cnt <= 3'd0;
110                     rst_trig_flag <= 1'b0;
111                 end
112             end
113             2'd2 : begin                       
114                 if(op_done) begin             //MDIO接口读操作完成
115                     if(op_rd_ack == 1'b0 && read_next == 1'b0) 
116                         flow_cnt <= 3'd3;    //读第一个寄存器,接口成功应答, 
117                     else if(op_rd_ack == 1'b0 && read_next == 1'b1)begin 
118                         read_next <= 1'b0;   //读第下一个寄存器,接口成功应答
119                         flow_cnt <= 3'd4;
120                     end
121                     else begin
122                         flow_cnt <= 3'd0;
123                      end
124                 end    
125             end
126             2'd3 : begin                     
127                 flow_cnt <= 3'd0;          //链路正常并且自协商完成
128                 if(op_rd_data[5] == 1'b1 && op_rd_data[2] == 1'b1)begin
129                     start_next <= 1;
130                     link_error <= 0;
131                 end
132                 else begin
133                     link_error <= 1'b1;  
134                end           
135             end
136             3'd4: begin
137                 flow_cnt <= 3'd0;
138                 if(op_rd_data[5:4] == 2'b10)
139                     speed_status <= 2'b11; //1000Mbps
140                 else if(op_rd_data[5:4] == 2'b01) 
141                     speed_status <= 2'b10; //100Mbps 
142                 else if(op_rd_data[5:4] == 2'b00) 
143                     speed_status <= 2'b01; //10Mbps
144                 else
145                     speed_status <= 2'b00; //其他情况  
146             end
147         endcase
148     end    
149 end    
150     
151 endmodule

程序中第48至第63行代码实现计数定时的功能,每当计数器计数到1000000-1时,会产生一个周期的脉冲信号(timer_done)。该模块输入的时钟频率为12.5Mhz,因此定时周期为80ms。
程序中第62行至第125行代码根据软复位信号对MDIO接口进行软复位,并定时读取以太网的连接状态。其中程序中第138行至145行代码,根据状态寄存器的值,为连接速率状态位(speed_status)赋值。
27.5下载验证
将下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,将网线一端连接开发板的PL网口(PL_ETH),另一端连接电脑的网口或者路由器,最后连接电源线后拨动开关按键给开发板上电,PL_ETH网口的位置如下图所示。
在这里插入图片描述

图 27.5.1 PL_ETH网口位置
点击Vivado左侧“Flow Navigator”窗口最下面的“Open Hardware Manager”,此时Vivado软件识别到下载器,点击“Hardware”窗口中“Program Device”下载程序,在弹出的界面中选择“Program”下载程序。
程序下载完成后,等待几秒即可看到开发板PL LED灯的点亮状态,如下图所示:
在这里插入图片描述

图 27.5.2 开发板实验现象
如上图可知,PL的两个LED灯都处于点亮状态,因此通信速率为1000Mbps。如果按下PL _KEY1按键会对PHY进行软复位,此时PHY芯片会重新开始与另一端设备进行自协商,等待几秒后,PL LED灯重新点亮。
另外,如果开发板另一端连接的是电脑的网口,此时可以查看自协商后的通信速率。查看方法是点击电脑右下角的网络图标,会看到本地连接刚开始显示的是正在识别,一段时间之后显示未识别的网络,打开方式如下图所示(WIN7和WIN10操作可能存在差异,但基本相同)。
在这里插入图片描述

图 27.5.3 点击网络图标
点击图 27.5.3中的“未识别的网络(无Internet)”,弹出如下图所示界面。

在这里插入图片描述

图 27.5.4 网络设置界面
点击“更改适配器”选项,弹出如下图所示界面。
在这里插入图片描述

图 27.5.5 “网络适配器界面”
如果看到上图“以太网”显示未识别的网络之后,说明硬件连接是没有问题的,接下来鼠标右击以太网,选择 “连接”,如图 27.5.6和图 27.5.7所示。
在这里插入图片描述

图 27.5.6 鼠标右击后选择“状态
在这里插入图片描述

图 27.5.7 以太网连接速度
由上图可知,开发板和电脑自协商的通信速率为1Gbps(1000Mbps)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

字典类型和字典函数、字典方法

字典类型 (无序&#xff0c;不能重复) 通过任意键信息查找一组数据中值信息的过程叫映射&#xff0c; Python语言中通过字典实现映射。 Python语言中的字典可以通过大括号({})建立&#xff0c;建立模式如下&#xff1a; {<键1>:<值1>,<键2>:<值2>,...,…

[附源码]Python计算机毕业设计SSM健身房管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

p15~p22基本链表容器和高级链表容器迭代器

STL一、自制链表容器/基本链表容器1.1 首/尾部增删节点1.2 获取首/尾部的元素1.3 清空链表7 / 判空链表 / 链表大小81.4 缺省构造0/拷贝构造10/析构函数91.5 输出流操作符重载二、迭代器原理2.1 迭代器概念2.2 迭代器的分类三、迭代器实现3.1 正向非常迭代类3.2 正向非常迭代器…

html旅游网站设计与实现——绿色古典旅游景区 HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

解析仓库管理系统对于企业的重要性

仓储管理的职责是有效的保存和管理仓库内的物资&#xff0c;这些物资是指仓库内所有的有形物品以及无形的资产。以前很多企业都是依靠人工方式对库房的管理&#xff0c;难免会造成一些难以解决的问题&#xff1a; 仓库种类太多&#xff0c;查看困难&#xff1b;仓库信息记录不…

Java应用程序安全框架

《从零打造项目》系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成MybatisPlus项目实操SpringBoot集成Spring Data JPA项目实操 数据库变更管理 数据库变更管理&#xff1a;Liquibase…

Word控件Spire.Doc 【图像形状】教程(11): 如何在 C# 中为 Word 中的图像设置 Transeperant 颜色

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

A-Level经济题解析及练习Policy options for Common Resources

今日知识点&#xff1a;Policy options for Common Resources 例题 There is a medieval town where sheep graze on common land. As the population grows, the number of sheep grows. However, the amount of land is fixed, the grass begins to disappear from overgra…

SwiftUI 中为什么应该经常用子视图替换父视图中的大段内容?

概览 在 SwiftUI 官方教程中&#xff0c;Apple 时常提出“化整为零”的界面布局思想。简单来说&#xff0c;Apple 推荐 SwiftUI 视图的构建方式是&#xff1a;用若干自定义小视图来构成上层的功能视图。 这是为什么呢&#xff1f; 在本篇博文中&#xff0c;我们将用一个通俗…

[Java反序列化]—CommonsCollections6

先贴个图 0x01: CC 6 应该是CC1 和 URLDNS 的综合&#xff0c;有一定联系&#xff0c;审一下吧 JDK版本需低于 8u71 AnnotationInvocationHandler类的readObject()方法在8u71以后逻辑就发生了改变&#xff0c;不能再利用了&#xff0c;所以就需要找一个绕过高版本的利用链…

Cadence Virtuoso Layout 版图绘制的使用技巧及其相关快捷键

1.版图前准备操作 画好原理图&#xff0c;打好pin脚&#xff08;pin最好以全大写的形式书写&#xff0c;以防后续操作中可能出现Bug&#xff09; 查看所使用工艺库的design rule文件&#xff0c;确定栅格单位设置大小 在准备绘制的原理图界面启动layout XL/GXL 在layout界面…

JS 正则表达式常用方法

1. JS 正则表达式 2. 使用字符串方法 3. 使用 RegExp 方法 1. JS 正则表达式 JS 正则表达式语法: # JS 的正则表达式不需要使用引号包裹&#xff0c;PHP 需要使用引号包裹。修饰符是可选的&#xff0c;可写可不写/正则表达式主体/修饰符JS 中使用正则表达式的方法比较多&am…

【强化学习论文合集】九.2018AAAI人工智能大会论文(AAAI2018)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

Python中的Apriori关联算法-市场购物篮分析

数据科学Apriori算法是一种数据挖掘技术&#xff0c;用于挖掘频繁项集和相关的关联规则。本模块重点介绍什么是关联规则挖掘和Apriori算法&#xff0c;以及Apriori算法的用法。 去年&#xff0c;我们为一家公司进行了短暂的咨询工作&#xff0c;该公司正在构建一个主要基于Apr…

使用DIV+CSS技术设计的非遗文化网页与实现制作(web前端网页制作课作业)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

m基于自适应遗传优化的IEEE-6建设费用和网络损耗费用最小化电网规划算法matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 电力工业是当今世界各国经济的重要组成部分&#xff0c;随着世界经济的不断发展&#xff0c;电网的建设和中长期规划和经济发展之间的矛盾变得越来越突出&#xff0c;对电力系统的需求也变得越来…

微服务框架 SpringCloud微服务架构 16 SpringAMQP 16.7 DirectExchange

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构16 SpringAMQP16.7 DirectExchange16.7.1 发布订阅 - DirectExchange16.7.…

基于遗传优化算法的小车障碍物避障路线规划matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 一种通过模拟自然进化过程搜索最优解的方法&#xff0c;对于一个最优化问题&#xff0c;该算法通过一定数量的候选解种群迭代地执行选择、交叉、变异、评价等操作使得种群向更好的解进化。 遗传算…

MyBatisPlus简述

文章目录一、MyBatisPlus入门案例与简介1.入门案例2.springboot整合mybatis的方式3.springboot整合mybatisplus步骤1.创建环境&#xff0c;上面我们已经创建过了步骤2.创建数据库及表步骤2.pom.xml补全依赖步骤3.添加MP的相关配置信息步骤4.根据数据库表创建实体类步骤5.创建Da…

linux安装redis哨兵

安装环境 服务器一台&#xff1a; 服务器IP&#xff1a;172.169.3.251主从端口&#xff1a;6379、6380、6381哨兵端口&#xff0c;26379、26380、26381安装目录&#xff1a;/usr/local/redis配置文件目录&#xff1a;/usr/loca/redis/conf redis安装 1、下载redis wget ht…