0
点赞
收藏
分享

微信扫一扫

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章 MDIO接口读写测试实验​

MDIO接口读写测试实验​

在以太网通信中,设备之间的物理层链路均由PHY芯片(物理层芯片,本文指YT8521)建立。PHY芯片有一个配置接口,即MDIO接口,可以配置PHY芯片的工作模式以及获取PHY芯片的若干状态信息。本章我们来学习如何通过DFZU2EG/4EV MPSoC开发板实现对PHY芯片的MDIO接口进行读写测试。

本章分为以下几个章节

  1. 简介
  2. 实验任务
  3. 硬件设计
  4. 程序设计
  5. 下载验证


简介

以太网概述

以太网(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接口样式所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_02


27.1.1 RJ45插头(左)、插座(右)

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

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_03


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_04


27.1.2 RJ45插座10M/100M接口定义

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

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_05


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_06


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连接示意图如下图所示。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_07


27.1.4 MDIO接口示意图

MDIO接口也称为SMI接口(Serial Management Interface,串行管理接口),包括ETH_MDC(数据管理时钟)和ETH_MDIO(数据管理输入输出)两条信号线。ETH_MDC为ETH_MDIO提供时钟,ETH_MDC的最大时钟不能超过12.5Mhz。ETH_MDIO为双向数据引脚,既用于发送数据,也用于接收数据。

MDIO接口的读写通信协议如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_08


27.1.5 MDIO接口通信协议

Preamble:32位前导码,由MAC端发送32位逻辑“1”,用于同步PHY芯片。

STStart 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接口读时序图如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_09


27.1.6 MDIO接口读时序图

上图是以PHY地址为0x01,从寄存器地址0x00读出数据为例。整个读操作过程的MDC时钟由MAC驱动,同时MAC驱动MDIO引脚输出前导码+帧开始+操作码+PHY地址+寄存器地址,随后MDIO引脚切换至PHY驱动。在第一个TA位,MDIO引脚为高阻状态,第二个TA位为低电平,表示PHY芯片成功响应,并且接下来会输出16位寄存器数据;而如果第二个TA位处于高电平,则PHY芯片响应失败,有可能PHY地址不正确或者其它时序的错误。

需要注意的是,PHY在MDC时钟的上升沿采集数据,为保证数据的稳定传输,MACMDC的下降沿更新MDIO引脚的数据。当MDIO引脚切换至PHY驱动时,MDIO数据在MDC时钟的下降沿更新,因此MAC在MDC时钟的上升沿采集数据。在读操作结束后,MAC将MDIO引脚输出高阻,此时MDIO引脚的外部上拉电阻会将MDIO引脚拉高,此时MDIO接口处于空闲状态。

MDIO接口写时序图如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_10


27.1.7 MDIO接口写时序图

上图是以PHY地址为0x01,向寄存器地址0x00写入0x1340为例,在整个写操作过程中,MDC时钟和MDIO引脚一直由MAC端驱动,按照MDIO接口写通信协议开始传输数据。需要注意的是,PHY在MDC时钟的上升沿采集数据,为保证数据的稳定传输,MACMDC的下降沿将数据更新至MDIO引脚。在写操作结束后,MAC将MDIO引脚输出高阻,此时MDIO引脚的外部上拉电阻会将MDIO引脚拉高,此时MDIO接口处于空闲状态。

以太网PHY芯片(YT8521

1)PHY地址

YT8521芯片的PHY地址由PHYAD[2:0]生成,如下图所示:由芯片手册的引脚分配表可知PHYAD[2:0]三位引脚从低位到高位分别对应LED0RX_CLK、RX_CTL,我们可以通过硬件电路设置LED0RX_CLK、RX_CTL引脚为上拉或者下拉,即分配为高低电平,0或1,从而表示不同的地址。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_11


27.1.8芯片引脚分配表

LED0RX_CLK、RX_CTL取不同的值表示的地址范围从001到111。开发板上的以太网PHY芯片RX_CTL接上拉电阻,LED0RX_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用于芯片的复位和其它功能的控制,各个位的说明如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_12


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_13


27.1.9 控制寄存器说明

部分常用位的说明如下:

Bit[15]:软件复位,1PHY复位 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,各个位的说明如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_14


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_15


27.1.10 状态寄存器说明

对我们用位的说明如下:

Bit[5]:自协商完成1:自协商完成 0:正在进行自协商;

Bit[2]:连接状态,1:连接成功0:连接失败。

PHY特定状态寄存器(PHY Specific Status Register ,Address 0x11,简写为:PHYSR,各个位的说明如下图所示:


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_16


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_17


27.1.11特定状态寄存器

Bit[15:14]:连接速度

11:保留

10:1000Mbps

01:100Mbps

00:10Mbps

实验任务

本节实验任务是使用DFZU2EG/4EV MPSoC开发板上的以太网接口,完成MDIO接口的读写测试实验。板载的PL按键(PL_KEY1)控制MDIO接口进行软复位,并通过两个LED灯实时指示当前网口的连接速度。

硬件设计

DFZU2EG/4EV MPSoC开发板上有两个千兆网口,一个是PL端网口,另一个是PS端网口,本次实验使用PL端网络进行试验。RJ45接口用于连接网线,其原理图如下图所示。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_18


27.3.1 RJ45接口原理图

上图中的PHY2_LED1PHY2_LED2是PHY输出的LED信号,用于控制RJ45接口上的LED灯, PHY2_MDI0_P/N~ PHY2_MDI3_P/N是PHY和RJ45接口间的差分信号线,用于传输数据。

以太网的数据传输离不开以太网PHY(物理层)芯片的支持,物理层定义了数据发送与接收所需要的电信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。我们的DFZU2EG/4EV MPSoC开发板上使用PHY芯片裕太车通公司YT8521,其原理图如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_19


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_20


《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_寄存器_21


27.3.2以太网接口原理图

YT8521是一个千兆以太网物理层收发器,支持1000/100/10Mbps通信速率,该芯片内部的参数可以通过MDIO接口进行配置。由上图可知,开发板上的以太网PHY芯片PHYAD2接上拉电阻,PHYAD [1:0]接下拉电阻,因此PHY地址为5’h04

原理图中的MDIO引脚连接了上拉电阻,在空闲状态下,当FPAG控制ETH_MDIO引脚输出高阻状态时,ETH_MDIO会被上拉至高电平。

本章主要完成MDIO接口的读写测试功能,因此以太网的引脚只用到了PHY2_MDCPHY2_MDIO引脚。本实验中,各端口信号的管脚分配如下表所示:

27.3.1 MDIO接口读写测试实验管脚分配

信号名

方向

管脚

端口说明

电平标准

sys_clk_p

input

AE5

系统差分输入时钟

DIFF_HSTL_I_12

sys_clk_n

input

AF5

系统差分输入时钟

DIFF_HSTL_I_12

sys_rst_n

input

AH11

系统复位按键低电平有效

LVCMOS33

eth_mdc

output

E7

PHY管理接口的时钟信号

LVCMOS18

eth_mdio

inout

C7

PHY管理接口的双向数据信号

LVCMOS18

key

input

AD11

PL按键1

LVCMOS33

led[0]

output

AE10

LED0

LVCMOS33

led[1]

output

AF10

LED1

LVCMOS33

对应的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]}]

