1. 程式人生 > >DDR3調試總結

DDR3調試總結

與操作 rank 數據接收 無法 解決問題 文章 基本原理 font 老師

以前同是DDR3的無知少年,由於項目需求、工作需要,有幸深入研究DDR3,中間也確實歷經各種盲目階段,查詢資料、建立工程、調試錯誤等等,如今對此不敢說是精通,也只能說是基本入門,寫此文章的目的也無非是想讓那些和當初的我一樣的初學者少走些彎路而已,也只當是拋磚引玉,也希望大神們能多多指教!提前謝過了,下面也為了不讓大家看的那麽無聊,也會適當換個方式,也望大家能給幾分薄面,大神們多多指點,小菜鳥們就好好學習吧,畢竟也是手打的材料,下面入正題~

作為初學者,我認為最好能做到以下三個方面:材料準備與學習、工程建立與調試、日常總結與記錄。

有些人會問誰都知道要學習資料,你也猜到了我要說手冊,廢話,傻子都知道沒有手冊搞不定的,當然是不只手冊啦,如果你是第一次接觸,最好下載幾篇相關的學術論文,什麽,不知去哪找?!不行就百度,我是在知乎上下的(本人西電,有沒有師姐校友啊,嘿嘿,本校免費下),簡單來說就是下載幾篇相關論文,自己對相關的結構流程能有所了解,最好是你要調試啥就找相關的(我當時就傻x了,調DDR3,下了幾篇DDR2當然可以借鑒,但心裏受影響啊),當然還有最最重要的官方的datasheet,沒有它,想搞定DDR3?洗洗睡吧~當然實驗平臺我就不說了,如果條件簡陋,或者囊中羞澀,軟仿也可以,怎麽?瞧不起軟仿?沒錢想學習還不允許嗎?我當初就硬著頭皮軟仿了一周,可坑爹的實驗室有板子,我楞是不知道,後來才找老師拿了她,於是才上了她,好啦,扯遠了,有板子,板子的原理圖也要有吧,材料這些就可以了,至少你可以有事情幹了!

再就是建立工程與工程調試,對於初學者網上都會說先看手冊,建個example,跑一跑,了解下例程,對,這一步必須要做,而且要認真做!但是可能等最後你會發現,最終的結果可能並沒有example那麽復雜……,下面再細說,工程調試是一個很無聊但是很艱巨的過程,它的重要性,我在這就不說了,覺得不重要的又到睡覺的時候了。

最後就是日常總結和記錄,像是日記,可並不是,這算是公開的,你師妹想看看?你不給?開玩笑,我一直認為這是個好習慣,日常犯的一些錯誤做好記錄,總結原因和解決辦法,這將會是一筆財富!當然可能沒有過習慣的人,一開始不知該記錄些啥,我一開始也是如此,我就想些啥就寫啥,寫著寫著就知道了,現在不寫都難受,這是病,不過不用治。簡單來說一些實驗現象,或者日常的仿真結果以及分析總結等,可以自己看,哪怕老板讓你寫報告你也有材料不是?抓緊拾起你的筆,敲起你的鍵盤,跟著我左手右手一個……

下面到了真刀真槍硬幹的時候了,有本事你別跑!

一、 材料準備與學習

先簡單介紹下我的準備,而後簡單介紹下DDR3的相關原理性知識,作為專業文檔,這部分內容要有,而且必須有!我用的是X家的Virtex-6的FPGA,DDR3用的是美光的,論文下了幾篇,名字我就不列了,自己查去,下面我簡單介紹下DDR3,當然挑和工程相關的,別的自己去查資料。

技術分享圖片

算啦,貼張圖,誰讓我勤政愛民呢,重點的已經標出來了,自己動動手指就可以,文檔裏有的我就不多說了,自己看,介紹下別的幾個關鍵詞,很有用的!

DDR(Double Data Rate SDRAM),即雙倍速率同步動態隨機存儲器,含義是數據會被時鐘的上升沿和下降沿采樣,相對於時鐘上升沿采樣,這種方法相當於把采樣時鐘頻率提升了一倍。DDR3 SDRAM在降低系統功耗的同時很大程度上提高了系統性能,其理由“fly-by”和動態片上匹配技術對於信號完整性的改善效果明顯。

