OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5208|回复: 0

[XILINX] 【正点原子FPGA连载】第二十四章 MDIO接口读写测试实验--摘自【正点原子】领航者ZYNQ之FPGA开发指南_V1.2

[复制链接]

1107

主题

1118

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4615
金钱
4615
注册时间
2019-5-8
在线时间
1218 小时
发表于 2020-7-23 16:33:50 | 显示全部楼层 |阅读模式
本帖最后由 正点原子01 于 2020-7-23 16:33 编辑

1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-301505-1-1.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:712557122
5)关注正点原子公众号,获取最新资料更新
1.jpg
1120.png
第二十四章MDIO接口读写测试实验

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

1.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接口样式如图24.1.1所示:
image002.jpg image004.gif
24.1.1RJ45插头(左)、插座(右)
RJ45接口定义以及各引脚功能说明如图24.1.2所示,在以太网中只使用了1、2、3、6这四根线,其中1、2这组负责传输数据(TX+、TX-),而3、6这组负责接收数据(RX+、RX-),另外四根线是备用的。
image006.jpg image008.jpg
24.1.2RJ45插座接口定义
从硬件的角度来说,以太网接口电路主要由MAC(Media AccessControl)控制器和物理层接口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连接示意图如下图所示。
image010.gif
24.1.3 MDIO接口示意图

MDIO接口也称为SMI接口(SerialManagement Interface,串行管理接口),包括ETH_MDC(数据管理时钟)和ETH_MDIO(数据管理输入输出)两条信号线。ETH_MDC为ETH_MDIO提供时钟,ETH_MDC的最大时钟不能超过12.5Mhz。ETH_MDIO为双向数据引脚,既用于发送数据,也用于接收数据。
MDIO接口的读写通信协议如下图所示:
image012.jpg
24.1.4 MDIO接口通信协议
Preamble:32位前导码,由MAC端发送32位逻辑“1”,用于同步PHY芯片。
ST(Startof 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中;在写命令中,MAC将要写入对应PHYAD的REGAD寄存器的值写入DATA中。
IDLE:空闲状态,此时MDIO为无源驱动,处于高阻状态,但一般用上拉电阻使其上拉至高电平。
MDIO接口读时序图如下图所示:
image014.gif
24.1.5 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接口写时序图如下图所示:
image016.gif
24.1.6 MDIO接口写时序图
上图是以PHY地址为0x01,向寄存器地址0x00写入0x1340为例,在整个写操作过程中,MDC时钟和MDIO引脚一直由MAC端驱动,按照MDIO接口写通信协议开始传输数据。需要注意的是,PHY在MDC时钟的上升沿采集数据,为保证数据的稳定传输,MAC在MDC的下降沿将数据更新至MDIO引脚。在写操作结束后,MAC将MDIO引脚输出高阻,此时MDIO引脚的外部上拉电阻会将MDIO引脚拉高,此时MDIO接口处于空闲状态。
以太网PHY芯片(B50610
1)PHY地址
B50610芯片的PHY地址由TEST[3:2]和PHYA[0]引脚决定,如下图所示:
image018.jpg
24.1.7 PHY地址选择
     从上图可以看出,PHY地址根据TEST[3:2]和PHYA[0]引脚的不同,共有4个不同的PHY地址。领航者ZYNQ开发板上的以太网PHY芯片TEST[3:2]和PHYA[0]均为高电平(原理图见本章硬件设计部分),因此PHY地址为5’h19。
2)复位
B50610芯片复位后,PHY内部寄存器的数据会恢复默认的状态,并且重新开始和MAC进行自协商。B50610支持两种复位方式,一种是硬件复位,另外一种是软件复位。硬件复位时通过ETH_RST_N引脚实现对PHY芯片的复位,当ETH_RST_N引脚持续2us的低电平时,即可实现对PHY芯片的复位。软件复位通过向寄存器地址0x00的Bit[15]写入1进行复位,并且在完成复位后,该位会自动清零。
3)寄存器
B50610共有32位寄存器,这里我们仅介绍常用的两个寄存器,控制寄存器和状态寄存器。
控制寄存器(地址:0x00)用于芯片的复位和其它功能的控制,各个位的说明如下图所示:
image020.jpg
24.1.8控制寄存器说明
部分常用位的说明如下:
Bit[15]:软件复位,1:PHY复位 0:正常模式;
Bit[14]:内部环回模式,1:本地环回模式0:正常模式;
Bit[12]:自动协商使能1:自动协商使能0:自动协商不使能;
Bit[9]:重启自协商,1:重新开始自协商0:自协商重启完成。
状态寄存器(0x19)用于获取当前芯片的工作状态,各个位的说明如下图所示:
image022.jpg
24.1.9:状态寄存器说明
部分常用位的说明如下:
Bit[15]:自协商完成1:自协商完成0:正在进行自协商;
Bit[10:8]:当前连接速度和双工模式;
        111:1000Mbps全双工传输;
         110:1000Mbps半双工传输;
        101:100Mbps,传输介质为2对高质量的双绞线,一对用于发送数据,一对用于接收数据,全双工传输;
         100:100Mbps,传输介质为4对3类非屏蔽(UTP)双绞线,仅支持半双工;
        011:100Mbps,传输介质为2对高质量的双绞线,一对用于发送数据,一对用于接收数据,半双工传输;
        010:10Mbps,全双工通信;
        001:10Mbps,半双工通信;
        000:未连接或者自协商尚未完成;
