戰(zhàn))
簡介針對Xilinx Kintex-7平臺(tái)DDR3存儲(chǔ)調(diào)試需求這份工程基于Vivado 2020.2構(gòu)建了完整的MicroBlazeMIGUARTLite測試環(huán)境。工程已在XC7K325T上驗(yàn)證通過Vitis環(huán)境下使用memory tests工具執(zhí)行讀寫校驗(yàn)用戶僅需更換DDR3顆粒型號(hào)與引腳約束即可快速部署省去底層控制器搭建與配置時(shí)間。壓縮包共1364個(gè)文件整體僅2.67MB包含H、C、V/VHD等源碼文件XCI、XDC等IP配置與約束文件以及ELF等編譯產(chǎn)物目錄結(jié)構(gòu)清晰完整既能幫助理解MIG與MicroBlaze的互聯(lián)機(jī)制也可作為實(shí)際項(xiàng)目的基礎(chǔ)模板直接復(fù)用。資源已有775人學(xué)習(xí)適合中高級(jí)FPGA開發(fā)者、嵌入式工程師以及需要快速驗(yàn)證DDR3硬件設(shè)計(jì)的項(xiàng)目團(tuán)隊(duì)。借助這套工程可大幅縮短開發(fā)周期降低DDR3調(diào)試門檻。1. 這工程到底解決什么問題先把這個(gè)標(biāo)題拆開看Vivado 2020.2、MicroBlaze、MIG、UART Lite、DDR3。說白了就是用Xilinx的軟核處理器MicroBlaze通過MIGMemory Interface Generator這個(gè)IP核去讀寫DDR3顆粒再把測試結(jié)果通過UART Lite串口打印出來驗(yàn)證整條鏈路是否正常。不少剛接觸FPGA的朋友有個(gè)誤區(qū)覺得DDR3測試就得自己用Verilog寫一套讀寫控制器從初始化、刷新到Bank管理全都自己來。這個(gè)思路沒錯(cuò)但難度曲線特別陡而且一旦出錯(cuò)你根本分不清是時(shí)序問題還是邏輯問題。我自己最開始也是硬啃DDR3協(xié)議折騰了快兩周最后發(fā)現(xiàn)MIG IP核其實(shí)已經(jīng)幫你搞定了90%的復(fù)雜工作。用MicroBlaze加MIG這套方案核心優(yōu)勢在于你不需要懂DDR3的刷新時(shí)序、Bank切換、ODT配置這些底層細(xì)節(jié)只需要通過AXI總線像操作普通內(nèi)存一樣讀寫DDR3就行大大降低了驗(yàn)證門檻。這個(gè)工程適合誰兩類人一是剛?cè)腴TFPGA、想驗(yàn)證自己板子上DDR3顆粒是否焊接正常、硬件鏈路是否OK的朋友二是做嵌入式軟核開發(fā)需要在一個(gè)工程里同時(shí)搞定微處理器、DDR3存儲(chǔ)和串口調(diào)試三個(gè)模塊的開發(fā)者。20.2這個(gè)版本在MicroBlaze和MIG的兼容性上已經(jīng)相當(dāng)穩(wěn)定選它做測試工程沒什么坑。2. MIG IP核配置的關(guān)鍵參數(shù)2.1 先確認(rèn)硬件底子配置MIG之前必須搞清楚板子上DDR3顆粒的具體參數(shù)。不同開發(fā)板的DDR3配置差異很大常見的有鎂光MT41K256M164Gbit16位顆粒正點(diǎn)原子、黑金很多板子用這個(gè)三星K4B2G1646F2Gbit16位海力士H5TQ4G634Gbit我最常遇到的問題是很多人拿著MIG配置向?qū)枮槭裁礇]有自己板子的型號(hào)選項(xiàng)。這里說清楚MIG里的顆粒型號(hào)選擇只是參考重要的是容量、位寬、Bank數(shù)、地址位這些參數(shù)要匹配。以MT41K256M16為例它的容量是4Gbit512MB行地址15位、列地址10位、Bank 3位8個(gè)Bank按這個(gè)參數(shù)去選一個(gè)類似型號(hào)或者自定義都行。DDR3工作頻率也要看板子硬件。常見的有400MHzDDR3-800、533MHzDDR3-1066、667MHzDDR3-1333。我建議測試工程先保守一點(diǎn)選擇533MHz或者667MHz等鏈路驗(yàn)證穩(wěn)定了再往上提。用667MHz在Vivado里實(shí)際配置的時(shí)候MIG內(nèi)部會(huì)根據(jù)數(shù)據(jù)率計(jì)算物理層時(shí)鐘輸入時(shí)鐘一般給200MHz。2.2 MIG配置向?qū)е痦?xiàng)說明Controller Options部分頻率選擇根據(jù)顆粒規(guī)格選667MHz對應(yīng)DDR3-1333Burst Length固定8DDR3的突發(fā)長度就是8不用改數(shù)據(jù)位寬常見64位或者32位。64位性能好但占用管腳多32位配合16位顆粒正好是兩片。測試工程選32位或者64位無所謂看板子實(shí)際連接地址映射推薦選ROW_BANK_COL這是DDR3默認(rèn)的地址映射方式Memory Options部分顆粒密度、位寬按實(shí)際填寫一般會(huì)勾選“User Memory Address”選項(xiàng)自己定義地址位寬Pin Compatible如果用的是開發(fā)板廠商會(huì)提供MIG的PRJ文件直接Import比較穩(wěn)妥。我吃過虧手配置引腳對著原理圖一個(gè)個(gè)核容易眼花配錯(cuò)。用廠商給的官方例程文件最穩(wěn)。2.3 創(chuàng)建MIG IP時(shí)最該注意的坑這里說個(gè)典型的翻車點(diǎn)Vivado報(bào)MIG 66-99錯(cuò)誤。這個(gè)錯(cuò)誤基本都出現(xiàn)在引腳約束階段原因是你手工分配的引腳或者管腳約束文件和MIG內(nèi)部生成的不一致。解決思路是先跑一次Fail的Implementation在報(bào)告中找到MIG對管腳的具體要求然后再對照實(shí)際硬件做調(diào)整。還有一種情況是板子上DDR3數(shù)據(jù)總線的交換Byte Swap問題比如板子為了布線方便交換了DQS和DQ的對應(yīng)關(guān)系這種情況下你必須在MIG配置里選中對應(yīng)的引腳交換選項(xiàng)或者在XDC約束里做相應(yīng)映射不然校準(zhǔn)永遠(yuǎn)過不了。3. MicroBlaze子系統(tǒng)搭建與地址映射3.1 Block Design連線的心得接下來在Block Design里搭建系統(tǒng)。用Vivado自帶的IP Integrator添加以下IPMicroBlaze軟核處理器MIGDDR3控制器UART Lite串口Clocking Wizard時(shí)鐘管理AXI Interconnect總線互聯(lián)Processor System Reset復(fù)位管理第一次搭的時(shí)候容易忽略的點(diǎn)MicroBlaze的時(shí)鐘必須和MIG的用戶接口時(shí)鐘同步。MIG的UI時(shí)鐘頻率取決于DDR3工作頻率和AXI數(shù)據(jù)位寬。比如DDR3跑667MHz、數(shù)據(jù)位寬32位那么MIG UI時(shí)鐘就是667/2333MHz左右。MicroBlaze主頻建議和MIG UI時(shí)鐘保持一致或成倍數(shù)關(guān)系避免跨時(shí)鐘域?qū)е碌牟环€(wěn)定。我一般會(huì)加一個(gè)Clocking Wizard輸入板載時(shí)鐘比如200MHz差分或單端輸出兩路一路給MIG的system clock一般200MHz另一路給MicroBlaze和其他邏輯。3.2 地址映射別搞反在Block Design里點(diǎn)擊“Address Editor”你會(huì)看到各個(gè)AXI Slave的地址空間。這里要特別注意MIG映射的地址空間必須包含你打算訪問的DDR3容量。比如DDR3是512MB那么MIG從地址0x80000000開始的地址段必須覆蓋0x80000000到0x9FFFFFFF512MB。如果地址段只給了256MB而你后續(xù)讀寫操作超過了這個(gè)范圍就會(huì)出現(xiàn)總線錯(cuò)誤或者“死機(jī)”現(xiàn)象串口完全沒反應(yīng)。另外分享一個(gè)小技巧給MIG地址段起個(gè)有辨識(shí)度的名字比如DDR3_BASE后續(xù)在SDK里用這個(gè)宏定義方便很多。MicroBlaze自己的本地存儲(chǔ)器Local Memory我習(xí)慣用32KB夠放啟動(dòng)代碼就行。這個(gè)32KB其實(shí)非常關(guān)鍵因?yàn)镕SBLFirst Stage Boot Loader需要一段RAM來運(yùn)行在DDR3還沒初始化之前MicroBlaze必須有一段本地內(nèi)存來執(zhí)行代碼。3.3 管腳約束和時(shí)序約束MIG生成時(shí)會(huì)自動(dòng)帶上DDR3物理接口的管腳約束不需要你手動(dòng)寫。但系統(tǒng)時(shí)鐘、復(fù)位這些引腳要自己處理。單端200M時(shí)鐘的話建議用IBUFGDS或IBUF來緩沖系統(tǒng)復(fù)位要處理好異步復(fù)位、同步釋放的邏輯我習(xí)慣直接用Processor System Reset IP來生成各個(gè)時(shí)鐘域的復(fù)位信號(hào)省得自己寫同步器。4. 串口打印與DDR3讀寫測試邏輯4.1 SDK側(cè)工程的搭建思路Block Design生成比特流之后導(dǎo)出硬件配置File - Export Hardware記得勾選Include bitstream然后啟動(dòng)Vitis或SDK2020.2用的是Xilinx SDK基于Eclipse那套還沒改名Vitis。新建一個(gè)Application Project模板選擇Hello World這樣能最快驗(yàn)證MicroBlaze能跑起來、串口能輸出。跑通Hello World只是第一步。接下來要做的核心工作是驗(yàn)證DDR3讀寫正確性。我的做法是在main函數(shù)里定義一個(gè)大數(shù)組通過指針指向DDR3起始地址比如0x80000000然后執(zhí)行以下測試寫入遞增數(shù)據(jù)比如地址i寫入數(shù)值i寫入固定值后讀回比較寫入偽隨機(jī)序列后讀回比較4.2 讀寫測試代碼片段#include xil_printf.h #include xparameters.h #include sleep.h #define DDR3_BASE_ADDR 0x80000000 #define TEST_SIZE 32 * 1024 * 1024 // 32MB int ddr3_test(void) { volatile unsigned int *ddr (volatile unsigned int *)DDR3_BASE_ADDR; unsigned int i; unsigned int errors 0; // 測試1遞增寫入再讀回 for (i 0; i TEST_SIZE; i) { ddr[i] i; } for (i 0; i TEST_SIZE; i) { if (ddr[i] ! i) { xil_printf(DATA INCR: addr %08x, exp %08x, got %08x\r\n, (unsigned int)ddr[i], i, ddr[i]); errors; if (errors 10) return -1; } } if (errors 0) xil_printf(TEST1 (INCR WR/RD): PASS\r\n); // 測試2全地址寫0xA5A5A5A5并讀回 for (i 0; i TEST_SIZE; i) { ddr[i] 0xA5A5A5A5; } for (i 0; i TEST_SIZE; i) { if (ddr[i] ! 0xA5A5A5A5) { xil_printf(DATA FIXED: addr %08x, exp A5A5A5A5, got %08x\r\n, (unsigned int)ddr[i], ddr[i]); errors; if (errors 10) return -1; } } if (errors 0) xil_printf(TEST2 (FIXED WR/RD): PASS\r\n); return errors; } int main(void) { int ret; xil_printf(DDR3 Test Start!\r\n); ret ddr3_test(); if (ret 0) { xil_printf(DDR3 All Tests PASS!\r\n); } else { xil_printf(DDR3 Test FAILED, errors%d\r\n, ret); } return 0; }這個(gè)代碼看起來簡單但實(shí)際操作中有一個(gè)調(diào)試心得32MB的測試范圍涵蓋了DDR3的多個(gè)Bank和Row能比較好地暴露地址線和Bank選擇上的錯(cuò)誤。如果只是測試幾個(gè)地址有些地址線接反的問題根本測不出來。比如A0和A1接反了只讀寫0x000000和0x000004兩個(gè)地址根本發(fā)現(xiàn)不了但遍歷大范圍地址就能暴露出來。4.3 串口波特率的設(shè)置細(xì)節(jié)UART Lite的配置在Block Design里就定下來了通常設(shè)為115200。SDK里xil_printf默認(rèn)走UART Lite的驅(qū)動(dòng)只要硬件上波特率一致就能輸出。我很早之前栽過一個(gè)跟頭板子上的UART芯片是USB轉(zhuǎn)串口默認(rèn)時(shí)鐘是12MHz而UART Lite IP默認(rèn)參考時(shí)鐘是系統(tǒng)時(shí)鐘比如100MHz兩者不匹配導(dǎo)致串口輸出亂碼。這里提供了一個(gè)排查方向先看板子原理圖確認(rèn)UART芯片的時(shí)鐘來源如果是獨(dú)立晶振且和FPGA系統(tǒng)時(shí)鐘不同就要在Block Design里給UART Lite單獨(dú)配置一個(gè)時(shí)鐘。很多開發(fā)板為了省成本UART芯片直接掛一個(gè)12MHz晶振但UART Lite的時(shí)鐘輸入是FPGA內(nèi)部邏輯時(shí)鐘需要在Clocking Wizard里給UART Lite生成一個(gè)獨(dú)立的時(shí)鐘域或者在硬件設(shè)計(jì)時(shí)直接用同一個(gè)時(shí)鐘自己注意匹配。5. 實(shí)測踩坑實(shí)錄與排查技巧5.1 常見問題速查表現(xiàn)象可能原因排查方法串口無輸出MicroBlaze本地內(nèi)存太小/FSBL跑飛檢查Local Memory大小增大到64KB試一下串口亂碼波特率不匹配/時(shí)鐘不同源確認(rèn)UART Lite時(shí)鐘頻率與波特率配置DDR3測試卡死地址范圍超出映射檢查Address Editor中MIG地址段大小calibration失敗MIG引腳約束與硬件不一致對照原理圖檢查引腳分配檢查Byte Swap數(shù)據(jù)位錯(cuò)亂數(shù)據(jù)線交換未配置在MIG中設(shè)置引腳交換或調(diào)整XDC映射程序燒寫后不運(yùn)行沒有正確生成Bootloop檢查FSBL是否編譯、連接是否正確5.2 最值得看的兩個(gè)真實(shí)案例案例一MIG calibration一直失敗。現(xiàn)象是Vivado里生成比特流正常但上板后程序停在MIG初始化階段串口輸出發(fā)現(xiàn)卡在DDR3初始化。查了一整天最后用ILA集成邏輯分析儀抓MIG的calib_done信號(hào)發(fā)現(xiàn)一直拉低。后來對比原理圖發(fā)現(xiàn)板子的DDR3復(fù)位引腳是低有效但MIG配置里默認(rèn)輸出高有效復(fù)位在MIG選項(xiàng)中調(diào)整復(fù)位極性后問題解決。案例二小地址測試通過大地址測試失敗。這個(gè)案例很典型32MB測試?yán)镌缙趲讉€(gè)MB沒問題但跑到后面就報(bào)錯(cuò)。我懷疑是地址線高位的問題比如A12以上有接反或虛焊。用萬用表測了地址線連通性發(fā)現(xiàn)有一根地址線中間斷裂重新焊接后恢復(fù)正常。有時(shí)候大范圍測試的意義就在于此能夠在更廣的地址空間里暴露硬件問題。5.3 排查技巧總結(jié)不要一上來就全速跑大范圍測試先用小范圍比如1KB驗(yàn)證基本通路錯(cuò)誤信息里的地址非常關(guān)鍵把報(bào)錯(cuò)地址換算成二進(jìn)制對比DDR3的Row/Column地址位可以快速定位是哪根地址線出問題Bootloop不可少FSBL跑完把控制權(quán)交給應(yīng)用程序之前先讓MicroBlaze訪問DDR3做個(gè)自檢自檢通過再繼續(xù)這能避免很多莫名其妙的后續(xù)問題保持復(fù)位時(shí)序正確上電后要給DDR3一段穩(wěn)定時(shí)間MIG里Vivado會(huì)自動(dòng)處理但MicroBlaze復(fù)位釋放時(shí)間要晚于DDR3初始化完成可以通過Processor System Reset的dcm_locked信號(hào)串聯(lián)實(shí)現(xiàn)6. 后續(xù)可以怎么擴(kuò)展這套工程驗(yàn)證通過之后你的DDR3鏈路就算打通了。接著可以考慮這幾個(gè)方向跑一下Xilinx官方的MIG Example Design看看帶Traffic Generator的完整測試是怎么寫的可以驗(yàn)證更復(fù)雜的讀寫模式把MicroBlaze換成硬核ARM比如Zynq系列DDR3控制器是PS端自帶的和MIG略有不同但地址映射、測試思路是相通的加一個(gè)DMA控制器比如AXI DMA讓DDR3數(shù)據(jù)在內(nèi)存和外設(shè)之間搬運(yùn)可以看到實(shí)際帶寬表現(xiàn)做固化方案把FSBL和應(yīng)用代碼固化到QSPI Flash里掉電重啟自動(dòng)加載在這些擴(kuò)展里我最推薦先把MIG的Example Design跑一遍。Xilinx自帶的Traffic Generator會(huì)生成更加復(fù)雜的讀寫序列包括Bank跳躍、隨機(jī)地址訪問比我們自己寫的遞增測試嚴(yán)格得多。只要Traffic Generator能跑到100%完成DDR3的物理鏈路就基本沒有問題了。7. 一點(diǎn)個(gè)人經(jīng)驗(yàn)做DDR3測試工程很多次了今天分享的這套MicroBlazeMIGUART方案最大的價(jià)值就在“省心”和“可控”這兩個(gè)字上。省心在于底層復(fù)雜的DDR3時(shí)序全交給MIG你不需要懂那么多協(xié)議細(xì)節(jié)可控在于MicroBlaze的軟件調(diào)試特別直接出問題可以快速縮小范圍判斷是硬件還是軟件原因。在實(shí)際操作中還有一個(gè)建議不要把問題都堆到最后一次性解決最好分階段驗(yàn)證。每完成一個(gè)步驟就確認(rèn)一下比如MIG生成后先看綜合報(bào)告有沒有錯(cuò)誤再上板跑MicroBlaze搭好后先只跑Hello World確認(rèn)環(huán)境通了再加載DDR3測試。這樣一步步來就算出問題你也很清楚問題出在哪一步。最后再提醒一次上面代碼里測試范圍我寫了32MB實(shí)際可以根據(jù)你的DDR3容量調(diào)整。如果是512MB的內(nèi)存你可以先測32MB再逐步擴(kuò)展到64MB、128MB直到覆蓋整個(gè)空間。跑大范圍測試的時(shí)候注意看串口輸出幾百兆的測試跑下來可能要幾分鐘別以為卡死了。這里再分享一個(gè)小細(xì)節(jié)測試代碼里我打印了實(shí)際出錯(cuò)地址和數(shù)據(jù)這個(gè)日志信息要保留好排查硬件問題時(shí)非常有用特別是地址線虛焊、引腳短路這些硬件故障基本靠日志就能定位。本文還有配套的精品資源點(diǎn)擊獲取