一、以太網(wǎng)簡介
????????是當今現(xiàn)有局域網(wǎng)采用的最通用的通信協(xié)議標準,它規(guī)定了包括物理層的連線、電子信號和介質(zhì)訪問層協(xié)議的內(nèi)容。成本低,通信速率高,抗干擾能力強。
? ? ? ? 1、分類
標準以太網(wǎng):10Mbit/s
快速以太網(wǎng):100Mbit/s
千兆以太網(wǎng):1000Mbit/s
.........
以太網(wǎng)和千兆網(wǎng)口其實不完全相同。以太網(wǎng)是一種局域網(wǎng)技術標準,而千兆網(wǎng)口通常指的是支持1Gb/s(即千兆位每秒)速度的網(wǎng)絡接口。
以太網(wǎng)是一種通用的局域網(wǎng)技術標準,定義了數(shù)據(jù)傳輸?shù)囊?guī)范和硬件設備之間的通信方式。而千兆網(wǎng)口是一種物理接口標準,用于連接計算機或其他網(wǎng)絡設備到網(wǎng)絡中,支持更高的數(shù)據(jù)傳輸速度。
因此,可以說千兆網(wǎng)口是以太網(wǎng)的一種實現(xiàn)方式,它提供了更快的數(shù)據(jù)傳輸速度,但并不等同于以太網(wǎng)。在實際應用中,通常會使用以太網(wǎng)技術,并通過千兆網(wǎng)口進行連接,以實現(xiàn)更快的網(wǎng)絡通信速度。
? ? ? ? 2、以太網(wǎng)接口
????????以太網(wǎng)通信離不開連接端口的支持,網(wǎng)絡數(shù)據(jù)連接的端口就是以太網(wǎng)接口。以太網(wǎng)接口類型有RJ45接口,RJ11接口(電話線接口),SC光纖接口等其中RJ45接口是我們現(xiàn)在最常見的網(wǎng)絡設備接口(如:電腦網(wǎng)口)
3、6一對是為了向下兼容10/100M
上圖為RGMII接口,時鐘為雙沿2.5MHz、25MHz、250MHz。位寬為4位。(節(jié)省引腳)
GMII接口,時鐘為單沿1.25MHz、12.5MHz、125MHz。位寬為8位。
MAC側完成對報文的封包和解包過程
PHY芯片:實現(xiàn)模數(shù)轉換
ETH_RXC | 接收端時鐘 |
ETH_RXCTL | 接收端數(shù)據(jù)使能(接受報文有效,該引腳拉高) |
ETH_RXD[3:0] | 接收數(shù)據(jù) |
ETH_TXC | 發(fā)送端時鐘 |
ETH_TXCTL | 發(fā)送端數(shù)據(jù)使能(發(fā)送報文有效,該引腳拉高) |
ETH_TXD[3:0] | 發(fā)送數(shù)據(jù) |
ETH_RST_N | 復位腳 |
ETH_MDC | |
ETH_MDIO |
MDIO接口:(默認即可實現(xiàn)功能)
? ? ? ? 3、UDP網(wǎng)絡協(xié)議簡介
UDP(User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議)是一種無連接的網(wǎng)絡傳輸協(xié)議,位于OSI模型的傳輸層。以下是UDP網(wǎng)絡協(xié)議的簡介:
? ? ? ? ? ? ? ? (1)無連接性:UDP是一種無連接的協(xié)議,發(fā)送端在發(fā)送數(shù)據(jù)之前不需要與接收端建立連接,也不會維護連接狀態(tài)。
? ? ? ? ? ? ? ? (2)面向數(shù)據(jù)報:UDP以數(shù)據(jù)報(Datagram)的形式傳輸數(shù)據(jù),每個數(shù)據(jù)報都是獨立的,互相之間沒有關聯(lián)。
? ? ? ? ? ? ? ? (3)不可靠性:UDP不提供數(shù)據(jù)可靠性保證,數(shù)據(jù)報可能會丟失、重復或無序到達。也不會進行數(shù)據(jù)校驗和重傳。
? ? ? ? ? ? ? ? (4)高效性:由于沒有連接建立和維護的開銷,以及簡化的功能,UDP比TCP更輕量級,傳輸效率更高。
? ? ? ? ? ? ? ? (5)適用場景:UDP適用于對實時性要求高、數(shù)據(jù)傳輸完整性要求不高的應用場景,如音頻、視頻流媒體傳輸、在線游戲等。
????????????????總的來說,UDP是一種簡單、高效但不可靠的網(wǎng)絡傳輸協(xié)議,適用于對實時性要求高、能容忍少量數(shù)據(jù)丟失的應用場景。
? ? ? ? 4、數(shù)據(jù)鏈路
????????數(shù)據(jù)通過FPGA進行數(shù)據(jù)協(xié)議的打包和MAC協(xié)議處理,通過RGMII總線協(xié)議傳輸將數(shù)據(jù)傳送至PHY芯片,PHY芯片將數(shù)據(jù)進行處理后發(fā)送至RJ45接口進行數(shù)據(jù)發(fā)送。
????????物理層(RJ45網(wǎng)口接口)、數(shù)據(jù)鏈路層(PHY芯片和MAC協(xié)議)、網(wǎng)絡層(在FPGA中處理的MAC協(xié)議)、傳輸層(在FPGA中處理的數(shù)據(jù)協(xié)議打包,用UDP或者TCP協(xié)議就是說的這一層)
二、以太網(wǎng)PHY芯片簡介RTL8211
? ? ? ? 1、PHY芯片:物理層芯片(物理接口收發(fā)器)
????????????????自動協(xié)商通信速率,或自行配置
? ? ? ? 2、BMCI寄存器配置(RTL8211為例)
? ? ? ? ? ? ? ? BMCI寄存器addr為:0x00
? ? ? ? ? ? ? ? (1)0.15:軟件復位,1復位,0工作。結束復位后,無需手動寫0,結束復位會自動歸0,
? ? ? ? ? ? ? ? (2)0.14:環(huán)回,主要用于檢測,1使能,0失能。
? ? ? ? ? ? ? ? (3)0.13,0.6:Speed配置,配置不同速率(先失能自協(xié)商)?
? ? ? ? ? ? ? ? (4)0.12:自協(xié)商配置,默認使能,1使能,0失能。
? ? ? ? ? ? ? ? (5)0.11:掉電模式配置,1掉電模式,0正常工作模式。
? ? ? ? ? ? ? ? (6)0.10:隔離配置,RGMII接口隔離,引腳失能,只有MDIO,MDC配置有效
? ? ? ? ? ? ? ? (7)0.9:重新開始自協(xié)商配置。
? ? ? ? ? ? ? ? (8)0.8:雙工模式配置
? ? ? ? ? ? ? ? (9)0.7:沖突測試
? ? ? ? ? ? ? ? (10)0.5:單向使能:1雙方建立連接成功后通信,0直接通信
? ? ? ? 3、BMSR寄存器配置
? ? ? ? ? ? ? ? BMCI寄存器addr為:0x01
? ? ? ? ? ? ? ? ? ? ? ? (1)1.5:自協(xié)商完成
? ? ? ? ? ? ? ? ? ? ? ? (2)1.2:是否連接OK
????????4、PHYSR寄存器配置
? ? ? ? ? ? ? ? BMCI寄存器addr為:0x11
? ? ? ? ? ? ? ? (1)17.15:14? :連接速率(前提link ok,自協(xié)商完成)
三、以太網(wǎng)PHY芯片簡介YT8531
? ? ? ? 1、PHY芯片
網(wǎng)線差分模擬信號轉換數(shù)字信號,F(xiàn)PGA數(shù)字信號轉換網(wǎng)線差分模擬信號。
? ? ? ? 2、引腳復用
? ? ? ? 3、硬件原理圖(正點原子達芬奇開發(fā)板)
22R電阻做阻抗匹配。
? ? ? ? 4、PHY地址接口
一定會響應0x00??!
? ? ? ? 5、基本控制寄存器配置
寄存器地址0x00
? ? ? ? ? ? ? ? (1)?15:軟復位,帶自清0,默認為0 。0工作,1復位。
? ? ? ? ? ? ? ? (2) 14:內(nèi)部環(huán)回,默認為0。0失能,1使能。
? ? ? ? ? ? ? ? (3) 13:速率配置低位,關閉自協(xié)商才可以使用,bit6,13進行配置。
? ? ? ? ? ? ? ? (4) 12:自協(xié)商使能,默認支持。1使能,0失能。
? ? ? ? ? ? ? ? (5) 11:掉電模式,1掉電,0正常。
? ? ? ? ? ? ? ? (6) 10:隔離模式,一般為0正常模式
? ? ? ? ? ? ? ? (7) 9:重新自協(xié)商,自帶置1。
? ? ? ? ? ? ? ? (8) 8:配置雙工,關閉自協(xié)商才可以使用,1雙工,0半雙工。
? ? ? ? 6、基本狀態(tài)寄存器配置?
寄存器地址0x01
? ? ? ? ? ? ? ? (1) 13:雙工模式檢測。? ? ? ? 0:半雙工,? ? ? ? ?1:全雙工。
? ? ? ? ? ? ? ? (2) 15~14:傳輸速度等級檢測。10:1000M? ? ? 01:100M? ? ? ?00:10M
? ? ? ? ? ? ? ? (3) 2:連接狀態(tài)。? ? ? 1:連接已建立,? ? ? ? 0:鏈接未建立。
? ? ? ? ? ? ? ? (4) 3:自協(xié)商能力,? ? 1具有,? ? ? 0不具備。
? ? ? ? ? ? ? ? (5) 4:遠端錯誤指示位:讀取后自動清0? ? ? ? ?0:遠端設備正常? ? 1:遠端設備異常
? ? ? ? ? ? ? ? (6) 5:自協(xié)商完成標志,軟復位后自動清0? ? ? ?1:完成自協(xié)商? ? ? 0:未完成自協(xié)商。
? ? ? ? ? ? ? ? (7) 6:前導碼模式,1:不檢測前導碼直接接受? ? ? ? 0:檢測前導碼
? ? ? ? ? ? ? ? (8) 7:單項傳輸能力:0:當檢測到建立有效連接才開始傳輸? ? ?1:直接開始傳輸。
? ? ? ? 7、特定狀態(tài)寄存器
寄存器地址0x11
四、MDIO接口時序
????????MDIO: Management Data Input/Output
????????也被稱為SMI ( Serial Management Interface ) ,即串行管理接口。
????????MAC和 PHY芯片有一個配置接口,即MDIO接口,可以配置 PHY芯片的工作模式以及獲取 PHY芯片的若干狀態(tài)信息。?
????????1、MDIO接口連接圖
? ? ? ? 2、PHY幀格式
????????管理接口通過MDC和MDIO引腳提供對內(nèi)部寄存器的訪問,如IEEE802.3u第22節(jié)所述。MDC信號由MAC提供,是MDIO信號的管理數(shù)據(jù)時鐘參考。MDIO是管理數(shù)據(jù)的輸入/輸出,是一個雙向信號,與MDC同步運行。MDIO引腳需要一個1.5k歐姆的上拉電阻,以在空閑和周轉期間保持MDIO高電平。
前置抑制為RTL8211E/RTL8211EG上電后的默認設置。然而,在操作之間仍然必須至少有一個空閑位。RTL8211E/RTL8211EG可以共享同一條MDIO線。在交換機/路由器應用程序中,每個端口應該在硬件復位序列中分配一個唯一的地址,并且只能通過該唯一的PHY地址進行尋址。有關RTL8211E/RTL8211EG管理寄存器的詳細信息,請參見第30頁第8節(jié)寄存器描述。
寫狀態(tài)下,一直由FPGA輸出數(shù)據(jù)給到PHY芯片;讀狀態(tài)下,在TA位切換方向
? ? ? ? ? ? ? ? (1)Preamble:前導碼,32個邏輯1,同時給出時鐘。
? ? ? ? ? ? ? ? (2)ST:幀開始。固定01
? ? ? ? ? ? ? ? (3)OP:操作碼,指示當前讀寫
? ? ? ? ? ? ? ? (4)PHYAD:PHY地址
? ? ? ? ? ? ? ? (5)REGAD:寄存器地址
? ? ? ? ? ? ? ? (6)TA:2bit寬度,時間間隔,切換FPGA數(shù)據(jù)線方向。Z為高阻狀態(tài),0為應答。
? ? ? ? ? ? ? ? (7)DATA:數(shù)據(jù)?
? ? ? ? 3、PHY讀寫傳輸時序
? ? ? ? ? ? ? ? ? ? ? ? 上升沿采集數(shù)據(jù),下降沿更新數(shù)據(jù);MDC的最小周期為80ns對應時鐘最大為12.5MHz?
?
五、MDIO讀寫測試實驗
? ? ? ? PHY芯片不進行配置也可以使用?
? ? ? ? 1、系統(tǒng)框圖
? ? ? ? 2、模塊原理圖
u_mdio_dri模塊:
op_addr:讀寫地址
op_exec:觸發(fā)信號↓↓↓↓↓↓↓↓↓↓↓
op_rh_wl:讀寫標志信號? ? 1讀? ? 0寫
op_wr_data:具體寫入數(shù)據(jù)
op_done:讀寫結束后,拉高該信號
op_rd_ack:讀應答信號? ? 0應答? ? ?1未應答(幀格式里面的AT)
op_rd_data:讀出的信號
dri_clk:驅動時鐘
?當op_exec信號拉高標志一次讀寫操作開始,根據(jù)op_rh_wl狀態(tài)判斷讀寫操作,同時給出讀寫操作地址op_addr(如果是寫操作要對應給出op_wr_data),讀寫操作結束后,拉高op_done信號,表示當前讀寫操作完成,控制模塊可以發(fā)起下一次操作(如果是寫讀操作,在op_done為高期間,如果是0表示應答,如果是1表示未應答)(如果讀操作,在op_done為高期間,會返回讀到的數(shù)據(jù))。
? ? ? ? 3、狀態(tài)機
? ? ? ? 4、用戶接口時序
? ? ? ? 5、程序設計
? ? ? ? ? ? ? ? (1)mdio_dri模塊
module mdio_dri #(
parameter PHY_ADDR = 5'b00100,//PHY地址
parameter CLK_DIV = 6'd10 //分頻系數(shù)
)
(
input clk , //時鐘信號
input rst_n , //復位信號,低電平有效
input op_exec , //觸發(fā)開始信號
input op_rh_wl , //低電平寫,高電平讀
input [4:0] op_addr , //寄存器地址
input [15:0] op_wr_data, //寫入寄存器的數(shù)據(jù)
output reg op_done , //讀寫完成
output reg [15:0] op_rd_data, //讀出的數(shù)據(jù)
output reg op_rd_ack , //讀應答信號 0:應答 1:未應答
output reg dri_clk , //驅動時鐘
output reg eth_mdc , //PHY管理接口的時鐘信號
inout eth_mdio //PHY管理接口的雙向數(shù)據(jù)信號
);
//parameter define
localparam st_idle = 6'b00_0001; //空閑狀態(tài)
localparam st_pre = 6'b00_0010; //發(fā)送PRE(前導碼)
localparam st_start = 6'b00_0100; //開始狀態(tài),發(fā)送ST(開始)+OP(操作碼)
localparam st_addr = 6'b00_1000; //寫地址,發(fā)送PHY地址+寄存器地址
localparam st_wr_data = 6'b01_0000; //TA+寫數(shù)據(jù)
localparam st_rd_data = 6'b10_0000; //TA+讀數(shù)據(jù)
//reg define
reg [5:0] cur_state ;
reg [5:0] next_state;
reg [5:0] clk_cnt ; //分頻計數(shù)
reg [15:0] wr_data_t ; //緩存寫寄存器的數(shù)據(jù)
reg [4:0] addr_t ; //緩存寄存器地址
reg [6:0] cnt ; //計數(shù)器
reg st_done ; //狀態(tài)開始跳轉信號
reg [1:0] op_code ; //操作碼 2'b01(寫) 2'b10(讀)
reg mdio_dir ; //MDIO數(shù)據(jù)(SDA)方向控制
reg mdio_out ; //MDIO輸出信號
reg [15:0] rd_data_t ; //緩存讀寄存器數(shù)據(jù)
//wire define
wire mdio_in ; //MDIO數(shù)據(jù)輸入
wire [5:0] clk_divide ; //PHY_CLK的分頻系數(shù)
assign eth_mdio = mdio_dir ? mdio_out : 1'bz; //控制雙向io方向
assign mdio_in = eth_mdio; //MDIO數(shù)據(jù)輸入
//將PHY_CLK的分頻系數(shù)除以2,得到dri_clk的分頻系數(shù),方便對MDC和MDIO信號操作
assign clk_divide = CLK_DIV >> 1;
//分頻得到dri_clk時鐘
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
dri_clk <= 1'b0;
clk_cnt <= 1'b0;
end
else if(clk_cnt == clk_divide[5:1] - 1'd1) begin
clk_cnt <= 1'b0;
dri_clk <= ~dri_clk;
end
else
clk_cnt <= clk_cnt + 1'b1;
end
//產(chǎn)生PHY_MDC時鐘
always @(posedge dri_clk or negedge rst_n) begin
if(!rst_n)
eth_mdc <= 1'b1;
else if(cnt[0] == 1'b0)
eth_mdc <= 1'b1;
else
eth_mdc <= 1'b0;
end
//(三段式狀態(tài)機)同步時序描述狀態(tài)轉移
always @(posedge dri_clk or negedge rst_n) begin
if(!rst_n)
cur_state <= st_idle;
else
cur_state <= next_state;
end
//組合邏輯判斷狀態(tài)轉移條件
always @(*) begin
next_state = st_idle;
case(cur_state)
st_idle : begin
if(op_exec)
next_state = st_pre;
else
next_state = st_idle;
end
st_pre : begin
if(st_done)
next_state = st_start;
else
next_state = st_pre;
end
st_start : begin
if(st_done)
next_state = st_addr;
else
next_state = st_start;
end
st_addr : begin
if(st_done) begin
if(op_code == 2'b01) //MDIO接口寫操作
next_state = st_wr_data;
else
next_state = st_rd_data; //MDIO接口讀操作
end
else
next_state = st_addr;
end
st_wr_data : begin
if(st_done)
next_state = st_idle;
else
next_state = st_wr_data;
end
st_rd_data : begin
if(st_done)
next_state = st_idle;
else
next_state = st_rd_data;
end
default : next_state = st_idle;
endcase
end
//時序電路描述狀態(tài)輸出
always @(posedge dri_clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 5'd0;
op_code <= 1'b0;
addr_t <= 1'b0;
wr_data_t <= 1'b0;
rd_data_t <= 1'b0;
op_done <= 1'b0;
st_done <= 1'b0;
op_rd_data <= 1'b0;
op_rd_ack <= 1'b1;
mdio_dir <= 1'b0;
mdio_out <= 1'b1;
end
else begin
st_done <= 1'b0 ;
cnt <= cnt +1'b1 ;
case(cur_state)
st_idle : begin
mdio_out <= 1'b1;
mdio_dir <= 1'b0;
op_done <= 1'b0;
cnt <= 7'b0;
if(op_exec) begin
op_code <= {op_rh_wl,~op_rh_wl}; //OP_CODE: 2'b01(寫) 2'b10(讀)
addr_t <= op_addr;
wr_data_t <= op_wr_data;
op_rd_ack <= 1'b1;
end
end
st_pre : begin //發(fā)送前導碼:32個1bit
mdio_dir <= 1'b1; //切換MDIO引腳方向:輸出
mdio_out <= 1'b1; //MDIO引腳輸出高電平
if(cnt == 7'd62)
st_done <= 1'b1;
else if(cnt == 7'd63)
cnt <= 7'b0;
end
st_start : begin
case(cnt)
7'd1 : mdio_out <= 1'b0; //發(fā)送開始信號 2'b01
7'd3 : mdio_out <= 1'b1;
7'd5 : mdio_out <= op_code[1]; //發(fā)送操作碼
7'd6 : st_done <= 1'b1;
7'd7 : begin
mdio_out <= op_code[0];
cnt <= 7'b0;
end
default : ;
endcase
end
st_addr : begin
case(cnt)
7'd1 : mdio_out <= PHY_ADDR[4]; //發(fā)送PHY地址
7'd3 : mdio_out <= PHY_ADDR[3];
7'd5 : mdio_out <= PHY_ADDR[2];
7'd7 : mdio_out <= PHY_ADDR[1];
7'd9 : mdio_out <= PHY_ADDR[0];
7'd11: mdio_out <= addr_t[4]; //發(fā)送寄存器地址
7'd13: mdio_out <= addr_t[3];
7'd15: mdio_out <= addr_t[2];
7'd17: mdio_out <= addr_t[1];
7'd18: st_done <= 1'b1;
7'd19: begin
mdio_out <= addr_t[0];
cnt <= 7'd0;
end
default : ;
endcase
end
st_wr_data : begin
case(cnt)
7'd1 : mdio_out <= 1'b1; //發(fā)送TA,寫操作(2'b10)
7'd3 : mdio_out <= 1'b0;
7'd5 : mdio_out <= wr_data_t[15];//發(fā)送寫寄存器數(shù)據(jù)
7'd7 : mdio_out <= wr_data_t[14];
7'd9 : mdio_out <= wr_data_t[13];
7'd11: mdio_out <= wr_data_t[12];
7'd13: mdio_out <= wr_data_t[11];
7'd15: mdio_out <= wr_data_t[10];
7'd17: mdio_out <= wr_data_t[9];
7'd19: mdio_out <= wr_data_t[8];
7'd21: mdio_out <= wr_data_t[7];
7'd23: mdio_out <= wr_data_t[6];
7'd25: mdio_out <= wr_data_t[5];
7'd27: mdio_out <= wr_data_t[4];
7'd29: mdio_out <= wr_data_t[3];
7'd31: mdio_out <= wr_data_t[2];
7'd33: mdio_out <= wr_data_t[1];
7'd35: mdio_out <= wr_data_t[0];
7'd37: begin
mdio_dir <= 1'b0;
mdio_out <= 1'b1;
end
7'd39: st_done <= 1'b1;
7'd40: begin
cnt <= 7'b0;
op_done <= 1'b1; //寫操作完成,拉高op_done信號
end
default : ;
endcase
end
st_rd_data : begin
case(cnt)
7'd1 : begin
mdio_dir <= 1'b0; //MDIO引腳切換至輸入狀態(tài)
mdio_out <= 1'b1;
end
7'd2 : ; //TA[1]位,該位為高阻狀態(tài),不操作
7'd4 : op_rd_ack <= mdio_in; //TA[0]位,0(應答) 1(未應答)
7'd6 : rd_data_t[15] <= mdio_in; //接收寄存器數(shù)據(jù)
7'd8 : rd_data_t[14] <= mdio_in;
7'd10: rd_data_t[13] <= mdio_in;
7'd12: rd_data_t[12] <= mdio_in;
7'd14: rd_data_t[11] <= mdio_in;
7'd16: rd_data_t[10] <= mdio_in;
7'd18: rd_data_t[9] <= mdio_in;
7'd20: rd_data_t[8] <= mdio_in;
7'd22: rd_data_t[7] <= mdio_in;
7'd24: rd_data_t[6] <= mdio_in;
7'd26: rd_data_t[5] <= mdio_in;
7'd28: rd_data_t[4] <= mdio_in;
7'd30: rd_data_t[3] <= mdio_in;
7'd32: rd_data_t[2] <= mdio_in;
7'd34: rd_data_t[1] <= mdio_in;
7'd36: rd_data_t[0] <= mdio_in;
7'd39: st_done <= 1'b1;
7'd40: begin
op_done <= 1'b1; //讀操作完成,拉高op_done信號
op_rd_data <= rd_data_t;
rd_data_t <= 16'd0;
cnt <= 7'd0;
end
default : ;
endcase
end
default : ;
endcase
end
end
endmodule
? ? ? ? ? ? ? ? ????????①控制雙向io方向
? ? ? ? ? ? ? ? ? ? ? ? ②分頻得到dri_clk時鐘
?????????????????
? ? ? ? ? ? ? ? 首先對CLK_DIV進行除2,目的是得到2倍的CLK_DIV時鐘分頻,再利用clk_cnt計數(shù)器產(chǎn)生dri_clk時鐘。clk_divide[5:1] - 1'd1? ? ?取clk_divide的第5到第1位(實際作用除2取整,記滿進行信號反轉),再減掉1位作為計數(shù)器最大值、dri_clk信號跳轉標志。(對時鐘信號進行二分頻)
? ? ? ?? ? ? ? ?????????③產(chǎn)生PHY_MDC時鐘
? ? ? ? ? ? ? ?cnt計數(shù)器最低位,實際只在0.1互相切換,?實際是對dri_clk進行二分頻。(也就是dri_clk是MDC的兩倍,此時eth_mdc是時鐘頻率四分頻)
? ? ? ? ? ? ? ? ????????④狀態(tài)機——狀態(tài)轉移
//parameter define
localparam st_idle = 6'b00_0001; //空閑狀態(tài)
localparam st_pre = 6'b00_0010; //發(fā)送PRE(前導碼)
localparam st_start = 6'b00_0100; //開始狀態(tài),發(fā)送ST(開始)+OP(操作碼)
localparam st_addr = 6'b00_1000; //寫地址,發(fā)送PHY地址+寄存器地址
localparam st_wr_data = 6'b01_0000; //TA+寫數(shù)據(jù)
localparam st_rd_data = 6'b10_0000; //TA+讀數(shù)據(jù)
//(三段式狀態(tài)機)同步時序描述狀態(tài)轉移
always @(posedge dri_clk or negedge rst_n) begin
if(!rst_n)
cur_state <= st_idle;
else
cur_state <= next_state;
end
? ? ? ? ? ? ? ? 狀態(tài)轉移,當前狀態(tài)等于下一狀態(tài)
? ? ? ? ? ? ? ? ? ? ? ? ⑤狀態(tài)機——狀態(tài)轉移條件
//組合邏輯判斷狀態(tài)轉移條件
always @(*) begin
next_state = st_idle;
case(cur_state)
st_idle : begin
if(op_exec)
next_state = st_pre;
else
next_state = st_idle;
end
st_pre : begin
if(st_done)
next_state = st_start;
else
next_state = st_pre;
end
st_start : begin
if(st_done)
next_state = st_addr;
else
next_state = st_start;
end
st_addr : begin
if(st_done) begin
if(op_code == 2'b01) //MDIO接口寫操作
next_state = st_wr_data;
else
next_state = st_rd_data; //MDIO接口讀操作
end
else
next_state = st_addr;
end
st_wr_data : begin
if(st_done)
next_state = st_idle;
else
next_state = st_wr_data;
end
st_rd_data : begin
if(st_done)
next_state = st_idle;
else
next_state = st_rd_data;
end
default : next_state = st_idle;
endcase
end
? ? ? ? 在?st_idle(空閑狀態(tài))模式下:op_exec(觸發(fā)開始信號)拉高,下一狀態(tài)進入st_pre,否則保持。
? ? ? ? 在st_pre(發(fā)送PRE(前導碼))模式下:st_done(狀態(tài)開始跳轉信號)拉高,下一狀態(tài)進入st_start,否則保持
? ? ? ? 在st_start(開始狀態(tài),發(fā)送ST(開始)+OP(操作碼))模式下:st_done(狀態(tài)開始跳轉信號)拉高,下一狀態(tài)進入st_addr,否則保持
? ? ? ? 在st_addr(寫地址,發(fā)送PHY地址+寄存器地址)模式下:如果op_code (操作碼)== 2'b01,下一狀態(tài)進入st_wr_data,否則進入st_rd_data
? ? ? ? 在st_wr_data(TA+寫數(shù)據(jù))模式下:st_done(狀態(tài)開始跳轉信號)拉高,下一狀態(tài)進入st_idle,否則保持
? ? ? ? 在st_rd_data(TA+讀數(shù)據(jù))模式下:st_done(狀態(tài)開始跳轉信號)拉高,下一狀態(tài)進入st_idle,否則保持
? ? ? ? ? ? ? ? ? ? ? ? ⑥狀態(tài)機——狀態(tài)輸出
//時序電路描述狀態(tài)輸出
always @(posedge dri_clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 5'd0;
op_code <= 1'b0;
addr_t <= 1'b0;
wr_data_t <= 1'b0;
rd_data_t <= 1'b0;
op_done <= 1'b0;
st_done <= 1'b0;
op_rd_data <= 1'b0;
op_rd_ack <= 1'b1;
mdio_dir <= 1'b0;
mdio_out <= 1'b1;
end
else begin
st_done <= 1'b0 ;
cnt <= cnt +1'b1 ;
case(cur_state)
st_idle : begin
mdio_out <= 1'b1;
mdio_dir <= 1'b0;
op_done <= 1'b0;
cnt <= 7'b0;
if(op_exec) begin
op_code <= {op_rh_wl,~op_rh_wl}; //OP_CODE: 2'b01(寫) 2'b10(讀)
addr_t <= op_addr;
wr_data_t <= op_wr_data;
op_rd_ack <= 1'b1;
end
end
st_pre : begin //發(fā)送前導碼:32個1bit
mdio_dir <= 1'b1; //切換MDIO引腳方向:輸出
mdio_out <= 1'b1; //MDIO引腳輸出高電平
if(cnt == 7'd62)
st_done <= 1'b1;
else if(cnt == 7'd63)
cnt <= 7'b0;
end
st_start : begin
case(cnt)
7'd1 : mdio_out <= 1'b0; //發(fā)送開始信號 2'b01
7'd3 : mdio_out <= 1'b1;
7'd5 : mdio_out <= op_code[1]; //發(fā)送操作碼
7'd6 : st_done <= 1'b1;
7'd7 : begin
mdio_out <= op_code[0];
cnt <= 7'b0;
end
default : ;
endcase
end
st_addr : begin
case(cnt)
7'd1 : mdio_out <= PHY_ADDR[4]; //發(fā)送PHY地址
7'd3 : mdio_out <= PHY_ADDR[3];
7'd5 : mdio_out <= PHY_ADDR[2];
7'd7 : mdio_out <= PHY_ADDR[1];
7'd9 : mdio_out <= PHY_ADDR[0];
7'd11: mdio_out <= addr_t[4]; //發(fā)送寄存器地址
7'd13: mdio_out <= addr_t[3];
7'd15: mdio_out <= addr_t[2];
7'd17: mdio_out <= addr_t[1];
7'd18: st_done <= 1'b1;
7'd19: begin
mdio_out <= addr_t[0];
cnt <= 7'd0;
end
default : ;
endcase
end
st_wr_data : begin
case(cnt)
7'd1 : mdio_out <= 1'b1; //發(fā)送TA,寫操作(2'b10)
7'd3 : mdio_out <= 1'b0;
7'd5 : mdio_out <= wr_data_t[15];//發(fā)送寫寄存器數(shù)據(jù)
7'd7 : mdio_out <= wr_data_t[14];
7'd9 : mdio_out <= wr_data_t[13];
7'd11: mdio_out <= wr_data_t[12];
7'd13: mdio_out <= wr_data_t[11];
7'd15: mdio_out <= wr_data_t[10];
7'd17: mdio_out <= wr_data_t[9];
7'd19: mdio_out <= wr_data_t[8];
7'd21: mdio_out <= wr_data_t[7];
7'd23: mdio_out <= wr_data_t[6];
7'd25: mdio_out <= wr_data_t[5];
7'd27: mdio_out <= wr_data_t[4];
7'd29: mdio_out <= wr_data_t[3];
7'd31: mdio_out <= wr_data_t[2];
7'd33: mdio_out <= wr_data_t[1];
7'd35: mdio_out <= wr_data_t[0];
7'd37: begin
mdio_dir <= 1'b0;
mdio_out <= 1'b1;
end
7'd39: st_done <= 1'b1;
7'd40: begin
cnt <= 7'b0;
op_done <= 1'b1; //寫操作完成,拉高op_done信號
end
default : ;
endcase
end
st_rd_data : begin
case(cnt)
7'd1 : begin
mdio_dir <= 1'b0; //MDIO引腳切換至輸入狀態(tài)
mdio_out <= 1'b1;
end
7'd2 : ; //TA[1]位,該位為高阻狀態(tài),不操作
7'd4 : op_rd_ack <= mdio_in; //TA[0]位,0(應答) 1(未應答)
7'd6 : rd_data_t[15] <= mdio_in; //接收寄存器數(shù)據(jù)
7'd8 : rd_data_t[14] <= mdio_in;
7'd10: rd_data_t[13] <= mdio_in;
7'd12: rd_data_t[12] <= mdio_in;
7'd14: rd_data_t[11] <= mdio_in;
7'd16: rd_data_t[10] <= mdio_in;
7'd18: rd_data_t[9] <= mdio_in;
7'd20: rd_data_t[8] <= mdio_in;
7'd22: rd_data_t[7] <= mdio_in;
7'd24: rd_data_t[6] <= mdio_in;
7'd26: rd_data_t[5] <= mdio_in;
7'd28: rd_data_t[4] <= mdio_in;
7'd30: rd_data_t[3] <= mdio_in;
7'd32: rd_data_t[2] <= mdio_in;
7'd34: rd_data_t[1] <= mdio_in;
7'd36: rd_data_t[0] <= mdio_in;
7'd39: st_done <= 1'b1;
7'd40: begin
op_done <= 1'b1; //讀操作完成,拉高op_done信號
op_rd_data <= rd_data_t;
rd_data_t <= 16'd0;
cnt <= 7'd0;
end
default : ;
endcase
end
default : ;
endcase
end
end
endmodule
? ? ? ? ? ? ? ? 復位后:cnt(計數(shù)器)、op_code(操作碼 ?2'b01(寫) ?2'b10(讀))、addr_t(緩存寄存器地址)、wr_data_t(緩存寫寄存器的數(shù)據(jù))、rd_data_t(緩存讀寄存器數(shù)據(jù))、op_done(讀寫完成)、st_done(狀態(tài)開始跳轉信號)、op_rd_data(讀出的數(shù)據(jù))、mdio_dir(MDIO數(shù)據(jù)(SDA)方向控制)清零。op_rd_ack(讀應答信號 0:應答 1:未應答)、mdio_out(MDIO輸出信號)置1。
????????mdio_out(MDIO輸出信號)置1、mdio_dir(MDIO數(shù)據(jù)(SDA)方向控制):輸入、op_done(讀寫完成)置0。
? ? ? ? 如果op_exec(觸發(fā)信號)拉高,對op_code進行為拼接賦值,op_addr、op_wr_data進行寄存,op_rd_ack(讀應答信號 0:應答 1:未應答)置1。
????????dri_clk下計數(shù)63個上升沿,對應MDC時鐘31個上升沿,即為發(fā)送32個前導碼1。記滿cnt清零
? ? ? ? 發(fā)送起始信號ST01,發(fā)送讀寫操作碼低電平寫,op_code[1],op_code[0]低電平寫,高電平讀。st_done(狀態(tài)開始跳轉信號)置為1。????????
? ? ? ? 為什么cnt計數(shù)為奇數(shù)時改變數(shù)據(jù):dri_clk為MDC的2倍,奇數(shù)剛好在MDC下降沿改變數(shù)據(jù)。
? ? ? ? 依次發(fā)送PHY地址、寄存器地址,期間st_done(狀態(tài)開始跳轉信號)置為1
? ? ? ? 發(fā)送TA寫指令后,開始發(fā)送寫入數(shù)據(jù)。之后將mdio_dir(MDIO數(shù)據(jù)(SDA)方向控制)置0釋放總線進入高阻,mdio_out(MDIO輸出信號)置1,op_done(讀寫完成)拉高標志一次讀寫造作結束。
?
???????? 發(fā)送TA讀指令后,TA[1]位無需操作保持高阻狀態(tài),由PHY側控制總線。檢測TA[0]位,如有應答,PHY側會拉低mdio_in引腳,作為應答信號。依次接受16位讀出數(shù)據(jù)寄存到rd_data_t下。之后op_done(讀寫完成)拉高標志一次讀寫造作結束,op_rd_data <= rd_data_t;進行輸出其他新信號清零。
? ? ? ? ? ? ? ? (2)mdio_ctrl模塊
module mdio_ctrl(
input clk ,
input rst_n ,
input soft_rst_trig , //軟復位觸發(fā)信號
input op_done , //讀寫完成
input [15:0] op_rd_data , //讀出的數(shù)據(jù)
input op_rd_ack , //讀應答信號 0:應答 1:未應答
output reg op_exec , //觸發(fā)開始信號
output reg op_rh_wl , //低電平寫,高電平讀
output reg [4:0] op_addr , //寄存器地址
output reg [15:0] op_wr_data , //寫入寄存器的數(shù)據(jù)
output [1:0] led //LED燈指示以太網(wǎng)連接狀態(tài)
);
//reg define
reg rst_trig_d0;
reg rst_trig_d1;
reg rst_trig_flag; //soft_rst_trig信號觸發(fā)標志
reg [23:0] timer_cnt; //定時計數(shù)器
reg timer_done; //定時完成信號
reg start_next; //開始讀下一個寄存器標致
reg read_next; //處于讀下一個寄存器的過程
reg link_error; //鏈路斷開或者自協(xié)商未完成
reg [2:0] flow_cnt; //流程控制計數(shù)器
reg [1:0] speed_status; //連接速率
//wire define
wire pos_rst_trig; //soft_rst_trig信號上升沿
//采soft_rst_trig信號上升沿
assign pos_rst_trig = ~rst_trig_d1 & rst_trig_d0;
//未連接或連接失敗時led賦值00
// 01:10Mbps 10:100Mbps 11:1000Mbps 00:其他情況
assign led = link_error ? 2'b00: speed_status;
//對soft_rst_trig信號延時打拍
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rst_trig_d0 <= 1'b0;
rst_trig_d1 <= 1'b0;
end
else begin
rst_trig_d0 <= soft_rst_trig;
rst_trig_d1 <= rst_trig_d0;
end
end
//定時計數(shù)
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
timer_cnt <= 1'b0;
timer_done <= 1'b0;
end
else begin
if(timer_cnt == 24'd1_000_000 - 1'b1) begin
timer_done <= 1'b1;
timer_cnt <= 1'b0;
end
else begin
timer_done <= 1'b0;
timer_cnt <= timer_cnt + 1'b1;
end
end
end
//根據(jù)軟復位信號對MDIO接口進行軟復位,并定時讀取以太網(wǎng)的連接狀態(tài)
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
flow_cnt <= 3'd0;
rst_trig_flag <= 1'b0;
speed_status <= 2'b00;
op_exec <= 1'b0;
op_rh_wl <= 1'b0;
op_addr <= 1'b0;
op_wr_data <= 1'b0;
start_next <= 1'b0;
read_next <= 1'b0;
link_error <= 1'b0;
end
else begin
op_exec <= 1'b0;
if(pos_rst_trig)
rst_trig_flag <= 1'b1; //拉高軟復位觸發(fā)標志
case(flow_cnt)
2'd0 : begin
if(rst_trig_flag) begin //開始對MDIO接口進行軟復位
op_exec <= 1'b1;
op_rh_wl <= 1'b0;
op_addr <= 5'h00;
op_wr_data <= 16'h9140; //Bit[15]=1'b1,表示軟復位
flow_cnt <= 3'd1;
end
else if(timer_done) begin //定時完成,獲取以太網(wǎng)連接狀態(tài)
op_exec <= 1'b1;
op_rh_wl <= 1'b1;
op_addr <= 5'h01;
flow_cnt <= 3'd2;
end
else if(start_next) begin //開始讀下一個寄存器,獲取以太網(wǎng)通信速度
op_exec <= 1'b1;
op_rh_wl <= 1'b1;
op_addr <= 5'h11;
flow_cnt <= 3'd2;
start_next <= 1'b0;
read_next <= 1'b1;
end
end
2'd1 : begin
if(op_done) begin //MDIO接口軟復位完成
flow_cnt <= 3'd0;
rst_trig_flag <= 1'b0;
end
end
2'd2 : begin
if(op_done) begin //MDIO接口讀操作完成
if(op_rd_ack == 1'b0 && read_next == 1'b0) //讀第一個寄存器,接口成功應答,
flow_cnt <= 3'd3; //讀第下一個寄存器,接口成功應答
else if(op_rd_ack == 1'b0 && read_next == 1'b1)begin
read_next <= 1'b0;
flow_cnt <= 3'd4;
end
else begin
flow_cnt <= 3'd0;
end
end
end
2'd3 : begin
flow_cnt <= 3'd0; //鏈路正常并且自協(xié)商完成
if(op_rd_data[5] == 1'b1 && op_rd_data[2] == 1'b1)begin
start_next <= 1;
link_error <= 0;
end
else begin
link_error <= 1'b1;
end
end
3'd4: begin
flow_cnt <= 3'd0;
if(op_rd_data[15:14] == 2'b10)
speed_status <= 2'b11; //1000Mbps
else if(op_rd_data[15:14] == 2'b01)
speed_status <= 2'b10; //100Mbps
else if(op_rd_data[15:14] == 2'b00)
speed_status <= 2'b01; //10Mbps
else
speed_status <= 2'b00; //其他情況
end
endcase
end
end
endmodule
? ? ? ? ? ? ? ? ? ? ? ? ①?對soft_rst_trig信號延時打兩拍
????????對soft_rst_trig?軟復位觸發(fā)信號進行打兩拍,抓取soft_rst_trig上升沿信號
? ? ? ? ? ? ? ? ? ? ? ? ?②定時計數(shù)
? ? ? ? ? ? ? ? ? ? ? ? ?③流程控制
?????????如果檢測到soft_rst_trig 上升沿,將rst_trig_flag信號拉高
? ? ? ? ?不拉高op_exec原因:觸摸按鍵按下實踐不確定,如果在讀寫期間按下,拉高op_exec沒有意義,無法達到復位效果。
? ? ? ? 0狀態(tài):
? ? ? ? 如果rst_trig_flag信號拉高,進行軟復位,op_exec(觸發(fā)開始信號)置1,op_rh_wl(低電平寫,高電平讀)置0。op_addr(寄存器地址)給出寄存器地址0x00,op_wr_data(寫入寄存器的數(shù)據(jù))對PHY芯片寄存器給出配置。flow_cnt下一狀態(tài)進入1狀態(tài)。
????????????????16'h9140? ?=? ? 2'b1001_0001_0100_0000?
回看0x00寄存器,
? ? ? ? ? ? ? ? 如果復位沒有按下,則會等待計數(shù)器記滿后,讀取當前通信速率。op_exec(觸發(fā)開始信號)置1,op_rh_wl(低電平寫,高電平讀)置1,op_addr(寄存器地址)給出寄存器地址0x01。flow_cnt下一狀態(tài)進入2狀態(tài)。
????????????????16'h9140? ?=? ? 2'b1001_0001_0100_0000?
? ? ? ? ? ? ? ? 如果計數(shù)器沒有記滿,start_next拉高時,op_exec(觸發(fā)開始信號)置1,op_rh_wl(低電平寫,高電平讀)置1,op_addr(寄存器地址)給出寄存器地址0x11。flow_cnt下一狀態(tài)進入2狀態(tài)。start_next <= 1'b0;read_next <= 1'b1;?
? ? ? ? 1狀態(tài):
? ? ? ? 等待op_done讀寫結束標志拉高,下一狀態(tài)為0狀態(tài),rst_trig_flag標志位拉低。
? ? ? ? 2狀態(tài):
? ? ? ? 如果應答信號op_rd_ack為0,read_next(寄存器讀取標志)為0,跳轉到3狀態(tài)。
? ? ? ? 如果read_next(寄存器讀取標志)為1,重置read_next為0,下一狀態(tài)為4狀態(tài)。
? ? ? ? 如果沒有應答信號op_rd_ack為1時,下一狀態(tài)進入0狀態(tài)。
? ? ? ? 3狀態(tài):
下一狀態(tài)進入0狀態(tài)。讀出0x01寄存器的第5位和第2位,進行判斷。符合條件(遠端連接成功)start_next拉高。
? ? ? ? ?4狀態(tài):
? ? ? ? 下一狀態(tài)進入0狀態(tài),讀取寄存器0x11的15、14位,的出對應的通信速率,賦值給speed_status。
? ? ? ? 利用三目運算為led進行賦值。文章來源:http://www.zghlxwxcb.cn/news/detail-842838.html
? ? ? ? ????????(3)mdio_rw_test頂層
module mdio_rw_test(
input sys_clk ,
input sys_rst_n,
//MDIO接口
output eth_mdc , //PHY管理接口的時鐘信號
inout eth_mdio , //PHY管理接口的雙向數(shù)據(jù)信號
output eth_rst_n, //以太網(wǎng)復位信號
input touch_key, //觸摸按鍵
output [1:0] led //LED連接速率指示
);
//wire define
wire op_exec ; //觸發(fā)開始信號
wire op_rh_wl ; //低電平寫,高電平讀
wire [4:0] op_addr ; //寄存器地址
wire [15:0] op_wr_data ; //寫入寄存器的數(shù)據(jù)
wire op_done ; //讀寫完成
wire [15:0] op_rd_data ; //讀出的數(shù)據(jù)
wire op_rd_ack ; //讀應答信號 0:應答 1:未應答
wire dri_clk ; //驅動時鐘
//硬件復位
assign eth_rst_n = sys_rst_n;
//MDIO接口驅動
mdio_dri #(
.PHY_ADDR (5'h04), //PHY地址
.CLK_DIV (6'd10) //分頻系數(shù)
)
u_mdio_dri(
.clk (sys_clk),
.rst_n (sys_rst_n),
.op_exec (op_exec ),
.op_rh_wl (op_rh_wl ),
.op_addr (op_addr ),
.op_wr_data (op_wr_data),
.op_done (op_done ),
.op_rd_data (op_rd_data),
.op_rd_ack (op_rd_ack ),
.dri_clk (dri_clk ),
.eth_mdc (eth_mdc ),
.eth_mdio (eth_mdio )
);
//MDIO接口讀寫控制
mdio_ctrl u_mdio_ctrl(
.clk (dri_clk),
.rst_n (sys_rst_n ),
.soft_rst_trig (touch_key ),
.op_done (op_done ),
.op_rd_data (op_rd_data),
.op_rd_ack (op_rd_ack ),
.op_exec (op_exec ),
.op_rh_wl (op_rh_wl ),
.op_addr (op_addr ),
.op_wr_data (op_wr_data),
.led (led )
);
endmodule
六、下載驗證
文章來源地址http://www.zghlxwxcb.cn/news/detail-842838.html
到了這里,關于FPGA千兆網(wǎng)口數(shù)據(jù)傳輸MDIO接口——FPGA學習筆記3的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!