1、邏輯Bank

組成DDR3的存儲單元稱為邏輯bank,在邏輯bank中,先指定一個行,再指定一個列,可以準確地定位到所需的存儲位置,這是DDR3尋址的基本原理,目前,DDR3基本上是8bank設計。

2、物理Bank

這是一個與存儲子系統相關的術語,並不針對存儲芯片,在PC上的北橋芯片用於控制存儲器與CPU之間的數據交換,為了高效傳輸數據,北橋芯片是存儲器總線的數據位寬等同於CPU數據總線的位寬,這個位寬被稱為物理Bank(又稱為Rank),當前這個位寬基本為64bit,每個內存顆粒的位寬為8bit,為了滿足Rank所需的64位寬,需要8顆內存顆粒並行組成。

3、行激活命令

在對DDR3的某一個bank內數據進行讀/寫訪問前,首先必須將該bank中數據所在的行激活,一旦激活,則該行將保持激活狀態直到發送預充電命令到DDR3。發送行激活命令式,bank地址與相應的行地址同時發出;行激活命令發送後,隨後發送列地址尋址命令與具體的讀/寫操作命令,由於這兩個命令也是同時發出的,所以一般都會以讀/寫命令來表示列尋址。從行有效到讀/寫命令發出之間的時間間隔被定義為tRCD,tRCD是DDR的一個重要時序參數,廣義的tRCD以時鐘周期為單位,如tRCD=3,就代表延遲周期為3個時鐘周期。

4、讀/寫命令

DDR3執行bank的行激活命令後,可以發送讀/寫命令對該行進行讀/寫操作,在發送讀/寫命令時,引腳A10決定是否允許自動預充電操作,如果允許進行預充電,那麽讀/寫命令結束時會自動對該行進行預充電,否則該行將一直保持激活狀態控制邏輯可繼續對該行進行讀/寫操作

5、數據掩碼

DDR3采用數據掩碼(DQM)技術,用於屏蔽不需要的數據。通過采用DQM,DDR3控制器能夠以字節為操作單元指示I/O端口數據的有效性,當然在讀取DDR3時,被掩碼掩掉的數據仍然會從存儲器中讀出,只是在“掩碼邏輯單元”處被屏蔽

6、預充電命令

數據讀取完成之後,為了釋放DDR3內讀出放大器的空間,以供同位置bank內的其他行尋址及傳輸數據,DDR3芯片將執行預充電命令來關閉當前的工作行。預充電對航中所有的存儲單元進行數據重新加載,並對行地址進行復位,其中A10決定是對某一個bank或所有bank進行預充電。預充電命令之後,要經過一段時間才允許發送行激活命令操作新的工作行,這個時間間隔稱為tRP

7、刷新操作

DDR3需要不斷進行刷新操作才能在存儲單元中維持數據的有效存儲。雖然預充電能夠針對一個或所有bank中的工作進行刷新,但是預充電命令與操作相關,不能保證所有存儲空間的遍歷,同時其操作時間也不固定。而刷新操作則有固定的操作周期,一次對所有行進行操作,以維護存儲單元中的所有數據。但是,與預充電不同,刷新操作的行是指所有bank中地址相同的行,而預充電中各bank中的工作行地址並不一定是相同的。

刷新操作分為兩種:自動刷新與自刷新。對於自動刷新,在刷新過程中,所有bank都停止工作,而每次刷新結束後,DDR3才可以進入正常的工作狀態,即在刷新期間,所有工作指令只能等待而無法執行。自刷新則主要用於休眠模式低功耗狀態下的數據維護,此時不再以高系統時鐘工作,而是根據內部的時鐘進行刷新操作。

8、突發長度/類型

突發是指在同一行中相鄰的存儲單元連續進行數據訪問,連續訪問的時鐘周期數就是突發長度,突發長度由模式寄存器MR0確定,可設置為固定模式:BC4或BL8模式,即在讀/寫操作室通過A12選擇突發長度4或8。進行突發傳輸時,只要指定起始列地址與突發長度,DDR3就會依次地自動對後續相應數量的存儲單元進行讀/寫訪問,而不再需要DDR3控制器連續的提供列地址。在這種模式下,除了第一次數據的訪問需要若幹個周期外,後續的每次數據只需一個周期即可獲得