Bit[2]:连接状态,1:连接成功0:连接失败。
1.2 实验任务
本节实验任务是使用领航者ZYNQ开发板上的以太网接口,完成MDIO接口的读写测试实验。板载的触摸按键(TPAD)控制MDIO接口进行软复位,并通过两个LED灯实时指示当前网口的连接速度。
1.3 硬件设计
领航者ZYNQ开发板上有两个千兆网口,本次实验使用的是PL端的网口。PL端的RJ45接口用于连接网线,其原理图如下图所示:
image024.jpg
24.3.1 RJ45接口原理图
上图中的LEDG和LEDY是PHY输出的LED信号,用于控制RJ45接口上的LED灯,PHY0_MDIOP/N~PHY3_MDIOP/N是PHY和RJ45接口间的差分信号线,用于传输数据。
以太网的数据传输离不开以太网PHY(物理层)芯片的支持,物理层定义了数据发送与接收所需要的电信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。我们的领航者ZYNQ开发板上使用的PHY芯片为博通公司的B50610,其原理图如下图所示:
image026.jpg
24.3.2以太网接口原理图
B50610是一个千兆以太网物理层收发器,支持1000/100/10Mbps通信速率,该芯片内部的参数可以通过MDIO接口进行配置。由上图可知,TEST[3:2]和PHYA[0]引脚均连接高电平,结合图24.1.7可知,该PHY地址为5’h19。
原理图中的ETH_MDC和ETH_MDIO引脚均连接了上拉电阻,在空闲状态下,当FPAG控制ETH_MDIO引脚输出高阻状态时,ETH_MDIO会被上拉至高电平。
本章主要完成MDIO接口的读写测试功能,因此以太网的引脚只用到了ETH_RESET_N、ETH_MDC和ETH_MDIO引脚。本实验中,各端口信号的管脚分配如下表所示:
24.3.1MDIO接口读写测试实验管脚分配
F4A4EDFA-8D7B-41ac-8781-AC2E7322C9E3.png
对应的XDC约束语句如下所示:
  1. set_property -dict {PACKAGE_PIN U18 IOSTANDARDLVCMOS33} [get_ports sys_clk]
  2. set_property -dict {PACKAGE_PIN J15 IOSTANDARDLVCMOS33} [get_ports sys_rst_n]
  3. set_property -dict {PACKAGE_PIN K14 IOSTANDARDLVCMOS33} [get_ports eth_mdc]
  4. set_property -dict {PACKAGE_PIN D20 IOSTANDARDLVCMOS33} [get_ports eth_mdio]
  5. set_property -dict {PACKAGE_PIN G14 IOSTANDARDLVCMOS33} [get_ports eth_rst_n]
  6. set_property -dict {PACKAGE_PIN L19 IOSTANDARDLVCMOS33} [get_ports touch_key]
  7. set_property -dict {PACKAGE_PIN J18 IOSTANDARDLVCMOS33} [get_ports {led[0]}]
  8. set_property -dict {PACKAGE_PIN H18 IOSTANDARDLVCMOS33} [get_ports {led[1]}]
