有了前面的一堆鋪墊?,F(xiàn)在終于開始正式準(zhǔn)備讀寫DDR了,開發(fā)環(huán)境:VIVADO2014.2 + SDK。
一、首先要想在PL端通過AXI去控制DDR,我們必須要有一個AXI master,由于是測試,就不自己寫了,直接用package IP生成,方法如下: 1.選擇package IP工具 2.創(chuàng)建新的AXI外設(shè) 3.接口類型選擇Full,模式選擇master,如果你不關(guān)心里面的詳細(xì)實(shí)現(xiàn)過程,那么直接finish就好了。(后面我們會繼續(xù)分析里面的過程)
二、創(chuàng)建好了IP,自然要加入到IP庫里,如圖,在IP Catalog空白處右鍵,設(shè)置,把剛剛生成IP的路徑放進(jìn)去:
三、接下來創(chuàng)建BD塊,把整個硬件系統(tǒng)搭建好: 需要指出的是,由于我們需要用到HP,所以在zynq的配置里面把HP勾選上,任選一個通道就行
四、然后校驗(yàn)正確性,產(chǎn)生輸出文件,創(chuàng)建BD塊頂層,這都是套路,一路走下來就行。如果你想在調(diào)試?yán)锟吹疆a(chǎn)生的AXI信號,那么需要對AXI標(biāo)記一下debug
五、綜合,set up debug,然后生成比特流,并將其導(dǎo)入到SDK;在SDK里跑個hello world 就行,主要目的是用CPU去把DDR控制器初始化。
到這里整個過程基本就結(jié)束了,接下來看仿真波形: 放大一點(diǎn),可以看到每次地址的步進(jìn)長度是十進(jìn)制的64,這是因?yàn)槲覀兊耐话l(fā)長度設(shè)置的是16,位寬為32bit。 但是問題來了,我們在上一節(jié)里面說過,有一部分地址是連到了OCM的,那么這一部分地址是多少呢?UG585里給出了如下說明: 我們是從全0地址開始寫數(shù)據(jù)的,然而全0的地址剛好分配到了OCM,這TM就很尷尬了。一開始想讓程序運(yùn)行的時間長一點(diǎn),這樣地址是不是就可以跑到0x0008_0000了?然而并沒有什么用,因?yàn)榈刂分慌艿?0001000就停止了,如圖: 還記得前面打包AXI IP時候我們說過要分析其過程嗎?其實(shí)那里就已經(jīng)挖了一個坑了,具體見代碼: 這是AXI的寫數(shù)據(jù)狀態(tài)機(jī),(可以看到,官方也是用一段式狀態(tài)機(jī)來實(shí)現(xiàn)整個時序的,印證了前面三段式狀態(tài)機(jī)不好實(shí)現(xiàn)的說法),從寫狀態(tài)到讀狀態(tài)的跳變是由writes_done信號來控制的,那么這個writes_done又是怎么產(chǎn)生的呢?繼續(xù)看代碼: writes_done是由write_burst_counter的高位進(jìn)位來控制的,再繼續(xù)找write_burst_counter: 在這個計數(shù)器里有一個很關(guān)鍵的位C_NO_BURSTS_REQ ,在代碼的低179行,它的定義如下: localparam integer C_NO_BURSTS_REQ = C_MASTER_LENGTH-clogb2((C_M_AXI_BURST_LEN*C_M_AXI_DATA_WIDTH/8)-1); C_M_AXI_BURST_LEN我們設(shè)置的是16,C_M_AXI_DATA_WIDTH是32,clogb2可以理解為計算以2為底的某個數(shù)的對數(shù),那么最后得到的C_NO_BURSTS_REQ = 6;也就是說write_burst_counter的位寬是7為,當(dāng)最高位為1時,寫數(shù)據(jù)停止。也就是只會發(fā)生64次寫數(shù)據(jù),之后計數(shù)器和寫地址就會歸零。那么64次寫數(shù)據(jù)乘以每次突發(fā)長度16再乘以位寬4個字節(jié),最后得到的數(shù)值是4096,換算成16進(jìn)制剛好是0x00001000。
|
|