FPGA以太網(wǎng)入門(mén)(一)——MDIO接口讀寫(xiě)測(cè)試實(shí)驗(yàn)(基于紫光同創(chuàng))
0 致讀者
此篇為專(zhuān)欄《紫光同創(chuàng)FPGA開(kāi)發(fā)筆記》的第五篇,記錄我的學(xué)習(xí) FPGA 的一些開(kāi)發(fā)過(guò)程和心得感悟,剛接觸 FPGA 的朋友們可以先去此博客 《FPGA零基礎(chǔ)入門(mén)學(xué)習(xí)路線》來(lái)做最基礎(chǔ)的掃盲。
本篇內(nèi)容基于筆者實(shí)際開(kāi)發(fā)過(guò)程和正點(diǎn)原子資料撰寫(xiě),將會(huì)詳細(xì)講解此 FPGA 實(shí)驗(yàn)的全流程,誠(chéng)摯地歡迎各位讀者在評(píng)論區(qū)或者私信我交流!
在以太網(wǎng)通信中,設(shè)備之間的物理層鏈路均由 PHY 芯片(物理層芯片,本文以 YT8511 為例)建立。PHY 芯片有一個(gè)配置接口,即 MDIO 接口,可以配置 PHY 芯片的工作模式以及獲取 PHY 芯片的若干狀態(tài)信息。本篇博客我們來(lái)學(xué)習(xí)如何使用紫光同創(chuàng) FPGA 實(shí)現(xiàn)對(duì) PHY 芯片的 MDIO 接口進(jìn)行讀寫(xiě)測(cè)試。
本文的工程文件開(kāi)源地址如下(基于ATK-DFPGL22G,大家 clone 到本地就可以直接跑仿真,如果要上板請(qǐng)根據(jù)自己的開(kāi)發(fā)板更改約束即可):
https://github.com/ChinaRyan666/PDS_MDIO_RW
1 實(shí)驗(yàn)任務(wù)
本文的實(shí)驗(yàn)任務(wù)是使用紫光同創(chuàng) FPGA 開(kāi)發(fā)板上的以太網(wǎng)接口,完成 MDIO 接口的讀寫(xiě)測(cè)試實(shí)驗(yàn)。板載的觸摸按鍵(TPAD)控制 MDIO 接口進(jìn)行軟復(fù)位,并通過(guò)兩個(gè) LED 燈實(shí)時(shí)指示當(dāng)前網(wǎng)口的連接速度。
2 簡(jiǎn)介
2.1 以太網(wǎng)概述
以太網(wǎng)(Ethernet) 是當(dāng)今現(xiàn)有局域網(wǎng)采用的最通用的通信協(xié)議標(biāo)準(zhǔn), 該標(biāo)準(zhǔn)定義了在局域網(wǎng)中采用的電纜類(lèi)型和信號(hào)處理方法。以太網(wǎng)憑借其成本低、通信速率高、抗干擾性強(qiáng)等優(yōu)點(diǎn)被廣泛應(yīng)用在網(wǎng)絡(luò)遠(yuǎn)程監(jiān)控、 交換機(jī)、工業(yè)自動(dòng)化等對(duì)通信速率要求較高的場(chǎng)合。
以太網(wǎng)是一種產(chǎn)生較早,使用相當(dāng)廣泛的局域網(wǎng)。其最初是由 Xerox(施樂(lè))公司創(chuàng)建并由 Xerox、Intel 和 DEC 公司聯(lián)合開(kāi)發(fā)的基帶局域網(wǎng)規(guī)范,后來(lái)被電氣與電子工程師協(xié)會(huì)(IEEE)所采納作為 802.3 的標(biāo)準(zhǔn)。
以太網(wǎng)的分類(lèi)有標(biāo)準(zhǔn)以太網(wǎng)(10Mbit/s)、快速以太網(wǎng)(100Mbit/s)和千兆以太網(wǎng)(1000Mbit/s)。隨著以太網(wǎng)技術(shù)的飛速發(fā)展, 市場(chǎng)上也出現(xiàn)了萬(wàn)兆以太網(wǎng)(10Gbit/s),它擴(kuò)展了 IEEE 802.3 協(xié)議和 MAC 規(guī)范,使其技術(shù)支持 10Gbit/s 的傳輸速率。 在實(shí)際應(yīng)用中,千兆以太網(wǎng)理論上最高通信速率為 1000Mbit/s,可以勝任大部分的使用場(chǎng)景。
以太網(wǎng)通信離不開(kāi)連接端口的支持,網(wǎng)絡(luò)數(shù)據(jù)連接的端口就是以太網(wǎng)接口。以太網(wǎng)接口類(lèi)型有 RJ45 接口、RJ11 接口(電話線接口)、SC 光纖接口等。其中 RJ45 接口是我們現(xiàn)在最常見(jiàn)的網(wǎng)絡(luò)設(shè)備接口(如:電腦網(wǎng)口),我們開(kāi)發(fā)板使用的就是這種接口。
RJ45 接口俗稱(chēng) “水晶頭”,專(zhuān)業(yè)術(shù)語(yǔ)為 RJ45 連接器,由插頭(接頭、水晶頭) 和插座(母座) 組成,屬于雙絞線以太網(wǎng)接口類(lèi)型。RJ45 插頭只能沿固定方向插入,設(shè)有一個(gè)塑料彈片與 RJ45 插槽卡住以防止脫落。
RJ45 接口樣式如下圖所示:
RJ45 接口定義以及各引腳功能在不同通信速率下的定義有區(qū)別,下圖是在 10M/100M 通信速率下的定義,由下圖可知,RJ45 插座只使用了 1、2、3、6 這四根線,其中 1、2 這組負(fù)責(zé)傳輸數(shù)據(jù)(TX+、TX-),而 3、6 這組負(fù)責(zé)接收數(shù)據(jù)(RX+、RX-),另外四根線是備用的。
而在 1000M 的通信速率下,RJ45 插座的 8 根線都有用到,且都是雙向引腳。需要說(shuō)明的是,支持千兆網(wǎng)通信的 RJ45 接口是向下兼容的,即也支持 10M/100M 通信速率,只不過(guò)不同的通信速率,其引腳功能有區(qū)別。千兆網(wǎng)各引腳功能如下圖所示:
從硬件的角度來(lái)說(shuō),以太網(wǎng)接口電路主要由 MAC(Media Access Control)控制器和物理層接口 PHY(Physical Layer)兩大部分構(gòu)成。MAC 指媒體訪問(wèn)控制子層協(xié)議,它和 PHY 接口既可以整合到單顆芯片內(nèi),也可以獨(dú)立分開(kāi),對(duì)于本次設(shè)計(jì)來(lái)說(shuō),MAC 控制器由 FPGA 實(shí)現(xiàn),PHY 芯片指開(kāi)發(fā)板板載的以太網(wǎng)芯片。
PHY 在發(fā)送數(shù)據(jù)的時(shí)候,接收 MAC 發(fā)過(guò)來(lái)的數(shù)據(jù)(對(duì) PHY 來(lái)說(shuō),沒(méi)有幀的概念,都是數(shù)據(jù)而不管什么地址,數(shù)據(jù)還是 CRC),把并行數(shù)據(jù)轉(zhuǎn)化為串行流數(shù)據(jù),按照物理層的編碼規(guī)則把數(shù)據(jù)編碼轉(zhuǎn)換為模擬信號(hào)發(fā)送出去,接收數(shù)據(jù)時(shí)的流程反之。
PHY 還提供了和對(duì)端設(shè)備連接的重要功能,并通過(guò) LED 燈顯示出自己目前的連接狀態(tài)和工作狀態(tài)。當(dāng)我們給網(wǎng)卡接入網(wǎng)線的時(shí)候, PHY 芯片不斷發(fā)出脈沖信號(hào)來(lái)檢測(cè)對(duì)端是否有設(shè)備,它們通過(guò)標(biāo)準(zhǔn)的 “語(yǔ)言” 交流,互相協(xié)商并確定連接速度、雙工模式、是否采用流控等。通常情況下,協(xié)商的結(jié)果是兩個(gè)設(shè)備中能同時(shí)支持的最大速度和最好的雙工模式。這個(gè)技術(shù)被稱(chēng)為 Auto Negotiation,即自協(xié)商。
2.2 MDIO 接口
MAC 和 PHY 芯片有一個(gè)配置接口,即 MDIO 接口,可以配置 PHY 芯片的工作模式以及獲取 PHY 芯片的若干狀態(tài)信息。 PHY 芯片內(nèi)部包含一系列寄存器,用戶通過(guò)這些寄存器來(lái)配置 PHY 芯片的工作模式以及獲取 PHY 芯片的若干狀態(tài)信息,如連接速率、雙工模式、自協(xié)商狀態(tài)等。
FPGA 通過(guò) MDIO 接口對(duì) PHY 芯片內(nèi)部的寄存器進(jìn)行配置。通常情況下,PHY 芯片在默認(rèn)狀態(tài)下也可以正常工作,在做以太網(wǎng)通信實(shí)驗(yàn)時(shí),對(duì) MDIO 接口的配置不是必須的,本章旨在向大家介紹 MDIO 接口以及如何對(duì) MDIO 接口進(jìn)行讀寫(xiě)操作。MAC 和 PHY 連接示意圖如下圖所示。
MDIO 接口也稱(chēng)為 SMI 接口(Serial Management Interface,串行管理接口),包括 ETH_MDC(數(shù)據(jù)管理時(shí)鐘)和 ETH_MDIO(數(shù)據(jù)管理輸入輸出)兩條信號(hào)線。ETH_MDC 為 ETH_MDIO 提供時(shí)鐘,ETH_MDC 的最大時(shí)鐘不能超過(guò) 12.5Mhz。ETH_MDIO 為雙向數(shù)據(jù)引腳,既用于發(fā)送數(shù)據(jù),也用于接收數(shù)據(jù)。
MDIO 接口的讀寫(xiě)通信協(xié)議如下圖所示:
名稱(chēng) | 功能 |
---|---|
Preamble | 32 位前導(dǎo)碼,由 MAC 端發(fā)送 32 位邏輯 “1”,用于同步 PHY 芯片。 |
ST(Start of Frame) | 2 位幀開(kāi)始信號(hào),用 01 表示。 |
OP(Operation Code) | 2 位操作碼,讀:10 寫(xiě):01。 |
PHYAD(PHY Address) | 5 位 PHY 地址,用于表示與哪個(gè) PHY 芯片通信,因此一個(gè) MAC 上可以連接多個(gè) PHY 芯片。 |
REGAD(Register Address) | 5 位寄存器地址,可以表示共 32 位寄存器。 |
TA(Turnaround) | 2 位轉(zhuǎn)向,在讀命令中,MDIO 在此時(shí)由 MAC 驅(qū)動(dòng)改為 PHY 驅(qū)動(dòng),在第一個(gè) TA位,MDIO 引腳為高阻狀態(tài),第二個(gè) TA 位,PHY 將 MDIO 引腳拉低,準(zhǔn)備發(fā)送數(shù)據(jù);在寫(xiě)命令中,不需要 MDIO 方向發(fā)生變化,MAC 固定輸出 2’b10,隨后開(kāi)始寫(xiě)入數(shù)據(jù)。 |
DATA | 16 位數(shù)據(jù),在讀命令中, PHY 芯片將讀到的對(duì)應(yīng) PHYAD 的 REGAD 寄存器的數(shù)據(jù)寫(xiě)到 DATA 中;在寫(xiě)命令中, PHY 芯片將接收到的 DATA 寫(xiě)入 REGAD 寄存器中。需要注意的是,在 DATA 傳輸?shù)倪^(guò)程中,高位在前,低位在后。 |
IDLE | 空閑狀態(tài),此時(shí) MDIO 為無(wú)源驅(qū)動(dòng),處于高阻狀態(tài),但一般用上拉電阻使其上拉至高電平。 |
MDIO 接口讀時(shí)序圖如下圖所示:
上圖是以 PHY 地址為 0x01,從寄存器地址 0x00 讀出數(shù)據(jù)為例。整個(gè)讀操作過(guò)程的 MDC 時(shí)鐘由 MAC 驅(qū)動(dòng),同時(shí) MAC 驅(qū)動(dòng) MDIO 引腳輸出前導(dǎo)碼+幀開(kāi)始+操作碼+PHY 地址+寄存器地址,隨后 MDIO 引腳切換至 PHY 驅(qū)動(dòng)。
在第一個(gè) TA 位,MDIO 引腳為高阻狀態(tài),第二個(gè) TA 位為低電平,表示 PHY 芯片成功響應(yīng),并且接下來(lái)會(huì)輸出 16 位寄存器數(shù)據(jù);而如果第二個(gè) TA 位處于高電平,則 PHY 芯片響應(yīng)失敗,有可能 PHY 地址不正確或者其它時(shí)序的錯(cuò)誤。
需要注意的是,PHY 在 MDC 時(shí)鐘的上升沿采集數(shù)據(jù),為保證數(shù)據(jù)的穩(wěn)定傳輸,MAC 在 MDC 的下降沿更新 MDIO 引腳的數(shù)據(jù)。當(dāng) MDIO 引腳切換至 PHY 驅(qū)動(dòng)時(shí),MDIO 數(shù)據(jù)在 MDC 時(shí)鐘的下降沿更新,因此 MAC 在 MDC 時(shí)鐘的上升沿采集數(shù)據(jù)。
在讀操作結(jié)束后,MAC 將 MDIO 引腳輸出高阻,此時(shí) MDIO 引腳的外部上拉電阻會(huì)將 MDIO 引腳拉高,此時(shí) MDIO 接口處于空閑狀態(tài)。
MDIO 接口寫(xiě)時(shí)序圖 如下圖所示:
上圖是以 PHY 地址為 0x01,向寄存器地址 0x00 寫(xiě)入 0x1340 為例,在整個(gè)寫(xiě)操作過(guò)程中,MDC 時(shí)鐘和 MDIO 引腳一直由 MAC 端驅(qū)動(dòng),按照 MDIO 接口寫(xiě)通信協(xié)議開(kāi)始傳輸數(shù)據(jù)。
需要注意的是,PHY 在 MDC 時(shí)鐘的上升沿采集數(shù)據(jù),為保證數(shù)據(jù)的穩(wěn)定傳輸,MAC 在 MDC 的下降沿將數(shù)據(jù)更新至 MDIO 引腳。在寫(xiě)操作結(jié)束后,MAC 將 MDIO 引腳輸出高阻,此時(shí) MDIO 引腳的外部上拉電阻會(huì)將 MDIO 引腳拉高,此時(shí) MDIO 接口處于空閑狀態(tài)。
2.3 以太網(wǎng) PHY 芯片(以YT8511為例)
-
PHY 地址
YT8511 芯片的 PHY 地址由 LED_ACT 和 RXD[1:0] 引腳決定,如下圖所示:PHY 地址一共有五位,其中高兩位固定為 00,LED_ACT 和 RXD[1:0] 引腳表示低三位,我們可以通過(guò)硬件電路設(shè)置 LED_ACT 和 RXD[1:0] 引腳引腳為上拉或者下來(lái),即分配為高低電平,0 或 1,從而表示不同的地址。
-
復(fù)位
YT8511 芯片復(fù)位后,PHY 內(nèi)部寄存器的數(shù)據(jù)會(huì)恢復(fù)默認(rèn)的狀態(tài),并且重新開(kāi)始和 MAC 進(jìn)行自協(xié)商。 YT8511 支持兩種復(fù)位方式,一種是硬件復(fù)位,另外一種是軟件復(fù)位。硬件復(fù)位時(shí)通過(guò) ETH_RST_N 引腳實(shí)現(xiàn)對(duì) PHY 芯片的復(fù)位,當(dāng) ETH_RST_N 引腳持續(xù) 10ms 的低電平時(shí),即可實(shí)現(xiàn)對(duì) PHY 芯片的復(fù)位。軟件復(fù)位通過(guò)向寄存器地址 0x00 的 Bit[15] 寫(xiě)入 1 進(jìn)行復(fù)位,并且在完成復(fù)位后,該位會(huì)自動(dòng)清零。 -
寄存器
YT8511 共有 22 位寄存器,本實(shí)驗(yàn)用到的三個(gè)寄存器,控制寄存器、狀態(tài)寄存器以及 PHY 芯片具體狀態(tài)寄存器。關(guān)于寄存器的具體信息大家可以查閱自己開(kāi)發(fā)板上以太網(wǎng) PHY 芯片對(duì)應(yīng)的芯片手冊(cè)。
3 程序設(shè)計(jì)
根據(jù)實(shí)驗(yàn)任務(wù),我們可以大致規(guī)劃出系統(tǒng)的控制流程:首先每隔一段時(shí)間通過(guò) MDIO 接口從 PHY 內(nèi)部寄存器中讀取基本狀態(tài)寄存器(BMSR)和特定狀態(tài)寄存器(PHYSR)的值,從而獲取到自協(xié)商完成狀態(tài)、連接狀態(tài)和連接速度,將網(wǎng)口的連接速度通過(guò) LED 燈進(jìn)行指示;當(dāng) FPGA 檢測(cè)到 TPAD 觸摸按鍵按下時(shí),開(kāi)始通過(guò) MDIO 接口對(duì) PHY 進(jìn)行軟復(fù)位,在軟復(fù)位完成后,PHY 會(huì)重新開(kāi)始自協(xié)商,此時(shí) LED 燈仍然會(huì)每隔一段時(shí)間獲取當(dāng)前網(wǎng)口的連接狀態(tài)以及連接速度。由此畫(huà)出系統(tǒng)的功能框圖如下圖所示:
MDIO 接口驅(qū)動(dòng)模塊實(shí)現(xiàn)了對(duì) MDIO 接口的讀寫(xiě)驅(qū)動(dòng)。MDIO 接口控制模塊根據(jù)輸入的觸摸按鍵,實(shí)現(xiàn)了對(duì) MDIO 接口驅(qū)動(dòng)模塊的寫(xiě)操作,并每隔一段時(shí)間對(duì) MDIO 接口驅(qū)動(dòng)模塊進(jìn)行讀操作,將獲取到的網(wǎng)口連接狀態(tài)與速度通過(guò) LED 燈進(jìn)行指示。FPGA 頂層模塊例化了以下兩個(gè)模塊,MDIO 接口控制模塊(mdio_ctrl)和 MDIO 接口驅(qū)動(dòng)模塊(mdio_dri),實(shí)現(xiàn)了各模塊之間的數(shù)據(jù)交互。其中 MDIO 接口驅(qū)動(dòng)模塊預(yù)留了用戶接口,方便對(duì) MDIO 接口進(jìn)行讀寫(xiě)操作。
當(dāng) FPGA 通過(guò) MDIO 控制模塊向 MDIO 驅(qū)動(dòng)模式讀寫(xiě)數(shù)據(jù)時(shí),拉高觸發(fā)控制信號(hào) op_exec 來(lái)觸發(fā) MDIO 驅(qū)動(dòng)模塊, op_rh_wl 用于表示讀或者寫(xiě)操作,當(dāng) op_rh_wl 為低電平時(shí),MDIO 驅(qū)動(dòng)模塊執(zhí)行寫(xiě)操作,當(dāng) op_rh_wl 為高電平時(shí), MDIO 驅(qū)動(dòng)模塊執(zhí)行讀操作。op_addr 表示讀寫(xiě)寄存器地址,op_wr_data 信號(hào)表示寫(xiě)入的數(shù)據(jù),op_rd_data 信號(hào)表示從 MDIO 接口的寄存器中讀到的數(shù)據(jù)。當(dāng)讀或者寫(xiě)操作完成時(shí),MDIO 驅(qū)動(dòng)模塊會(huì)產(chǎn)生一個(gè)時(shí)鐘周期的 op_done 信號(hào),表示 MDIO 驅(qū)動(dòng)模塊讀或者寫(xiě)操作完成。
頂層模塊的代碼如下:
module mdio_rw_test(
input sys_clk ,
input sys_rst_n,
//MDIO接口
output eth_mdc , //PHY管理接口的時(shí)鐘信號(hào)
inout eth_mdio , //PHY管理接口的雙向數(shù)據(jù)信號(hào)
output eth_rst_n, //以太網(wǎng)復(fù)位信號(hào)
input touch_key, //觸摸按鍵
output [1:0] led //LED連接速率指示
);
//wire define
wire op_exec ; //觸發(fā)開(kāi)始信號(hào)
wire op_rh_wl ; //低電平寫(xiě),高電平讀
wire [4:0] op_addr ; //寄存器地址
wire [15:0] op_wr_data ; //寫(xiě)入寄存器的數(shù)據(jù)
wire op_done ; //讀寫(xiě)完成
wire [15:0] op_rd_data ; //讀出的數(shù)據(jù)
wire op_rd_ack ; //讀應(yīng)答信號(hào) 0:應(yīng)答 1:未應(yīng)答
wire dri_clk ; //驅(qū)動(dòng)時(shí)鐘
//硬件復(fù)位
assign eth_rst_n = sys_rst_n;
//MDIO接口驅(qū)動(dòng)
mdio_dri #(
.PHY_ADDR (5'h04), //PHY地址 3'b100
.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接口讀寫(xiě)控制
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
頂層模塊主要完成對(duì)其余模塊的例化。在程序的第 24 行將系統(tǒng)復(fù)位(sys_rst_n)直接賦值給以太網(wǎng)的硬件復(fù)位信號(hào)(eth_rst_n),當(dāng)復(fù)位按鍵按下時(shí),會(huì)對(duì) PHY 芯片進(jìn)行硬件復(fù)位。
在程序的第 28 行和 29 行代碼例化了兩個(gè)參數(shù),分別表示 PHY 地址和 ETH_MDC 相對(duì)于輸入時(shí)鐘的分頻系數(shù)。 這里將 PHY 地址設(shè)置為 5’h04, 如果 PHY 地址設(shè)置錯(cuò)誤, 會(huì)導(dǎo)致對(duì) MDIO 接口的讀寫(xiě)操作失敗。另外需要注意的是,ETH_MDC 的時(shí)鐘頻率不能超過(guò) 12.5Mhz。
由前面的 MDIO 接口讀寫(xiě)時(shí)序圖我們可以發(fā)現(xiàn),MDIO 驅(qū)動(dòng)模塊非常適合采用狀態(tài)機(jī)來(lái)編寫(xiě)。狀態(tài)機(jī)的狀態(tài)跳轉(zhuǎn)圖如下圖所示,總共有 6 個(gè)狀態(tài),分別為 st_idle(空閑狀態(tài))、st_pre(發(fā)送前導(dǎo)碼狀態(tài))、st_start(發(fā)送幀開(kāi)始 + 操作碼)、st_addr(發(fā)送 PHY 地址 + 寄存器地址)、st_wr_data(發(fā)送 TA + 寫(xiě)入數(shù)據(jù))和 st_rd_data(接收 TA + 接收數(shù)據(jù))。當(dāng)狀態(tài)機(jī)處于空閑狀態(tài)時(shí),如果觸發(fā)信號(hào)拉高(op_exec = 1),狀態(tài)機(jī)進(jìn)入發(fā)送前導(dǎo)碼狀態(tài)。另外當(dāng)狀態(tài)機(jī)處于 st_addr 時(shí),在發(fā)送完 PHY 地址和寄存器地址之后,接下來(lái)狀態(tài)機(jī)根據(jù)讀或者寫(xiě)操作來(lái)跳轉(zhuǎn)至 st_wr_data 狀態(tài)或者 st_rd_data 狀態(tài)。在讀或者寫(xiě)完數(shù)據(jù)后,狀態(tài)機(jī)重新跳轉(zhuǎn)至空閑狀態(tài)。
程序中我們采用的是三段式狀態(tài)機(jī),由于代碼較長(zhǎng),這里僅貼出部分代碼(完整代碼見(jiàn)文章開(kāi)頭的開(kāi)源地址),代碼如下:
省略部分代碼……
(以下所指的程序行數(shù)來(lái)源于源工程中的代碼,各位讀者可打開(kāi)文章開(kāi)頭我提供的開(kāi)源地址來(lái)進(jìn)行源碼的查看)
在程序的第 69 行,通過(guò) mdio_dir(MDIO 引腳方向選擇)信號(hào)控制 eth_mdio 引腳的方向,當(dāng)設(shè)置成輸入時(shí),FPGA 將該引腳輸出高阻(1’bz);當(dāng)設(shè)置成輸出時(shí),將 FPGA 驅(qū)動(dòng)的 mdio_out 信號(hào)連接至 eth_mdio。
由于 eth_mdc 需要在輸入時(shí)鐘的基礎(chǔ)上進(jìn)行分頻,為了方便操作,這里先對(duì)輸入的時(shí)鐘進(jìn)行分頻,得到一個(gè) dri_clk 時(shí)鐘,作為 MDIO 驅(qū)動(dòng)模塊和 MDIO 控制模塊的操作時(shí)鐘。eth_mdc 在 dri_clk 的基礎(chǔ)上進(jìn)行 2 分頻,由于輸入的參數(shù) CLK_DIV 為 eth_mdc 相對(duì)于輸入時(shí)鐘的分頻系數(shù),因此為了得到 dri_clk 的分頻系數(shù),需要將 CLK_DIV 除以 2,如代碼中第 72 行所示。
程序中第 74 行至第 86 行根據(jù)分頻系數(shù)(clk_divide),得到 dri_clk 的時(shí)鐘。在程序的第 88 行至第 96 行代碼,當(dāng) cnt 一直累加時(shí),eth_mdc 的時(shí)鐘相當(dāng)于對(duì) dri_clk 進(jìn)行 2 分頻。當(dāng)開(kāi)始對(duì) MDIO 接口進(jìn)行讀寫(xiě)操作時(shí),cnt 累加,此時(shí)才會(huì)產(chǎn)生 eth_mdc 時(shí)鐘;當(dāng)讀寫(xiě)操作結(jié)束后,cnt 等于 0,eth_mdc 將一直處于高電平。
需要說(shuō)明的是,由于 clk_divide 等于 CLK_DIV 除以 2,程序中第 74 行至第 86 行代碼只支持偶數(shù)分頻,所以最終生成的 eth_mdc 的時(shí)鐘頻率相比于輸入的 CLK_DIV 可能產(chǎn)生偏差。本次實(shí)驗(yàn)中,CLK_DIV 等于 10,因此 clk_divide 等于 5,dri_clk 的時(shí)鐘頻率為 12.5Mhz,eth_mdc 為 6.25Mhz。
程序的第 255 行至 289 行代碼為狀態(tài)機(jī)的 st_wr_data(發(fā)送 TA+寫(xiě)入數(shù)據(jù))和 st_rd_data(接收 TA+接收數(shù)據(jù))狀態(tài)。在 st_wr_data 狀態(tài)下,數(shù)據(jù)是在 eth_mdc 的下降沿寫(xiě)入,而在 st_rd_data 狀態(tài),數(shù)據(jù)在 erth_mdc 的上升沿讀出。值得一提是,在 st_rd_data 狀態(tài)下,程序中根據(jù) TA 的第二位,判斷 PHY 芯片有沒(méi)有應(yīng)答,如果沒(méi)有應(yīng)答,則說(shuō)明讀取數(shù)據(jù)失敗,如程序中第 264 行代碼所示。
MDIO 接口讀寫(xiě)操作驅(qū)動(dòng)模塊的仿真代碼:
module tb_mdio_dri;
//parameter define
parameter T = 20; //時(shí)鐘周期為20ns
parameter OP_CYCLE = 100; //讀寫(xiě)操作周期
parameter PHY_ADDR = 5'h04; //設(shè)置PHY地址
//reg define
reg sys_clk; //時(shí)鐘信號(hào)
reg sys_rst_n; //復(fù)位信號(hào)
reg op_exec ;
reg op_rh_wl ;
reg [4:0] op_addr ;
reg [15:0] op_wr_data;
reg [3:0] flow_cnt ;
reg [13:0] delay_cnt ;
//wire define
wire [15:0] op_rd_data;
wire op_done ;
wire op_rd_ack ;
wire eth_mdc ;
wire eth_mdio ;
wire dri_clk ;
//*****************************************************
//** main code
//*****************************************************
//給輸入信號(hào)初始值
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b0; //復(fù)位
#(T+1) sys_rst_n = 1'b1; //在第21ns的時(shí)候復(fù)位信號(hào)信號(hào)拉高
end
//50Mhz的時(shí)鐘,周期則為1/50Mhz=20ns,所以每10ns,電平取反一次
always #(T/2) sys_clk = ~sys_clk;
always @(posedge dri_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
op_exec <= 1'b0;
op_rh_wl <= 1'b0;
op_addr <= 1'b0;
op_wr_data <= 1'b0;
flow_cnt <= 1'b0;
delay_cnt <= 1'b0;
end
else begin
case(flow_cnt)
'd0 : flow_cnt <= flow_cnt + 1'b1;
'd1 : begin
op_exec <= 1'b1; //拉高觸發(fā)信號(hào)
op_rh_wl <= 1'b0; //寫(xiě)操作
op_addr <= 5'h05; //寫(xiě)地址
op_wr_data <= 16'h55aa; //寫(xiě)數(shù)據(jù)
flow_cnt <= flow_cnt + 1'b1;
end
'd2 : begin
op_exec <= 1'b0;
flow_cnt <= flow_cnt + 1'b1;
end
'd3 : begin
if(op_done)
flow_cnt <= flow_cnt + 1'b1;
end
'd4 : begin
delay_cnt <= delay_cnt + 1'b1;
if(delay_cnt == OP_CYCLE - 1'b1)
flow_cnt <= flow_cnt + 1'b1;
end
'd5 : begin
op_exec <= 1'b1;
op_rh_wl <= 1'b1; //讀操作
op_addr <= 5'h05;
op_wr_data <= 16'h55aa;
flow_cnt <= flow_cnt + 1'b1;
end
'd6 : begin
op_exec <= 1'b0;
flow_cnt <= flow_cnt + 1'b1;
end
'd7 : begin
if(op_done)
flow_cnt <= flow_cnt + 1'b1;
end
default:;
endcase
end
end
pullup(eth_mdio); //MDIO信號(hào)上拉
//為PHY寄存器賦初始值
reg we_i;
reg strobe_i;
reg [7:0] address_i;
reg [7:0] data_i;
initial begin
we_i = 1'b0;
strobe_i = 1'b0;
address_i = 8'd0;
data_i = 8'd0;
#(10*T)
we_i = 1'b1; //像地址5'h05寫(xiě)入16'h55aa
strobe_i = 1'b1;
address_i = 8'h0a;
data_i = 8'h55;
#T
address_i = 8'h0b;
data_i = 8'haa;
#T
address_i = 8'h40; //設(shè)置PHY芯片的PHY地址
data_i = PHY_ADDR;
#T
we_i = 1'b0;
strobe_i = 1'b0;
address_i = 8'd0;
data_i = 8'd0;
end
//例化MDIO接口驅(qū)動(dòng)
mdio_dri #(
.PHY_ADDR (PHY_ADDR), //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接口從機(jī)仿真模型
mdio_slave_interface u_mdio_slave_interface(
.rst_n_i (sys_rst_n),
.mdc_i (eth_mdc),
.mdio (eth_mdio),
//wishbone interface
.clk_i (sys_clk),
.rst_i (~sys_rst_n),
.address_i (address_i),
.data_i (data_i),
.data_o (),
.strobe_i (strobe_i),
.we_i (we_i),
.ack_o ()
);
endmodule
我仿真的是 MDIO 接口的驅(qū)動(dòng)模塊,所以需要一個(gè) MDIO 從接口 mdio_slave_interface.v 文件(該模型是從網(wǎng)上獲取的),將該模塊例化在仿真代碼的 145~160 行。
MDIO 接口讀 PHYSR 寄存器的仿真波形圖如下圖所示:
由上圖可知,op_exec 的脈沖信號(hào)作為 MDIO 接口讀寫(xiě)的觸發(fā)信號(hào),圖中 op_rh_wl 為高電平,表示讀操作,op_addr 寄存器地址為 5’h05。 在 TA 位時(shí),mdio_dir 由高電平切換至低電平,表示 MDIO 引腳由輸出切換至輸入,隨后 op_rd_ack 變?yōu)榈碗娖?,說(shuō)明 PHY 芯片應(yīng)答成功。在整個(gè)讀操作結(jié)束后,MDIO 驅(qū)動(dòng)模塊產(chǎn)生一個(gè)脈沖的 op_done 信號(hào),此時(shí)從狀態(tài)寄存器中讀出的數(shù)據(jù)為 16’h55aa。
MDIO 控制模塊代碼如下:
module mdio_ctrl(
input clk ,
input rst_n ,
input soft_rst_trig , //軟復(fù)位觸發(fā)信號(hào)
input op_done , //讀寫(xiě)完成
input [15:0] op_rd_data , //讀出的數(shù)據(jù)
input op_rd_ack , //讀應(yīng)答信號(hào) 0:應(yīng)答 1:未應(yīng)答
output reg op_exec , //觸發(fā)開(kāi)始信號(hào)
output reg op_rh_wl , //低電平寫(xiě),高電平讀
output reg [4:0] op_addr , //寄存器地址
output reg [15:0] op_wr_data , //寫(xiě)入寄存器的數(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信號(hào)觸發(fā)標(biāo)志
reg [23:0] timer_cnt; //定時(shí)計(jì)數(shù)器
reg timer_done; //定時(shí)完成信號(hào)
reg start_next; //開(kāi)始讀下一個(gè)寄存器標(biāo)致
reg read_next; //處于讀下一個(gè)寄存器的過(guò)程
reg link_error; //鏈路斷開(kāi)或者自協(xié)商未完成
reg [2:0] flow_cnt; //流程控制計(jì)數(shù)器
reg [1:0] speed_status; //連接速率
//wire define
wire pos_rst_trig; //soft_rst_trig信號(hào)上升沿
//采soft_rst_trig信號(hào)上升沿
assign pos_rst_trig = ~rst_trig_d1 & rst_trig_d0;
//未連接或連接失敗時(shí)led賦值00
// 01:10Mbps 10:100Mbps 11:1000Mbps 00:其他情況
assign led = link_error ? 2'b00: speed_status;
//對(duì)soft_rst_trig信號(hào)延時(shí)打拍
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í)計(jì)數(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ù)軟復(fù)位信號(hào)對(duì)MDIO接口進(jìn)行軟復(fù)位,并定時(shí)讀取以太網(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ù)位觸發(fā)標(biāo)志
case(flow_cnt)
2'd0 : begin
if(rst_trig_flag) begin //開(kāi)始對(duì)MDIO接口進(jìn)行軟復(fù)位
op_exec <= 1'b1;
op_rh_wl <= 1'b0;
op_addr <= 5'h00;
op_wr_data <= 16'h9140; //Bit[15]=1'b1,表示軟復(fù)位
flow_cnt <= 3'd1;
end
else if(timer_done) begin //定時(shí)完成,獲取以太網(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 //開(kāi)始讀下一個(gè)寄存器,獲取以太網(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接口軟復(fù)位完成
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) //讀第一個(gè)寄存器,接口成功應(yīng)答,
flow_cnt <= 3'd3; //讀第下一個(gè)寄存器,接口成功應(yīng)答
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
程序中第 48 至第 63 行代碼實(shí)現(xiàn)計(jì)數(shù)定時(shí)的功能,每當(dāng)計(jì)數(shù)器計(jì)數(shù)到 1000000 - 1 時(shí),會(huì)產(chǎn)生一個(gè)周期的脈沖信號(hào)(timer_done)。該模塊輸入的時(shí)鐘頻率為 12.5Mhz,因此定時(shí)周期為 80ms。
程序中第 81 行至第 125 行代碼根據(jù)軟復(fù)位信號(hào)對(duì) MDIO 接口進(jìn)行軟復(fù)位,并定時(shí)讀取以太網(wǎng)的連接狀態(tài)。其中程序中第 138 行至 145 行代碼,根據(jù)狀態(tài)寄存器的值,為連接速率狀態(tài)位(speed_status)賦值。
4 下載驗(yàn)證
編譯工程并生成比特流 .sbit
文件后,此時(shí)將下載器一端連接電腦, 另一端與開(kāi)發(fā)板上的 JTAG 下載口連接, 將網(wǎng)線一端連接開(kāi)發(fā)板的網(wǎng)口,另一端連接電腦的網(wǎng)口或者路由器,接下來(lái)連接電源線,并打開(kāi)開(kāi)發(fā)板的電源開(kāi)關(guān),網(wǎng)口的位置如下圖所示。(根據(jù)自己的開(kāi)發(fā)板進(jìn)行管腳約束后然后連接即可,注意芯片型號(hào)在 PDS 中不要選錯(cuò)了,本文以正點(diǎn)原子的開(kāi)發(fā)板為例來(lái)講解)
點(diǎn)擊 PDS 工具欄的下載按鈕,在彈出的 Fabric Configuration 界面中雙擊 “Boundary Scan”, 我們將生成好的 .sbit
流文件下載到開(kāi)發(fā)板中去。
程序下載完成后, 等待幾秒即可看到開(kāi)發(fā)板 LED 燈的點(diǎn)亮狀態(tài),如下圖所示:
如上圖可知,兩個(gè) LED 燈都處于點(diǎn)亮狀態(tài),因此通信速率為 1000Mbps。如果按下復(fù)位按鍵可以對(duì) PHY 進(jìn)行硬件復(fù)位,按下 TPAD 觸摸按鍵會(huì)對(duì) PHY 進(jìn)行軟復(fù)位,此時(shí) PHY 芯片會(huì)重新開(kāi)始與另一端設(shè)備進(jìn)行自協(xié)商,等待幾秒后, LED 燈重新點(diǎn)亮。
另外,如果開(kāi)發(fā)板另一端連接的是電腦的網(wǎng)口,此時(shí)可以查看自協(xié)商后的通信速率。查看方法是點(diǎn)擊電腦右下角的網(wǎng)絡(luò)圖標(biāo),會(huì)看到本地連接剛開(kāi)始顯示的是正在識(shí)別,一段時(shí)間之后顯示未識(shí)別的網(wǎng)絡(luò),打開(kāi)方式如下圖所示(不同的 Windows 版本操作可能存在差異,但基本相同)。
點(diǎn)擊上圖中的 “未識(shí)別的網(wǎng)絡(luò)(無(wú) Internet)”,彈出如下圖所示界面。
點(diǎn)擊 “更改適配器” 選項(xiàng),彈出如下圖所示界面。
如果看到上圖 “以太網(wǎng)” 顯示未識(shí)別的網(wǎng)絡(luò)之后,說(shuō)明硬件連接是沒(méi)有問(wèn)題的,接下來(lái)鼠標(biāo)右擊以太網(wǎng),選擇 “狀態(tài)”,如下面兩張圖片所示。
由上圖可知,開(kāi)發(fā)板和電腦自協(xié)商的通信速率為 1Gbps(1000Mbps)。
5 總結(jié)
以上是 FPGA 以太網(wǎng)系列的第一篇,未來(lái)會(huì)繼續(xù)更新以太網(wǎng)系列,感興趣的朋友可以關(guān)注本專(zhuān)欄(免費(fèi)),持續(xù)學(xué)習(xí),共同進(jìn)步!
希望以上的內(nèi)容對(duì)您有所幫助,誠(chéng)摯地歡迎各位讀者在評(píng)論區(qū)或者私信我交流!
微博:沂舟Ryan (@沂舟Ryan 的個(gè)人主頁(yè) - 微博 )
GitHub:ChinaRyan666
微信公眾號(hào):沂舟無(wú)限進(jìn)步(內(nèi)含精品資料及詳細(xì)教程)
如果對(duì)您有幫助的話請(qǐng)點(diǎn)贊支持下吧!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-852574.html
集中一點(diǎn),登峰造極。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-852574.html
到了這里,關(guān)于FPGA以太網(wǎng)入門(mén)(一)——MDIO接口讀寫(xiě)測(cè)試實(shí)驗(yàn)(基于紫光同創(chuàng))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!