9、模式寄存器

模式寄存器用於設置DDR3 SDRAM的工作模式,目前支持4個模式寄存器,分別為MR0、MR1、MR2、MR3,其中MR0用於設置DDR3的基本工作模式,包括突發長度、突發類型、CAS延遲和DLL復位等。MR1用來存儲DLL使能、輸出驅動長度、Rtt_Nom、額外長度和寫電平使能等。MR2用來存儲控制更新的特性、Rtt_WR阻抗和CAS寫長度。MR3用來控制MPR。

Xilinx公司提供的MIG工具適用於高速存儲器接口的解決方案,MIG工具中的DDR3 SDRAM控制器設計運行用戶在V6等器件中通過用戶接口快速建立FPGA內部控制邏輯與外部存儲器的訪問連接,DDR3 SDRAM存儲器接口包括用戶接口模塊、存儲控制器、物理層模塊、以及本地接口和物理層接口等。

下面再重申下幾個重要的內容,搞清以下幾個:tRCD(RAS to CAS delay)、CL(CAS Latency,CAS潛伏期/RL,僅在讀取時出現)、CWL(CAS Write Latency)、附加延時AL、BL(Burst Length,DDR3的預取為8bit,所以BL固定為8),BC(DDR3增加了一個4bit Burst Chop 突發突變)。
對與DDR3的工作流程資料裏有,鑒於篇幅原因,就不提了,也該自己看看了。

二、工程建立與調試

首先,在CORE Generator中建立一個核。

技術分享圖片

如果你有參數那很好,按照你的參數建立,如果你沒有芯片資料,但有前輩的測試工程,也可以,在工程目錄下找到datasheet.txt的文件打開,裏面有以前建立核的相關配置,當然你如果建立核之後,也會生成這樣一個文件,配置也都在裏面,如果你啥也沒有,只想跑個仿真,也可以!那就一路默認,或者任意配置,反正又不犯法。

建好之後,任務就來了,如果你是一個老油條,就不用我多說了,如果你是新手你就按照手冊中建立仿真的過程走一下?算了我告訴你吧,MIG工具最終的生成結果,存放在名為的文件夾中,< component name >文件夾中包含3個文件夾:docs:包含了設計中的相關文檔。example_design:在仿真以及硬件測試中均可使用,除了控制器設計外,example_design還包含了可綜合的測試文件,該測試文件可生成讀寫命令,並比較邏輯驗證寫入數據與讀取數據的一致性。user_design:中僅包含控制設計,允許用戶根據自身需求設計應用邏輯(測試文件)。

想直接分析,可以!把ipcore_dir\ddr3\example_design\rtl下的文件全部添加到你新建的工程中,還有ipcore_dir\ddr3\example_design\sim目錄下的

技術分享圖片

當然,你如果習慣用modelsim,可以按照datasheet中的指示進行,我是有點懶,就直接添加了,下面可以簡單配置下頂層參數,可以更快的仿真,將SIM_BYPASS_INIT_CAL設置為FAST,你點了運行了沒?咋還不點?!讓程序跑著,下面說下咱們的工程,example_design中有一個流量生成器,簡單來說就是產生數據,以及最終接收數據給你的,這部分也是用戶可以編輯刪除修改的,也是和user_design的區別,user_design顧名思義,用戶的設計,所以流量生成器當然是自己定義了,別的基本相同,對於 example_design仿真我就不具體分析了,自己看看就可以,我還是說些實用的吧!

example_design只是讓你能對DDR3的工作有所了解,實際中的應用還是要利用user_design,並在此基礎上進行修改,具體的修改等細節的工程問題,在總結中介紹,下面對example_design工程進行一些分析:

技術分享圖片

數據由流量產生器產生,經過用戶接口部分,存儲器控制部分,物理層部分傳輸給外部DDR3存儲器,數據接收反之,具體每個文件是幹啥的,看手冊吧。反正我調程序是沒改過Memc_ui_top裏的程序,只是改過頂層的參數。

下面是user_design中的實現框圖,我們要做的就是建立自己的user_design

技術分享圖片

你也許會說,一點根據都沒有,怎麽建?還是手冊。

技術分享圖片

