這篇文章是一年半以前寫(xiě)的,當時(shí)使用這種方法,成功解決了問(wèn)題。前兩天,有網(wǎng)友在做以太網(wǎng)設計的時(shí)候,也遇到了這個(gè)問(wèn)題,做以太網(wǎng)傳輸,讀寫(xiě)fifo時(shí)候,總是會(huì )丟一個(gè)數據,后來(lái)他找到了這篇文章,并按照文章中的方法進(jìn)行后,問(wèn)題也得以解決,因此今天就再以公眾號文章的形式發(fā)布一遍。
以下為文章原文,編寫(xiě)于2017年7月
一直在調試使用Verilog編寫(xiě)的以太網(wǎng)發(fā)送攝像頭數據到電腦的工程(以下簡(jiǎn)稱(chēng)以太網(wǎng)圖傳)。該工程基于今年設計的一款FPGA教學(xué)板AC620。AC620上有一個(gè)百兆以太網(wǎng)接口和一個(gè)通用CMOS攝像頭接口,因此非常適合實(shí)現以太網(wǎng)圖傳功能。CMOS攝像頭接口沒(méi)有什么好說(shuō)的,就是IO而已,這里先重點(diǎn)介紹下以太網(wǎng)接口。
以太網(wǎng)接口使用了一片10/100M自適應以太網(wǎng)收發(fā)器(PHY),型號為RTL8201。該芯片和FPGA采用標準的MII接口進(jìn)行連接。什么是MII接口呢?這里暫不做任何介紹,因為今天要介紹的主角不是他。關(guān)于MII接口等以太網(wǎng)知識,可以關(guān)注小梅哥的FPGA以太網(wǎng)系列連載博客。簡(jiǎn)單點(diǎn)說(shuō),對于以太網(wǎng)發(fā)送數據來(lái)說(shuō),有一個(gè)發(fā)送時(shí)鐘、一個(gè)發(fā)送使能信號和4位并行的數據發(fā)送信號,對于以太網(wǎng)接收數據,有一個(gè)接收時(shí)鐘、一個(gè)接收數據有效信號和4位并行的數據接收信號。在發(fā)送時(shí),發(fā)送使能信號有效,則每個(gè)字節的數據被拆分成2個(gè)4位的數據然后通過(guò)4位的數據信號,通過(guò)兩個(gè)周期的時(shí)鐘信號,依次傳遞到以太網(wǎng)PHY芯片,再由PHY進(jìn)行并串轉換,串行編碼等工作后,將數據通過(guò)網(wǎng)絡(luò )變壓器加載到傳輸媒介(網(wǎng)線(xiàn))上。在這里,以太網(wǎng)發(fā)送時(shí)鐘是由以太網(wǎng)PHY芯片產(chǎn)生,然后送給FPGA使用的。該時(shí)鐘信號一般叫做mii_tx_clk,當以太網(wǎng)速率為100Mbps時(shí),該時(shí)鐘信號為25MHz。而在FPGA側,為了保證數據和控制信號的傳輸能夠高度的同步于該以太網(wǎng)發(fā)送時(shí)鐘信號,因此往往直接使用該以太網(wǎng)發(fā)送時(shí)鐘信號作為相關(guān)時(shí)序邏輯的時(shí)鐘信號。也因為這個(gè)要求,問(wèn)題隨之產(chǎn)生——該以太網(wǎng)時(shí)鐘信號作為眾多時(shí)序邏輯的時(shí)鐘信號,其時(shí)鐘質(zhì)量和到達各個(gè)寄存器的時(shí)間最好也沒(méi)有大的偏差,這樣才能夠保證時(shí)序收斂,從而使得設計的邏輯運行穩定。
在A(yíng)C620 FPGA開(kāi)發(fā)板上,該以太網(wǎng)發(fā)送時(shí)鐘信號連接在了EP4CE10F17型FPGA的D11引腳上。而D11只是一個(gè)普通的FPGA輸入輸出管腳,非時(shí)鐘輸入管腳。因此從該引腳接入的信號如果不經(jīng)過(guò)任何處理,將無(wú)法像專(zhuān)用時(shí)鐘輸入管腳上輸入的信號一樣被連接到全局時(shí)鐘資源上。那么該時(shí)鐘信號在FPGA片上進(jìn)行走線(xiàn)時(shí),只能使用片上的長(cháng)線(xiàn)和短線(xiàn)布線(xiàn)資源,有時(shí)候甚至要通過(guò)LUT連接,才能到達各個(gè)寄存器。那么這里,問(wèn)題就出現了,個(gè)人感覺(jué)的主要問(wèn)題最起碼有2點(diǎn)(不足的歡迎大家補充):
1、由于該時(shí)鐘信號是通過(guò)各種長(cháng)短布線(xiàn)資源,甚至經(jīng)過(guò)LUT連接才能到達其驅動(dòng)的各個(gè)寄存器,因此該時(shí)鐘信號從進(jìn)入FPGA管腳,到傳遞到各個(gè)寄存器的時(shí)鐘輸入端,其時(shí)間是很難保持相同的,距離的遠近直接決定了該時(shí)鐘信號的傳輸延遲。而這個(gè)傳輸延遲的差值,可能達到幾納秒甚至十幾納秒。這個(gè)差值,將直接影響數據的建立和保持時(shí)間,造成時(shí)序無(wú)法收斂,從而導致設計失敗。我們可以通過(guò)下圖更加直觀(guān)的分析這個(gè)問(wèn)題。
CLK認為是時(shí)鐘輸入腳輸入的時(shí)鐘信號。REG1是數據源,REG2是數據接收寄存器。REG1的輸出端Q經(jīng)過(guò)一段組合邏輯后連接到REG2的輸入端D上。
REG1.CLK為CLK到達REG1的波形,相對于CLK,有一個(gè)延遲,設為T(mén)clk1.
REG1.Q為REG1的輸出端數據值,其值開(kāi)始穩定下來(lái)時(shí),相對于REG1.CLK,有一個(gè)延遲,設為T(mén)co。
REG2.D為REG2的輸入端D端口上的數據波形,該信號由REG1.Q經(jīng)過(guò)組合邏輯傳遞后到達,因此REG1.Q到達REG2.D這個(gè)時(shí)間是數據傳輸時(shí)間,設為T(mén)data.
RERG2.CLK(OK)是使用全局時(shí)鐘資源時(shí)理想的波形,這種情況下,認為CLK到達REG1和REG2的時(shí)間差很小。
RERG2.CLK(ERROR)是使用非全局時(shí)鐘資源時(shí)的波形,這種情況下,認為CLK到達REG1和REG2的時(shí)間差可能較大,設這個(gè)差值為T(mén)clk2。
由于REG2.D端口上的數據將在REG2.CLK的上升沿被采樣,那么。當使用全局時(shí)鐘資源時(shí)可以看到,在REG2.CLK的上升沿前后一段時(shí)間,數據是保持穩定的。而使用非全局時(shí)鐘資源的時(shí)候,由于時(shí)鐘走線(xiàn)的延遲,REG2.CLK到達REG2的時(shí)間將會(huì )有一個(gè)較大的差值,在這種情況下。在REG2.CLK的上升沿前后,REG2.D上的數據可能已經(jīng)不穩定甚至變化了。因此導致數據接收失敗。
2、使用非全局布線(xiàn)資源,時(shí)鐘信號在布線(xiàn)的過(guò)程中更容易受到周?chē)盘柕母蓴_。導致時(shí)鐘質(zhì)量變差。什么意思呢?打個(gè)比方,一只小鳥(niǎo)和一只兔子共同穿越一個(gè)滿(mǎn)是灰塵的工地。工地上到處都是灰塵。小鳥(niǎo)從空中飛過(guò),不直接與灰塵接觸,因此基本不會(huì )沾到灰塵,因為它有自己獨立的路線(xiàn)和空間。而兔子因為不會(huì )飛,因此只能跑著(zhù)從工地中穿過(guò),那么,不可避免的,兔子的腳上會(huì )沾上灰塵。導致當兔子穿過(guò)這個(gè)工地的時(shí)候,早已由小白兔變成了小灰兔。時(shí)鐘信號也是如此,全局時(shí)鐘資源有專(zhuān)門(mén)的時(shí)鐘路徑,在自己的空間走線(xiàn),不穿過(guò)或很少穿過(guò)各種高速翻轉的邏輯區域,因此很少受到污染。而非全局時(shí)鐘資源沒(méi)有專(zhuān)門(mén)的時(shí)鐘路徑,只能使用通用布線(xiàn)資源,而這些布線(xiàn)不可避免的會(huì )穿過(guò)很多高速翻轉的邏輯區域。從而受到這些邏輯的翻轉噪聲的污染。最終時(shí)鐘信號變的很差。例如邊沿上升和下降更慢,占空比發(fā)送變化,時(shí)鐘抖動(dòng)增大等。
好了,回到問(wèn)題的開(kāi)頭,由于A(yíng)C620開(kāi)發(fā)板上以太網(wǎng)PHY芯片的mii_tx_clk是連接到了FPGA的普通IO口上,因此如果不經(jīng)過(guò)處理,該時(shí)鐘信號將不能走全局時(shí)鐘資源,因此只能通過(guò)普通布線(xiàn)資源走線(xiàn),從而導致到達各個(gè)寄存器的時(shí)間差別很大,而且受到各個(gè)高速翻轉邏輯的噪聲影響也很大,時(shí)鐘抖動(dòng)嚴重。所以,當該時(shí)鐘信號驅動(dòng)的邏輯過(guò)多時(shí),勢必導致整個(gè)設計時(shí)序無(wú)法收斂,然后就會(huì )出現各種各樣的問(wèn)題。
接下分析下我所編寫(xiě)的以太網(wǎng)發(fā)送邏輯。由于該邏輯主要為講解以太網(wǎng)的各種協(xié)議而設計,而以太網(wǎng)協(xié)議最典型的特征就是數據是分層打包的。因此我在設計該邏輯的時(shí)候也嚴格按照以太網(wǎng)分層的方式進(jìn)行。分別為MAC層、IP層、UDP層和用戶(hù)數據層。在MAC層、IP層和UDP層,我都使用了PHY提供的這個(gè)時(shí)鐘信號,所以導致該時(shí)鐘信號的扇出非常的高。
從Quartus II軟件的編譯報告可以看出,該時(shí)鐘信號的扇出為193個(gè)。是所有非全局信號中扇出最高的。這么高扇出的一個(gè)信號,還是時(shí)鐘,可以想象該時(shí)鐘到達這193個(gè)位置的路徑有多少種可能,要經(jīng)過(guò)多少布線(xiàn)鏈接??上攵摃r(shí)鐘信號有多差。所以,我在調試時(shí)候出現的問(wèn)題就是——不做任何修改,將該工程編譯多次,有的時(shí)候編譯得到的sof文件下載進(jìn)芯片后能跑一整夜不宕機,而有的時(shí)候編譯得到的sof文件下載進(jìn)入芯片后幾秒鐘內就宕機了。
了解決這個(gè)問(wèn)題,需要將mii_tx_clk這個(gè)時(shí)鐘信號分配到全局時(shí)鐘資源上。這樣該時(shí)鐘信號就能走全局時(shí)鐘資源,扇出再多,也能差不多同時(shí)到達各個(gè)寄存器。也有了自己的專(zhuān)線(xiàn),不用從灰塵里滾爬,不怕小白兔變小灰兔。
首先看下全局資源的使用情況,如下圖。
可以看到,PLL的4個(gè)輸出,復位輸入,以及晶振輸入的50M時(shí)鐘(clk)都被分配到了全局時(shí)鐘資源上,尤其是clk信號,扇出高達1018個(gè)。
那么怎樣才能讓我們普通IO輸入的時(shí)鐘信號mii_tx_clk信號也能進(jìn)入全局時(shí)鐘資源呢?在Cyclone IV E器件中,有這樣的專(zhuān)用緩沖器,該緩沖器可以將普通IO或者寄存器產(chǎn)生的時(shí)鐘信號分配到全局時(shí)鐘資源上。該緩沖器對用戶(hù)以IP的形式提供,在IP列表的IO分組中,名稱(chēng)叫做ALTCLKCTRL,如下圖所示。
設置也非常簡(jiǎn)單只需選擇該時(shí)鐘控制器的用途,我們這里設置為'For global clock'。另外在輸入數量那里選擇相應的值即可,我們這里只需將mii_tx_clk接入全局時(shí)鐘資源,不需要做多時(shí)鐘切換,因此數量選擇1,設置完成后點(diǎn)擊finish即可。
將該IP例化到我們的設計中,先定義一個(gè)mii_tx_clk_g,代表走全局時(shí)鐘資源的mii_tx_clk信號。然后將輸入的mii_tx_clk信號連接到這個(gè)緩沖器的輸入,將緩沖器的輸出連接到mii_tx_clk_g上即可,再由mii_tx_clk_g作為時(shí)鐘信號驅動(dòng)之前的所有時(shí)序邏輯。如下圖所示。
wire mii_tx_clk_g;
clk_ctrl clk_ctrl(
.inclk(mii_tx_clk),
.outclk(mii_tx_clk_g)
);
通過(guò)該緩沖器,將mii_tx_clk信號連接到了全局時(shí)鐘資源上,再通過(guò)全局時(shí)鐘資源去連接到各個(gè)寄存器,則時(shí)鐘延遲和時(shí)鐘抖動(dòng)都變的很小,使得時(shí)序易于收斂,設計出來(lái)的系統就更加穩定了。下圖為通過(guò)該緩沖器將mii_tx_clk分配到全局時(shí)鐘信號上后的全局資源使用圖,可以看到,mii_tx_clk信號已經(jīng)被分配到了全局時(shí)鐘資源上。再由此方式編譯得到的sof文件,燒寫(xiě)到AC620開(kāi)發(fā)板中,能持續穩定運行。再次編譯工程,再下載測試,都能穩定運行,問(wèn)題得以解決。
下圖為使用AC620開(kāi)發(fā)板進(jìn)行以太網(wǎng)圖傳的實(shí)際照片。