解决方案

PHY之MDIO解析

seo靠我 2023-09-24 03:57:00

概述

管理MII接口的MDIO接口是一个双线的串行接口,用来对PHY芯片等物理层信息进行操作管理

MDIO

MDIO(Management Data Input/Output),对G比特以太网而言,串行通信SEO靠我总线称为管理数据输入输出 (MDIO)。

MDIO由两根线组成,MDC线是数据的随路时钟,最高速率可达几MHz(各PHY芯片有异)。MDIO线是数据的输入输出双向总线,数据是与MDC时钟同步的。

MDIOSEO靠我前后有两种协议, 包括之前的Clause22 以及之后为了弥补Clause22 寄存器空间不足而出的Clause45, Clause 45 向前兼容Clause 22。

Clause 22

Clause SEO靠我22 的时序图如下:

STA:Station Management

MMD:MDIO Managed Device

PRE:帧前导码,为32个连续“1”比特。

ST:帧开始标志, Clause22 的开始标志SEO靠我为比特“01”。

OP:操作码,CL22中比特“10”表示此帧为一读操作帧,比特“01”表示此帧为一写操作帧。

PHYAD:MMD的物理地址,5个比特,每个MMD都把自己的地址与这5个比特进行比较,若匹配SEO靠我则响应后面的操作,若不匹配,则忽略掉后面的操作。

REGAD:用来选MMD的32个寄存器中的某个寄存器的地址。

TA:状态转换域,若为读操作,则第一比特时MDIO为高阻态,第二比特时由MMD使MDIO置“SEO靠我0”。若为写操作,则MDIO仍由STA控制,连续输出“10”两个比特。

DATA:帧的寄存器的数据域,16比特,若为读操作,则为MMD送到STA的数据,若为写操作,则为STA送到MMD数据。

IDLE:帧SEO靠我结束后的空闲状态,此时MDIO无源驱动,处高阻状态。

Clause 45

Clause 45 的时序图如下:

STA:Station Management

MMD:MDIO Managed Device

PRESEO靠我:帧前导码,为32个连续“1”比特。

ST:帧开始标志, 为了区别CL22,Clause45 的开始标志为比特“00”。

OP:操作码,Clause45有4种操作码,比特“00”表示设置当前寄存器地址,比SEO靠我特“01”表示写当前寄存器。比特“10”表示读当前寄存器,比特“11”表示读当前寄存器读完后把当前寄存器的值加1,用于顺序读。

PRTAD:Port Address,端口地址, 也称物理地址。

DEVADSEO靠我:器件地址,CL45新增概念,各值与器件对应如下。

REGAD:用来选MMD的65536个寄存器中的某个寄存器的地址。

TA:状态转换域,若为读操作,则第一比特时MDIO为高阻态,第二比特时由MMD使MDSEO靠我IO置“0”。若为写操作,则MDIO仍由STA控制,连续输出“10”两个比特。

DATA:帧的寄存器的数据域,16比特,若为读操作,则为MMD送到STA的数据,若为写操作,则为STA送到MMD数据。

IDSEO靠我LE:帧结束后的空闲状态,此时MDIO无源驱动,处高阻状态。

Problems with the MDIO

当MDIO通信出现问题,可依次检查以下方面

确保MDC工作在合适的频率

确保MDC以及MDIO有上拉SEO靠我

PHYAD(PRTAD)没有搞错。

MMD 没有处于复位状态。

适当调整MDC的相位。

有些MMD要求帧与帧之间一定要用高阻态分隔