手冊中還有幾幅時序圖,有BL=4的等等,具體信號的作用以及輸入輸出關系,因果關系我就不說了,手冊中有信號線的說明,一看就懂,我們控制的也就是按照這些時序圖來寫,上面的指是一個例子,僅供參考。

三、 日常總結與記錄

最後這一部分就不像上兩部分那麽枯燥了,下面主要是我日常的總結,主要包括具體的工程實現與仿真分析,以及遇到的問題以及解決方案。此部分含金量很高,我盡量寫的詳細些,大家也認真體會一下。

參數設置:


輸入時鐘:125M(此時鐘是外部芯片接的晶振時鐘,內部使用需要進行倍頻分頻)
主時鐘:400M(由輸入時鐘倍頻得到)
突發長度:8(期間用過4,具體原因,下面再說)


下面以一個框圖說明位寬時鐘關系

技術分享圖片

首先以發送數據為例,用戶端數據首先經過FIFO緩存,解決跨時鐘域的問題,FIFO的寫入時鐘為100M,數據位寬為256bit,FIFO的讀取時鐘為200M,位寬為128bit,主時鐘為400M,用戶時鐘為此主時鐘分頻得到,可以驗證數據量:200M*128bit = 400M*2*32bit(其中2為上下沿發送)。

接下來對工程進行簡要描述:最一開始數據由一個流量產生器traffic_generator發出,首先對DDR3寫數據,數據每加一,地址加8(突發長度為8,而且貌似規定地址必須加8,我試過4,不成),寫數據地址加到4000時,寫操作結束,開始讀數據,同樣是地址加8,當然讀完4000為止。讀寫數據以及讀寫地址由於是跨時鐘域處理,所以都需要經過FIFO(具體的設置我就不說了,基本設置),也就是4個FIFO,寫數據FIFO,寫地址FIFO,讀數據FIFO,讀地址FIFO,其中兩個地址FIFO是可以IP核復用的,對於4個FIFO的讀寫將成為此次設計的重點以及難點,我也只能說下大體思路,其余的就靠大家自己摸索了。

首先對於寫數據以及寫地址FIFO的寫使能,只要不滿就可以寫,而我們主要控制的就是何時讀,以及如何讀,主要通過狀態機完成,寫數據FIFO的讀使能和用戶接口的寫使能(app_wdf_wren)可以認為同步,我們要控制產生的也即是這幾個信號:app_wdf_wren,app_wdf_end,wr_dfifo_ren,wr_afifo_ren,決定這幾個信號的輸入信號:app_wdf_rdy,app_rdy,wrq(寫請求,不空同時初始化完成就有寫請求)。

首先對於讀數據以及讀地址FIFO的寫使能,只要地址和數據有效就可以寫,對於讀數據的讀使能,只要FIFO不空就出數據,而我們主要控制的是讀地址FIFO的讀使能,主要通過狀態機完成,我們要控制產生的也即是這幾個信號:app_en,rd_afifo_ren,決定這幾個信號的輸入信號:app_rdy ,rdq。
程序設計完成,最好對DDR3 IP核的參數進行下配置,以方便仿真,可以將SIM_BYPASS_INIT_CAL設置為FAST,可以跳過最一開始的初始化,節約仿真時間,將ORDERING設置為STRICT,中間數據不會進行重排序,便於查看中間的仿真結果。

下面就是綜合、實現、生成bit文件,可以上板子了……

如果您沒遇到問題,那你真是命好!

還是說說我這命不好的吧!

問題總結一:系統不能初始化

一般如果正常添加生成核後自帶的user_design,能正常編譯通過,不會存在不能初始化的問題!!!在此工程中,按照設置總結進行相應設置,進行仔細檢查,利用chipscope進行信號抓取,可以一個觸發信號一個觸發信號的測試,而後分析原因,切不可貿然懷疑硬件的問題(前提是曾經成功過)

問題總結二:雖可以初始化,但是沒有寫入數據

此問題主要是出現在頂層例化中,初始化信號未進行模塊的正確連接,主要還是不細心,仔細進行頂層檢查,尤其是自己動手修改過的地方,一定要註意!

下面說一下神奇的現象:(寫入數據開始設置為128,最終版為256,改為256可以避免很多問題,可以想想為什麽?)

