管理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 SEO靠我22 的时序图如下:
STA:Station Management
MMD:MDIO Managed DevicePRE:帧前导码,为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 的时序图如下:
STA:Station Management
MMD:MDIO Managed DevicePRESEO靠我:帧前导码,为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网站备案号:浙ICP备17034767号-2