程序设计

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

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_22


27.4.1 MDIO接口读写测试系统框图

MDIO接口驱动模块实现了对MDIO接口的读写驱动。MDIO接口控制模块根据输入的PL Key1按键,实现了对MDIO接口驱动模块的写操作,并每隔一段时间对MDIO接口驱动模块进行读操作,将获取到的网口连接状态与速度通过LED灯进行指示。

各模块端口及信号连接如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_23


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状态。在读或者写完数据后,状态机重新跳转至空闲状态。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_24


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_mdc6.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波形图如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_25


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)赋值。

下载验证

将下载器一端连电脑,一端开发板上的JTAG下载口连接,将网线一端连接开发板的PL网口(PL_ETH),另一端连接电脑的网口或者路由器,最后连接电源线后拨动开关按键给开发板上电,PL_ETH网口的位置如下图所示。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_26


27.5.1 PL_ETH网口位置

点击Vivado左侧“Flow Navigator”窗口最下面的“Open Hardware Manager”,此时Vivado软件识别到下载器,点击“Hardware”窗口中“Program Device”下载程序,在弹出的界面中选择“Program”下载程序。

程序下载完成后,等待几秒即可看到开发板PL LED灯的点亮状态,如下图所示:

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_27


27.5.2 开发板实验现象

如上图可知,PL的两个LED灯都处于点亮状态,因此通信速率为1000Mbps。如果按下PL _KEY1按键会对PHY进行软复位,此时PHY芯片会重新开始与另一端设备进行自协商,等待几秒后,PL LED灯重新点亮。

另外,如果开发板另一端连接的是电脑的网口,此时可以查看自协商后的通信速率。查看方法是点击电脑右下角的网络图标,会看到本地连接刚开始显示的是正在识别,一段时间之后显示未识别的网络,打开方式如下图所示(WIN7和WIN10操作可能存在差异,但基本相同)。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_28


27.5.3 点击网络图标

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




《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_29


27.5.4 网络设置界面

点击“更改适配器”选项,弹出如下图所示界面。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_数据_30


27.5.5 “网络适配器界面”

如果看到上图“以太网”显示未识别的网络之后,说明硬件连接是没有问题的,接下来鼠标右击以太网,选择27.5.627.5.7所示。

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_31


27.5.6鼠标右击后选择“状态

《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章  MDIO接口读写测试实验​_引脚_32


27.5.7以太网连接速度

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


举报

相关推荐

0 条评论