1、讀寫時鐘改為200M(此時鐘對應於寫FIFO的時鐘,也就是將上面的100M換為200M,ddr3核主時鐘400M),突發長度8(可預知結果出現連續兩個周期數據相同),寫入數據位寬128,讀取位寬128,抓取結果與預測結果相同

技術分享圖片

技術分享圖片

2、讀寫時鐘改為100M,突發長度4(可預知結果不會出現連續兩個周期數據相同),寫入數據位寬128,讀取位寬128,抓取結果與預測結果相同,看來如果不修改寫入位寬時,突發長度改為4也是一種策略

技術分享圖片

技術分享圖片

技術分享圖片

下面對上面兩種情況進行具體分析:

現象一:此平臺選用的DDR3單片為16位,硬件設計時是將兩片並聯,見下圖

技術分享圖片

由於寫入的數據為128位,所以如上圖,我們寫入的只是一個大方框的數據,其實為何後面沒有寫入數據的部分又保留了前128位數據的值,這和寫入數據的FIFO的寫使能有關,下面再介紹(先知道此時突發長度為8時前128與後128都寫入相同的數據),接著上面分析,而我們下面現象2時,我們將突發長度改為了4,就可以實現讀出來的數據是一個地址對應一個數據,這是為啥?因為,我們雖然突發長度為4,但是我們程序中地址依舊加的是8,所以結果就是地址加8,我們寫入4個地址的數據(讀也一樣),當然我們讀的時候就像抽取一樣,兩個裏抽一個(畢竟兩個數據是一樣的),那這樣雖然輸出的結果是一樣的,也是正確的,但是這樣就完了嗎?再接著想,這樣一來,我們就相當於浪費了一半的存儲空間!!!!!!你寫入了一半的廢物數據,這樣在實際中是不能容忍的!所以我們要做到的就是將128位數據挨個存儲,不要有重復,避免浪費存儲空間,雖然改突發長度可以得到正確結果,但是代價是顯然的!
前面我提了一下,出現重復數據是因為寫數據FIFO的讀使能存在問題,下面著重解決,首先看兩個圖,上圖是正確的軟仿結果,下圖是導致兩個重復數據的錯誤結果。

技術分享圖片

技術分享圖片

正確的讀使能應該一直為1,而下圖中讀使能呈脈沖式變化,在讀使能為0時就導致數據保持了上一周期的數據,這便是根本原因,既然分析出原因就要修改程序了。

技術分享圖片

上面中為使app_wdf_wren和wr_dfifo_ren同步特意進行添加,如此解決了連續兩個周期相同數據的問題。但是又出現問題了,給你張圖看下

技術分享圖片

按道理說寫到502就結束了,後面的哪裏來的呢?

還記得我之前說過讀數據的地址也是加到4000時結束讀操作,程序中寫的是數據每加一,地址加8,則默認的是8個地址對應一個數據,但是自己進行的是地址加8,對應寫入的是2個數據,所以,對於寫入數據來說,地址雖加到了4000多,但是實際中數據僅僅寫到前2000個地址,而讀數據時,卻讀出來的是4000個地址,但是只有前2000個地址數據是正確的,後面地址的數據還是保存的以前寫入的錯誤數據(相鄰兩個周期數據相同),所以會出現上面的情況,所以將讀地址改為原來的一半就可以了!

最後一個問題就是對於讀寫FIFO的時鐘和位寬最好匹配下,差距不要過大,當然這要取決與你的程序。

好啦,下面給你最一開始參數的仿真圖。

將用戶輸入輸出數據位寬256,寫入時鐘100M,app_wdf_data為128,突發長度為8,讀出的數據滿足要求,但是開頭存在些許問題,但其余無問題,下面為仿真結果,開頭數據存在些許問題,懶得調了,也就放在這了,數據往後打幾拍應該可以解決問題,嘿嘿

技術分享圖片

技術分享圖片

好啦,打字好累啦,希望這篇文章能對初學者有所幫助,也希望大神們能多多批評指正,先謝過了,大家可以互相交流,覺得有用,大家就點個贊!我也正在調試一些接口,如果效果好,題主還會繼續更新的,敬請期待!

DDR3調試總結