SDRAM和Nios II連接的典型電路框圖如下圖所示。SDRAM和System使用同一個PLL輸出時鍾,可以保證System Clock和SDRAM Clock的相對抖動比較小。外部晶振的時鍾送入PLL,然后由PLL產生兩個同頻的時鍾一個供給Nios II系統使用,另一個供給SDRAM使用。(把PLL設置成Zero Buffer Mode可以比較方便地控制SDRAM Clock和輸入時鍾Extern Clock的相位關系。)Nios II系統中的SDRAM控制器和SDRAM通過雙向數據線以及其它的單向控制線和SDRAM相連。
SDRAM Clock通常是E0輸出或者C2輸出,E0和C2都是PLL專用於輸出外部時鍾的,有比較小的抖動。由於一個FPGA中通常有若干個PLL,綜合后使用哪個PLL是由輸入時鍾Extern Clock決定的,所以SDRAM Clock必須和Extern Clock是同一個PLL的專用輸入管腿和專用輸出管腿。調試SDRAM和Nios II 的最關鍵是調整SDRAM Clock的相位。下面推導SDRAM Clock和Extern Clock的相位關系。
用實線向上箭頭表示Extern Clock的上升沿,用虛線向上箭頭表示Sdram Clock的上升沿。先看第一種情況:FPGA輸出數據,而SDRAM采樣數據。FPGA在Extern Clock上升沿的時候送出數據,經過最大Tcoutmax(FPGA)的時間在FPGA的管腿輸出,由於SDRAM的輸入建立時間為Tsu(SDRAM),所以Sdram Clock的采樣時機必須在信號到達SDRAM后再等Tsu(SDRAM)。忽略PCB板傳輸延時,有:
Tlead=T-(Tcoutmax(FPGA)+ Tsu(SDRAM));其中Tlead 為SDRAM Clock相對Extern Clock的最大提前量,T為時鍾周期。
在下一個時鍾上升沿來了后,FPGA會驅動新的信號,在經過最小Tcoutmin(FPGA)的時間(相當於輸出保持時間)可能把先前驅動的信號沖掉,而SDRAM要求輸入信號要求在采樣的時候保持Tih(SDRAM)的時間,所以SDRAM的采樣時機必須在Tcoutmin(FPGA)到來之前Tih(SDRAM)。忽略PCB板傳輸延時,有:
Tlag=Tcoutmin(FPGA)-Tih(SDRAM);其中Tlag 為SDRAM Clock相對Extern Clock的最大落后量,Tih(SDRAM)為SDRAM輸入保持時間。
第二種情況:SDRAM輸出數據,FPGA采樣數據。分析和上面類似,最后有:
Tlead=Tcoutmin(SDRAM)-Tih(FPGA);
Tlag= T-(Tcoutmax(SDRAM)+ Tsu(FPGA));
選取最小的Tlead和最小的TlagSDRAM Clock的允許最大提前量和最大的落后量。舉個例子:Nios II 和 SDRAM(MT48LC4M32B2-7)相連主頻100MHz。其數據如下:
- Data In: Tsu = 2 ns, Tih = 1 ns
- Data Out: Toh (Tcoutmin )= 2.5 ns, Thz/tac (Tcoutmax)= 5.5 ns (CL=3)
l 2.5 – 5.5 ns (Data Undefined)
FGPA的數據可以在編譯報告的時序分析部分得到,Tcoutmax(FPGA) ,Tsu(FPGA),Tih(FPGA)分別可以從Tco,Tsu,Th部分得到各個SDRAM相關信號的最大值。而Tcoutmin(FPGA)則可以運行Fast timing model timing analyzer 來得到。
比如:
- Data In: Tsu = 1.75 ns, Tih = 0 ns
- Data Out: Tcoutmin(FPGA) = 2 ns, Tcoutmax(FPGA)=5.5 ns
Tlead=T-(Tcoutmax(FPGA)+ Tsu(SDRAM))=10ns-5.5ns-2ns=2.5ns
Tlead=Tcoutmin(SDRAM)-Tih(FPGA)=2.5ns-0ns=2.5ns
選一個小的,仍然是2.5ns。即Tlead=2.5ns
Tlag=Tcoutmin(FPGA)-Tih(SDRAM)=2ns-1ns=1ns
Tlag= T-(Tcoutmax(SDRAM)+ Tsu(FPGA))=10-5.5ns-1.75ns=2.75ns
選一個小的,即Tlag=1ns。
所以SDRAM Clock的相對External Clock相位為-2.5ns~+1ns之間。在生成PLL時指定在這個范圍內的相位偏移就可以了。
注意:因為FPGA的時序分析報告都是以External Clock來算的,所以我們並沒有使用System Clock來分析。
搭建好了這個SOPC之后就可以用NIOS來實現我們想要的功能了。下面轉入正題,用NIOS內部的SDRAM控制器,在SOPC里添加了這個項目之后,我們就可以狠方便的實現SDRAM的驅動了。因為控制器已經為你引出了SDRAM需要的連線,我們所作的工作只是需要把這些線連起來就可以了,下面簡單的介紹一下這些引腳的功能。 CLK--時鍾輸入 CKE--內部刷新時鍾控制端 CS--片選 BA1,0--BANK的選擇 A0--A11--地址線,包括行地址與列地址 RAS--行地址選通 CAS--列地址選通 WE--寫使能 LDQM,UDQM--字節與字控制端 DQ0--DQ15--數據端 看了這些控制線,大家應該感到狠痛苦了,確實SDRAM的控制確實狠復雜。但是NIOS里的控制器幫我們解決了這些問題,當我們正確的連好了這些線之后,我們就不需要去管它了,NIOS會幫我們處理好這些時序,也就是說我們要作的工作是:1 在SOPC里設計一個根我們用的SDRAM時序一樣的控制器,這需要參考SDRAM的資料。2 正確地連接好NIOS與外部SDRAM的連線。3 也是最麻煩的一點,CLK的時序問題。下面着重介紹一下CLK的時序設置。 我們先看一下原理,FPGA里的NIOS2需要一個時鍾,SDRAM需要一個時鍾,那這兩個時鍾之間是什么關系呢?答案是很復雜。首先來講這兩個時鍾都是PLL的輸出,PLL里根據不同的FPGA有不同的選項。
一般來講,PLL的輸出有C1,C0,E1,E0........,C就是說PLL經過內部的復雜邏輯的輸出,所以它根原始的時鍾輸入之間是相位差的,E就是說直接時鍾輸出,它的相位差幾乎位0,但是它需要特定的引腳。我們在設計的時候最好用E端作SDRAM的時鍾輸入,具體的原因看后面的解釋。
這段解析比較勉強,可以說是錯誤的,其實E0這個信號是Altera用來對外輸出的,並非E0就沒有經過復雜的運算。在CycloneIII中,好像沒有區分內部和外部,估計所以信號都可以對外輸出。
SDRAM的特殊性決定了它的驅動的復雜性,想要完全明白它的所有時序的意義需要很長的時間積累,但是應用的話不需要那么多,所以下面簡單介紹一下最關鍵的幾個。 1、 --輸入建立時間,SDRAM里的參數
2、 --輸出保持時間,SDRAM里的參數
3、 --FPGA從引腳輸入到內部邏輯的建立時間
4、 ---FPGA內部邏輯到輸出的建立時間
這是我們計算SDRAM的CLK所需要的幾個最關鍵的參數, 意義是說當NIOS的地址線和數據線到達SDRAM時,需要保持這么長的時間, 是說SDRAM在讀取的時候,需要這么長的時間才能把輸出值輸出到總線上,設CLK為時鍾信號,CLK1為SDRAM的時鍾,CLK2為FPGA外部引腳的時鍾,可以看出來,CLK2-CLK= ,關於CLK2與CLK1我們可以仿真得到他們之間的相差,所以我們要做到的是:
1、 CLK2-CLK1=
2、 CLK1-CLK2=( + ) (以上的計算是相差的計算)
相差是正的話說明被減數在減數之后。所以通過上邊的公式可以確定CLK1的范圍,所以在PLL里設置一下就可以讓我們的SDRAM滿足系統的要求了。關於為什么要用E0來作SDRAM的時鍾的問題,首先我們每次編譯的結果的時序都不一樣,雖然變化部大,但在高頻的時候部可忽視,而E0的相位與編譯無關,其次,它的抖動比C端要小。現在我的系統跑在75M上,還可以,但感覺這種方法在高頻中會有潛在的問題,以后我會進行相應的測試,然后告訴大家結果。 上邊算是對SDRAM的一個小結。 下面對FLASH作一下解釋,跟SDRAM一樣,FLASH只需要連好相應線就可以。但在實際的應用中有一個小問題,就是說假如FLASH的總線是22位的,既21..0,NIOS會給你22..0,所以我們在連接的時候需要錯一位,也就是說NIOS的1接FLASH的0,依次類推下去。但有的時候我們需要SDRAM和FLASH公用總線,這就存在一個問題,FLASH需要從1開始接,而SDRAM是從0開始,所以設計公用總線的時候,原理圖上SDRAM的A1要接FLASH的A0,這點一定要注意,但發現ALTERA不推薦這么去設計,因為SDRAM需要自己的一套時序,共用的話會大大降低SDRAM的性能,在實際中也發現了這點,所以在資源部緊張的情況下還是部要復用。還有NIOS對AMD的FLASH支持的很好,其他的象SST的FLASH ,對以前的200,400,800系列支持的好,但之后的160,320,640就支持部好了,所以用NIOS的時候最好用AMD的FLASH.
SDRAM使用注意事項:
1. 首先要在sopc里加入sdram控制器,根據器件手冊設置好數據寬度,行列地址寬度等;
2. 加入PLL移相。因為SDRAM為動態的存儲器,對時序要求比較高.因為有延遲,所以加入PLL來調整相位,一般的經典值為-63deg,要是不行,可以每5度增加或者減少;用cylone器件時最好用e0輸出SDRAM的時鍾,同時用專用的時鍾輸出引腳輸出;cycloneⅡ用c2;
3. 數據線設置成雙向,同時因為管腳比較多,務必要保證管腳鎖定正確;
#include "system.h" #include "altera_avalon_pio_regs.h" #include "alt_types.h" int main (void) __attribute__ ((weak, alias ("alt_main"))); int alt_main (void) {unsigned char sdrw_d[60],sdrr_d[60],i; for(i=0;i<50;i++) { sdrw_d = 0x0; } for(i=0;i<50;i++) { sdrw_d = i; IOWR(SDRAM_BASE, i, sdrw_d); } for(i=0;i<50;i++) { sdrr_d = 0x0; } for(i=0;i<50;i++) { sdrr_d = IORD(SDRAM_BASE, i); if(sdrr_d != sdrw_d) while(1){IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0xff);}; } }
在sopc里加入SDRAM控制器,命名為SDRAM,讓程序在片上RAM執行,
本例中,當讀寫的數據不一致時,輸出信號來點亮LED,也可以根據實際情況另做判斷。比如在循環那里加斷點,總之,是要判斷程序是否進入死循環,從而判斷讀寫數據是否一致。