复制代码
1.4 程序设计
     根据实验任务,我们可以大致规划出系统的控制流程:首先每隔一段时间通过MDIO接口从PHY内部寄存器中读取状态控制寄存器,从而获取到自协商完成状态、连接状态和连接速度,将网口的连接速度通过LED灯进行指示;当FPGA检测到TPAD触摸按键按下时,开始通过MDIO接口对PHY进行软复位,在软复位完成后,PHY会重新开始自协商,此时LED灯仍然会每隔一段时间获取当前网口的连接状态以及连接速度。由此画出系统的功能框图如下图所示:
image028.gif
24.4.1MDIO接口读写测试系统框图
     MDIO接口驱动模块实现了对MDIO接口的读写驱动。MDIO接口控制模块根据输入的触摸按键,实现了对MDIO接口驱动模块的写操作,并每隔一段时间对MDIO接口驱动模块进行读操作,将获取到的网口连接状态与速度通过LED灯进行指示。
各模块端口及信号连接如下图所示:
image030.jpg
24.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  ,
  3. input          sys_rst_n,
  4. //MDIO接口
  5. output         eth_mdc  ,//PHY管理接口的时钟信号
  6. inout          eth_mdio ,//PHY管理接口的双向数据信号
  7. output         eth_rst_n,//以太网复位信号

  8. input          touch_key,//触摸按键
  9. output[1:0  led        //LED连接速率指示
  10. );

  11. //wire define
  12. wire          op_exec    ;//触发开始信号
  13. wire          op_rh_wl   ;//低电平写,高电平读
  14. wire[4:0   op_addr    ;//寄存器地址
  15. wire[15:0  op_wr_data ;//写入寄存器的数据
  16. wire          op_done    ;//读写完成
  17. wire[15:0  op_rd_data ;//读出的数据
  18. wire          op_rd_ack  ;//读应答信号 0:应答 1:未应答
  19. wire          dri_clk    ;//驱动时钟

  20. //硬件复位
  21. assign eth_rst_n = sys_rst_n;

  22. //MDIO接口驱动
  23. mdio_dri #(
  24. .PHY_ADDR    (5'h19),//PHY地址
  25. .CLK_DIV     (6'd10)//分频系数
  26. )
  27.      u_mdio_dri(
  28. .clk        (sys_clk),
  29. .rst_n      (sys_rst_n),
  30. .op_exec    (op_exec   ),
  31. .op_rh_wl   (op_rh_wl  ),
  32. .op_addr    (op_addr   ),
  33. .op_wr_data (op_wr_data),
  34. .op_done    (op_done   ),
  35. .op_rd_data (op_rd_data),
  36. .op_rd_ack  (op_rd_ack),
  37. .dri_clk    (dri_clk   ),

  38. .eth_mdc    (eth_mdc   ),
  39. .eth_mdio   (eth_mdio  )
  40. );

  41. //MDIO接口读写控制   
  42. mdio_ctrl  u_mdio_ctrl(
  43. .clk           (dri_clk),
  44. .rst_n         (sys_rst_n),
  45. .soft_rst_trig (touch_key ),
  46. .op_done       (op_done   ),
  47. .op_rd_data    (op_rd_data),
  48. .op_rd_ack     (op_rd_ack),
  49. .op_exec       (op_exec   ),
  50. .op_rh_wl      (op_rh_wl  ),
  51. .op_addr       (op_addr   ),
  52. .op_wr_data    (op_wr_data),
  53. .led           (led       )
  54. );

  55. endmodule
复制代码
    顶层模块主要完成对其余模块的例化。在程序的第24行将系统复位(sys_rst_n)直接赋值给以太网的硬件复位信号(eth_rst_n),当复位按键按下时,会对PHY芯片进行硬件复位。
    在程序的第28行和29行代码例化了两个参数,分别表示PHY地址和ETH_MDC相对于输入时钟的分频系数。这里将PHY地址设置为5’h19,如果PHY地址设置错误,会导致对MDIO接口的读写操作失败。另外需要注意的是,ETH_MDC的时钟频率不能超过12.5Mhz。
    由前面的MDIO接口读写时序图我们可以发现,MDIO驱动模块非常适合采用状态机来编写。状态机的状态跳转图如图24.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状态。在读或者写完数据后,状态机重新跳转至空闲状态。
image032.gif
24.4.3状态跳转图
     程序中我们采用的是三段式状态机,由于代码较长,这里仅贴出部分代码,代码如下:
  1. //wire define
  2. wire          mdio_in    ;//MDIO数据输入
  3. wire[5:0  clk_divide ;//PHY_CLK的分频系数

  4. assign eth_mdio = mdio_dir ?mdio_out :1'bz;//控制双向io方向
  5. assign mdio_in = eth_mdio;//MDIO数据输入
  6. //将PHY_CLK的分频系数除以2,得到dri_clk的分频系数,方便对MDC和MDIO信号操作
  7. assign clk_divide = CLK_DIV >>1;

  8. //分频得到dri_clk时钟
  9. always@(posedge clk ornegedge rst_n)begin
  10. if(!rst_n)begin
  11.           dri_clk <=1'b0;
  12.           clk_cnt <=1'b0;
  13. end
  14. elseif(clk_cnt == clk_divide[5:1]-1'd1)begin
  15.           clk_cnt <=1'b0;
  16.           dri_clk <=~dri_clk;
  17. end
  18. else
  19.           clk_cnt <=clk_cnt +1'b1;
  20. end

  21. //产生PHY_MDC时钟
  22. always@(posedge dri_clk ornegedge rst_n)begin
  23. if(!rst_n)
  24.           eth_mdc <=1'b1;
  25. elseif(cnt[0]==1'b0)
  26.           eth_mdc <=1'b1;
  27. else
  28.           eth_mdc <=1'b0;
  29. end
  30. 省略部分代码……
  31.              st_wr_data :begin
  32. case(cnt)
  33. 7'd1: mdio_out <=1'b1;//发送TA,写操作(2'b10)
  34. 7'd3: mdio_out <=1'b0;
  35. 7'd5: mdio_out <= wr_data_t[15];//发送写寄存器数据
  36. 7'd7: mdio_out <= wr_data_t[14];
  37. 7'd9: mdio_out <= wr_data_t[13];
  38. 7'd11: mdio_out <= wr_data_t[12];
  39. 7'd13: mdio_out <= wr_data_t[11];
  40. 7'd15: mdio_out <= wr_data_t[10];
  41. 7'd17: mdio_out <= wr_data_t[9];
  42. 7'd19: mdio_out <= wr_data_t[8];
  43. 7'd21: mdio_out <= wr_data_t[7];
  44. 7'd23: mdio_out <= wr_data_t[6];
  45. 7'd25: mdio_out <= wr_data_t[5];
  46. 7'd27: mdio_out <= wr_data_t[4];
  47. 7'd29: mdio_out <= wr_data_t[3];
  48. 7'd31: mdio_out <= wr_data_t[2];
  49. 7'd33: mdio_out <= wr_data_t[1];
  50. 7'd35: mdio_out <= wr_data_t[0];
  51. 7'd37:begin
  52.                          mdio_dir <=1'b0;
  53.                          mdio_out <=1'b1;
  54. end
  55. 7'd39: st_done <=1'b1;
  56. 7'd40:begin
  57.                                 cnt <=7'b0;
  58.                                 op_done <=1'b1;//写操作完成,拉高op_done信号
  59. end
  60. default:;
  61. endcase
  62. end
  63.              st_rd_data :begin
  64. case(cnt)
  65. 7'd1:begin
  66.                          mdio_dir <=1'b0;//MDIO引脚切换至输入状态
  67.                          mdio_out <=1'b1;
  68. end
  69. 7'd2:;//TA[1]位,该位为高阻状态,不操作            
  70. 7'd4: op_rd_ack = mdio_in;//TA[0]位,0(应答) 1(未应答)
  71. 7'd6: rd_data_t[15]<= mdio_in;//接收寄存器数据
  72. 7'd8: rd_data_t[14]<= mdio_in;
  73. 7'd10: rd_data_t[13]<= mdio_in;
  74. 7'd12: rd_data_t[12]<= mdio_in;
  75. 7'd14: rd_data_t[11]<= mdio_in;
  76. 7'd16: rd_data_t[10]<= mdio_in;
  77. 7'd18: rd_data_t[9]<= mdio_in;
  78. 7'd20: rd_data_t[8]<= mdio_in;
  79. 7'd22: rd_data_t[7]<= mdio_in;
  80. 7'd24: rd_data_t[6]<= mdio_in;
  81. 7'd26: rd_data_t[5]<= mdio_in;
  82. 7'd28: rd_data_t[4]<= mdio_in;
  83. 7'd30: rd_data_t[3]<= mdio_in;
  84. 7'd32: rd_data_t[2]<= mdio_in;
  85. 7'd34: rd_data_t[1]<= mdio_in;
  86. 7'd36: rd_data_t[0]<= mdio_in;
  87. 7'd39: st_done <=1'b1;
  88. 7'd40:begin
  89.                          op_done <=1'b1;//读操作完成,拉高op_done信号         
  90.                          op_rd_data <= rd_data_t;
  91.                          rd_data_t <=16'd0;
  92.                          cnt <=7'd0;
  93. end
  94. default:;
  95. 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等于10,因此clk_divide等于5,dri_clk的时钟频率为12.5Mhz,eth_mdc为6.25Mhz。
     程序的第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接口读操作的ILA波形图如下图所示:
image034.jpg
24.4.4 MDIO接口读操作ILA波形图
     由上图可知,op_exec的脉冲信号作为MDIO接口读写的触发信号,图中op_rh_wl为高电平,表示读操作,op_addr寄存器地址为5’h19。在TA位时,mdio_dir由高电平切换至低电平,表示MDIO引脚由输出切换至输入,随后op_rd_ack变为低电平,说明PHY芯片应答成功。在整个读操作结束后,MDIO驱动模块产生一个脉冲的op_done信号,此时从状态寄存器中读出的数据为0x871c。
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. outputreg          op_exec       ,//触发开始信号
  9. outputreg          op_rh_wl      ,//低电平写,高电平读
  10. outputreg[4:0   op_addr      ,//寄存器地址
  11. outputreg[15:0  op_wr_data   ,//写入寄存器的数据
  12. output[1:0   led             //LED灯指示以太网连接状态
  13. );

  14. //reg define
  15. reg          rst_trig_d0;
  16. reg          rst_trig_d1;
  17. reg          rst_trig_flag;//soft_rst_trig信号触发标志
  18. reg[23:0  timer_cnt;//定时计数器
  19. reg          timer_done;//定时完成信号
  20. reg[1:0   flow_cnt;//流程控制计数器
  21. reg[1:0   speed_status;//连接速率

  22. //wire define
  23. wire         pos_rst_trig;//soft_rst_trig信号上升沿

  24. //采soft_rst_trig信号上升沿
  25. assign pos_rst_trig =~rst_trig_d1 &rst_trig_d0;
  26. //连接速率00:未连接或连接失败 01:10Mbps 10:100Mbps  11:1000Mbps
  27. assign led = speed_status;

  28. //对soft_rst_trig信号延时打拍
  29. always@(posedge clk ornegedge rst_n)begin
  30. if(!rst_n)begin
  31.           rst_trig_d0 <=1'b0;
  32.           rst_trig_d1 <=1'b0;
  33. end
  34. elsebegin
  35.           rst_trig_d0 <= soft_rst_trig;
  36.           rst_trig_d1 <= rst_trig_d0;
  37. end
  38. end

  39. //定时计数
  40. always@(posedge clk ornegedge rst_n)begin
  41. if(!rst_n)begin
  42.           timer_cnt <=1'b0;
  43.           timer_done <=1'b0;
  44. end
  45. elsebegin
  46. if(timer_cnt ==24'd1_000_000-1'b1)begin
  47.               timer_done <=1'b1;
  48.               timer_cnt <=1'b0;
  49. end
  50. elsebegin
  51.               timer_done <=1'b0;
  52.               timer_cnt <= timer_cnt +1'b1;
  53. end
  54. end
  55. end

  56. //根据软复位信号对MDIO接口进行软复位,并定时读取以太网的连接状态
  57. always@(posedge clk ornegedge rst_n)begin
  58. if(!rst_n)begin
  59.           flow_cnt <=2'd0;
  60.           rst_trig_flag <=1'b0;
  61.           speed_status <=1'b0;
  62.           op_exec <=1'b0;
  63.           op_rh_wl <=1'b0;
  64.           op_addr <=1'b0;
  65.           op_wr_data <=1'b0;
  66. end
  67. elsebegin
  68.           op_exec <=1'b0;
  69. if(pos_rst_trig)
  70.               rst_trig_flag <=1'b1;//拉高软复位触发标志
  71. case(flow_cnt)
  72. 2'd0:begin
  73. if(rst_trig_flag)begin//开始对MDIO接口进行软复位
  74.                       op_exec <=1'b1;
  75.                       op_rh_wl <=1'b0;
  76.                       op_addr <=5'h00;
  77.                       op_wr_data <=16'hB100;//Bit[15]=1'b1,表示软复位
  78.                       flow_cnt <=3'd1;
  79. end
  80. elseif(timer_done)begin//定时完成,获取以太网连接状态
  81.                       op_exec <=1'b1;
  82.                       op_rh_wl <=1'b1;
  83.                       op_addr <=5'h19;
  84.                       flow_cnt <=3'd2;
  85. end
  86. end
  87. 2'd1:begin
  88. if(op_done)begin//MDIO接口软复位完成
  89.                       flow_cnt <=3'd0;
  90.                       rst_trig_flag <=1'b0;
  91. end
  92. end
  93. 2'd2:begin
  94. if(op_done)begin//MDIO接口读操作完成
  95. if(op_rd_ack ==1'b0)//MDIO接口成功应答
  96.                          flow_cnt <=3'd3;
  97. else
  98.                          flow_cnt <=3'd0;
  99. end
  100. end
  101. 2'd3:begin
  102.                  flow_cnt <=2'd0;
  103. //根据MDIO接口读到的数据,解析以太网的连接状态
  104. if(op_rd_data[15]==1'b1&&op_rd_data[2]==1'b1)begin
  105. if(op_rd_data[10:9]==2'b11)
  106.                          speed_status <=2'b11;//1000Mbps
  107. elseif((op_rd_data[10:9]==2'b10)||(op_rd_data[10:8]==3'b011))
  108.                          speed_status <=2'b10;//100Mbps
  109. elseif((op_rd_data[10:8]==3'b010)||(op_rd_data[10:8]==3'b001))
  110.                          speed_status <=2'b01;//10Mbps
  111. else
  112.                          speed_status <=2'b00;//连接失败或者自协商尚未完成
  113. end
  114. else
  115.                      speed_status <=2'b00;//连接失败或者自协商尚未完成
  116. end
  117. endcase
  118. end
  119. end

  120. endmodule
复制代码
     程序中第44至第60行代码实现计数定时的功能,每当计数器计数到1000000-1时,会产生一个周期的脉冲信号(timer_done)。该模块输入的时钟频率为6.25Mhz,因此定时周期为160ms。
     程序中第62行至第125行代码根据软复位信号对MDIO接口进行软复位,并定时读取以太网的连接状态。其中程序中第107行至122行代码,根据状态寄存器的值,为连接速率状态位(speed_status)赋值。
1.5 下载验证
     将下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,将网线一端连接开发板的PL网口(GE_PL),另一端连接电脑的网口或者路由器,接下来连接电源线,并打开开发板的电源开关。GE_PL网口的位置如下图所示。
image036.gif
24.5.1 GE_PL网口位置
     点击Vivado左侧“FlowNavigator”窗口最下面的“Open Hardware Manager”,此时Vivado软件识别到下载器,点击“Hardware”窗口中“Program Device”下载程序,在弹出的界面中选择“Program”下载程序。
程序下载完成后,等待几秒即可看到底板PL LED灯的点亮状态,如下图所示:
image038.gif
24.5.2开发板实验现象
     如上图可知,PL的两个LED灯都处于点亮状态,因此通信速率为1000Mbps。如果按下复位按键可以对PHY进行硬件复位,按下TPAD触摸按键会对PHY进行软复位,此时PHY芯片会重新开始与另一端设备进行自协商,等待几秒后,PL LED灯重新点亮。
     另外,如果开发板另一端连接的是电脑的网口,此时可以查看自协商后的通信速率。查看方法是点击电脑右下角的网络图标,会看到本地连接刚开始显示的是正在识别,一段时间之后显示未识别的网络,打开方式如下图所示(WIN7和WIN10操作可能存在差异,但基本相同)。
image040.jpg
24.5.3点击网络图标
点击图24.5.3中的“未识别的网络(无Internet)”,弹出如下图所示界面。
image042.jpg
24.5.4网络设置界面
点击“更改适配器”选项,弹出如下图所示界面。
image044.jpg
24.5.5“网络适配器界面”
如果看到上图“以太网”显示未识别的网络之后,说明硬件连接是没有问题的,接下来鼠标右击以太网,选择“连接”,如图24.5.6和图24.5.7所示。
image046.jpg
24.5.6鼠标右击后选择状态
image048.jpg
24.5.7以太网连接速度
由上图可知,开发板和电脑自协商的通信速率为1Gbps(1000Mbps)。



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-10-3 11:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表