STA MDIO 接口 Verilog 代码如下 `timescale 1nsSEO靠我 / 1ps//// Company: // Engineer: // // Create Date: 2019/08/12 10:39:51// Design Name: // Module NamSEO靠我e: eth_mdio_interface// Project Name: // Target Devices: // Tool Versions: // Description: // // DepSEO靠我endencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:  //      //module eSEO靠我th_mdio_interface #(parameter MDC_DIVISOR = 100      MDC frequency is clk_i / MDC_DIVISOR.  )(input SEO靠我              clk_i,input               rstn_i,input               clause_sel_i,1 : Clause 45;  0 : SEO靠我Clause 22;output  reg         ready_o,input               valid_i,input   [1:0]       cmd_i,input   SEO靠我[25:0]      addr_i,      Cl45: PHY Addr(5 bit) + Devices Addr(5 bit) + Reg Addr(16 bit); Cl22 : PHY SEO靠我Addr(5 bit) + Reg Addr(5 bit) + invalid(16 bit)//input   [15:0]      wdata_i,  output  reg         rSEO靠我data_vld_o,output  reg [15:0]  rdata_o,output  reg         mdc_o,input               mdio_i,output  SEO靠我reg         mdio_o,output  reg         mdio_oen_o);localparam  WR_CMD = 2b01;localparam  RD_CMD = 2bSEO靠我11; localparam  RD_INC = 2b10;  not supported//-----------------------------------------------------SEO靠我----------------------------------------------// Function - Calculates the log2ceil of the input valSEO靠我ue//------------------------------------------------------------------------------------------------SEO靠我---function integer log2ceil;input integer val;integer i;begini = 1;log2ceil = 0;while (i < val) begSEO靠我inlog2ceil = log2ceil + 1;i = i << 1; endendendfunction  localparam P_MDC_DIVIDE_BITS = log2ceil(MDCSEO靠我_DIVISOR) - 1;    // Need to count to (MDC_DIVISOR/2) - 1   reg [P_MDC_DIVIDE_BITS-1:0] mdc_divide; SEO靠我 reg mdc_tick;     reg mdc_sample;   Divide clock to make MDIO clock  always @(posedge clk_i, negedgSEO靠我e rstn_i) if(!rstn_i)mdc_divide <= 0;else if(mdc_divide == 0)      mdc_divide <= (MDC_DIVISOR/2) - 1SEO靠我b1;else mdc_divide <= mdc_divide - 1b1;always @(posedge clk_i, negedge rstn_i)if(!rstn_i)    mdc_o <SEO靠我= 1b0;else if(mdc_divide == 0)mdc_o <= ~mdc_o;Data is output on mdc_tick. Delay it slightly from theSEO靠我 clock to ensure setup and hold timing is metSample read data just before rising edge of MDCalways @SEO靠我(posedge clk_i, negedge rstn_i)if(!rstn_i) beginmdc_tick <= 1b0;mdc_sample <= 1b0;endelse beginmdc_tSEO靠我ick <= ~mdc_o & (mdc_divide==(MDC_DIVISOR/2) - (MDC_DIVISOR/4));mdc_sample <= ~mdc_o & (mdc_divide==SEO靠我2);endwire   [4:0]    cl45_phy_addr = addr_i[25:21];           wire   [4:0]    cl45_dev_addr = addr_SEO靠我i[20:16];           wire   [15:0]   cl45_reg_addr = addr_i[15:0];          wire   [4:0]    cl22_phy_SEO靠我addr = addr_i[25:21];              wire   [4:0]    cl22_reg_addr = addr_i[20:16];                   SEO靠我                                                        reg    [3:0]    state;localparam      ST_PRESEO靠我AMBLE1        = 4d0;localparam      ST_IDLE1            = 4d1;localparam      ST_WR_ADDR_CL45     = SEO靠我4d2;localparam      ST_IDLE2            = 4d3;localparam      ST_PREAMBLE2        = 4d4;localparam  SEO靠我    ST_REWR_ADDR_CL45   = 4d5;localparam      ST_WR_ADDR_CL22     = 4d6;localparam      ST_WR_DATA  SEO靠我        = 4d7;localparam      ST_RD_DATA          = 4d8;wire  preamble_set_done;wire  wr_addr_cl45_dSEO靠我one;wire  wr_addr_cl22_done;wire  rewr_addr_cl45_done;wire  wr_data_done;wire  rd_data_done;reg   wrSEO靠我_rdn_en;reg   cmd_pending;always @(posedge clk_i, negedge rstn_i)if(!rstn_i)state <= ST_IDLE1;else  SEO靠我case (state)ST_IDLE1               :   if(cmd_pending && mdc_tick)state <= ST_PREAMBLE1; else state SEO靠我<= ST_IDLE1;ST_PREAMBLE1           :   if(preamble_set_done)     state <= clause_sel_i? ST_WR_ADDR_CSEO靠我L45 : ST_WR_ADDR_CL22;else state <= ST_PREAMBLE1;                              ST_WR_ADDR_CL45      SEO靠我  :   if(wr_addr_cl45_done)state <= ST_IDLE2;else state <= ST_WR_ADDR_CL45;ST_IDLE2               : SEO靠我  if(mdc_tick)    state <= ST_PREAMBLE2;else state <= ST_IDLE2;                           ST_PREAMBLSEO靠我E2           :   if(preamble_set_done)state <= ST_REWR_ADDR_CL45;else state <= ST_PREAMBLE2;ST_REWR_SEO靠我ADDR_CL45      :   if(rewr_addr_cl45_done)state <= wr_rdn_en? ST_WR_DATA : ST_RD_DATA;  else state <SEO靠我= ST_REWR_ADDR_CL45;ST_WR_ADDR_CL22        :   if(wr_addr_cl22_done)state <= wr_rdn_en? ST_WR_DATA :SEO靠我 ST_RD_DATA;   else state <= ST_WR_ADDR_CL22;                          ST_WR_DATA             :   ifSEO靠我(wr_data_done)                               state <= ST_IDLE1;else state <= ST_WR_DATA;            SEO靠我                     ST_RD_DATA             :   if(rd_data_done)   state <= ST_IDLE1;else state <= SSEO靠我T_RD_DATA;       default                :   state <= ST_IDLE1;endcasewire latch_en;assign latch_en =SEO靠我 (ready_o && valid_i);  wait mdc_tick to startalways @(posedge clk_i, negedge rstn_i)if(!rstn_i)cmd_SEO靠我pending <= 1b0;else if(latch_en)cmd_pending <= 1b1;else if(mdc_tick)cmd_pending <= 1b0;always @(poseSEO靠我dge clk_i, negedge rstn_i)if(!rstn_i)wr_rdn_en <= 1b0;else if(latch_en)wr_rdn_en <= (cmd_i == WR_CMDSEO靠我);reg [5:0]  preamble_cnt;always @(posedge clk_i, negedge rstn_i)if(!rstn_i)preamble_cnt <= 6b0;elseSEO靠我 if(state != ST_PREAMBLE1 && state != ST_PREAMBLE2)   preamble_cnt <= 6b0; else if(mdc_tick)preambleSEO靠我_cnt <= preamble_cnt + 6b1;assign preamble_set_done = (preamble_cnt == 6d31) && mdc_tick;reg [5:0] wSEO靠我r_addr_cl45_cnt;always @(posedge clk_i, negedge rstn_i)if(!rstn_i)wr_addr_cl45_cnt <= 6b0;else if(stSEO靠我ate != ST_WR_ADDR_CL45)wr_addr_cl45_cnt <= 6b0;else if(mdc_tick)wr_addr_cl45_cnt <= wr_addr_cl45_cntSEO靠我 + 6b1;assign wr_addr_cl45_done = (wr_addr_cl45_cnt == 6d31) && mdc_tick; reg [4:0] rewr_addr_cl45_cSEO靠我nt;  always @(posedge clk_i, negedge rstn_i)if(!rstn_i)rewr_addr_cl45_cnt <= 5b0;else if(state != STSEO靠我_REWR_ADDR_CL45)      rewr_addr_cl45_cnt <= 5b0;else if(mdc_tick)rewr_addr_cl45_cnt <= rewr_addr_cl4SEO靠我5_cnt + 5b1;assign rewr_addr_cl45_done = (rewr_addr_cl45_cnt == 5d13) && mdc_tick;reg [4:0] wr_addr_SEO靠我cl22_cnt;always @(posedge clk_i, negedge rstn_i)if(!rstn_i)wr_addr_cl22_cnt <= 5b0;else if(state != SEO靠我ST_WR_ADDR_CL22)wr_addr_cl22_cnt <= 5b0;else if(mdc_tick)wr_addr_cl22_cnt <= wr_addr_cl22_cnt + 5b1;SEO靠我assign wr_addr_cl22_done = (wr_addr_cl22_cnt == 5d13) && mdc_tick;reg [4:0] wr_data_cnt;always @(posSEO靠我edge clk_i, negedge rstn_i)if(!rstn_i)wr_data_cnt <= 5b0;else if(state != ST_WR_DATA)wr_data_cnt <= SEO靠我5b0;else if(mdc_tick)wr_data_cnt <= wr_data_cnt + 5b1;assign wr_data_done = (wr_data_cnt == 5d17) &&SEO靠我 mdc_tick;reg [4:0] rd_data_cnt;always @(posedge clk_i, negedge rstn_i)if(!rstn_i)rd_data_cnt <= 5b0SEO靠我;else if(state != ST_RD_DATA)rd_data_cnt <= 5b0;else if(mdc_tick)rd_data_cnt <= rd_data_cnt + 5b1;asSEO靠我sign rd_data_done = (rd_data_cnt == 5d17) && mdc_tick; always @(posedge clk_i, negedge rstn_i)if(!rsSEO靠我tn_i)ready_o = 1b0;else ready_o = (state == ST_IDLE1) && (!valid_i) && (!cmd_pending);reg [1:0] op_cSEO靠我ode_cl45;always @(*)case (cmd_i)WR_CMD : op_code_cl45 = 2b01;RD_CMD : op_code_cl45 = 2b11;RD_INC : oSEO靠我p_code_cl45 = 2b10;default : op_code_cl45 = 2b11;endcasereg [1:0] op_code_cl22;always @(*)case (cmd_SEO靠我i)WR_CMD : op_code_cl22 = 2b01;RD_CMD : op_code_cl22 = 2b10;default : op_code_cl22 = 2b11;endcaseregSEO靠我 [31:0] first_wraddr_sfr_cl45;always @(posedge clk_i)if(latch_en)first_wraddr_sfr_cl45 <= {2b00, 2b0SEO靠我0, cl45_phy_addr, cl45_dev_addr, 2b10, cl45_reg_addr};else if((state == ST_WR_ADDR_CL45) && mdc_tickSEO靠我)first_wraddr_sfr_cl45 <= {first_wraddr_sfr_cl45[30:0], 1b0};reg [13:0] second_wraddr_sfr_cl45;alwaySEO靠我s @(posedge clk_i)if(latch_en)second_wraddr_sfr_cl45 <= {2b00, op_code_cl45, cl45_phy_addr, cl45_devSEO靠我_addr};else if((state == ST_REWR_ADDR_CL45) && mdc_tick)second_wraddr_sfr_cl45 <= {second_wraddr_sfrSEO靠我_cl45[12:0], 1b0};reg [13:0]  wraddr_sfr_cl22;always @(posedge clk_i)  if(latch_en)wraddr_sfr_cl22 <SEO靠我= {2b01, op_code_cl22, cl22_phy_addr, cl22_reg_addr};else if((state == ST_WR_ADDR_CL22) && mdc_tick)SEO靠我wraddr_sfr_cl22 <= {wraddr_sfr_cl22[12:0], 1b0};reg [17:0] wrdata_sfr;always @(posedge clk_i)if(latcSEO靠我h_en)wrdata_sfr <= {2b10, wdata_i};else if((state == ST_WR_DATA) && mdc_tick)      wrdata_sfr <= {wrSEO靠我data_sfr[16:0], 1b0};reg [15:0] rddata_sfr;always @(posedge clk_i)if((state == ST_RD_DATA) && mdc_saSEO靠我mple)  rddata_sfr <= {rddata_sfr[14:0], mdio_i};always @(posedge clk_i, negedge rstn_i)if(!rstn_i)mdSEO靠我io_o <= 1b0;else case (state)ST_WR_ADDR_CL45    : mdio_o <= first_wraddr_sfr_cl45[31];ST_REWR_ADDR_CSEO靠我L45  : mdio_o <= second_wraddr_sfr_cl45[13];ST_WR_ADDR_CL22    : mdio_o <= wraddr_sfr_cl22[13];ST_WRSEO靠我_DATA         : mdio_o <= wrdata_sfr[17];default            : mdio_o <= 1b1;endcasealways @(posedge SEO靠我clk_i, negedge rstn_i)if(!rstn_i)mdio_oen_o <= 1b1;else mdio_oen_o <= (state != ST_RD_DATA)&&(state SEO靠我!= ST_IDLE1)&&(state != ST_IDLE2);always @(posedge clk_i, negedge rstn_i)if(!rstn_i) beginrdata_vld_SEO靠我o <= 1b0;rdata_o <= 16b0;endelse if(rd_data_done) beginrdata_vld_o <= 1b1;rdata_o <= rddata_sfr;endeSEO靠我lse beginrdata_vld_o <= 1b0;rdata_o <= rdata_o;endendmodule

实际使用时抓取的波形

————————————————

原文链接:https://blSEO靠我og.csdn.net/yhs18200259681/article/details/99652701
“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2