PGL50H FPGA PCIe開(kāi)發(fā)實(shí)戰(zhàn):從IP配置到Windows識(shí)別)
1. 這塊板子和PCIe方案到底適合做什么先說(shuō)清楚一個(gè)很多人容易誤解的點(diǎn)紫光同創(chuàng)PGL50H并不是一顆主打PCIe功能的FPGA它的定位更偏中低容量的國(guó)產(chǎn)FPGA平臺(tái)但PGL50H內(nèi)部集成了一路硬核PCIe控制器支持Endpoint模式速率最高可達(dá)PCIe 2.0 x45GT/s per lane。這意味著在不需要太高帶寬的工業(yè)控制、數(shù)據(jù)采集、視頻傳輸、科研教學(xué)場(chǎng)景下完全可以用它來(lái)做一套完整的PCIe通信系統(tǒng)而不必一上來(lái)就上高端型號(hào)。我從實(shí)際項(xiàng)目經(jīng)驗(yàn)來(lái)看最適合用這套方案的人群主要有三類(lèi)高校和研究所的FPGA學(xué)習(xí)者想系統(tǒng)性地走通PCIe協(xié)議棧的枚舉、配置空間、中斷、DMA傳輸?shù)植幌胗肰ivado那套成熟得過(guò)于自動(dòng)化的流程紫光同創(chuàng)的PDS工具鏈能逼你把每個(gè)環(huán)節(jié)搞清楚。做國(guó)產(chǎn)化替代的工程師項(xiàng)目要求必須用國(guó)產(chǎn)FPGA平臺(tái)實(shí)現(xiàn)標(biāo)準(zhǔn)PCIe接口PGL50H是少數(shù)在性?xún)r(jià)比上能打的型號(hào)。做自定義數(shù)據(jù)采集卡的硬件開(kāi)發(fā)者需要把ADC、傳感器數(shù)據(jù)通過(guò)PCIe總線高速上送主機(jī)但帶寬需求不超過(guò)2GB/s的場(chǎng)景。這套方案的典型通路總結(jié)下來(lái)是這樣的FPGA作為PCIe Endpoint設(shè)備插到主板的PCIe插槽上通過(guò)硬核控制器完成鏈路訓(xùn)練主機(jī)側(cè)枚舉出未知設(shè)備后加載驅(qū)動(dòng)最終在設(shè)備管理器里看到完整識(shí)別信息然后開(kāi)始正式的數(shù)據(jù)傳輸。我要把這條鏈路從零開(kāi)始完整走一遍包括IP核安裝這種最容易卡住新手的環(huán)節(jié)。2. 開(kāi)發(fā)環(huán)境準(zhǔn)備PDS軟件和License的一個(gè)大坑2.1 PDS版本選擇與安裝紫光同創(chuàng)的FPGA開(kāi)發(fā)軟件叫PDSPango Design Suite在開(kāi)始PCIe開(kāi)發(fā)前先要把這個(gè)平臺(tái)裝好。官網(wǎng)下載頁(yè)面目前提供多個(gè)版本我建議直接選較新的2021.2及以上版本因?yàn)镻CIe IP核在早期版本里存在一些已修復(fù)的Bug比如鏈路訓(xùn)練不穩(wěn)定、中斷引腳映射錯(cuò)誤等問(wèn)題。安裝過(guò)程不多講Windows下直接一路Next。但有一點(diǎn)必須提醒安裝路徑千萬(wàn)不要帶中文和空格這個(gè)工具鏈對(duì)路徑敏感之前有人裝在D:\軟件\PDS下結(jié)果綜合時(shí)報(bào)出一堆莫名其妙的路徑錯(cuò)誤。建議統(tǒng)一放C:\PDS這種純英文路徑。2.2 License配置的隱藏細(xì)節(jié)這部分是新手最容易卡住的地方。紫光同創(chuàng)的License分兩種一種是評(píng)估License一般通過(guò)代理或官方申請(qǐng)有時(shí)效限制另一種是綁定機(jī)器碼的正式License。拿到License文件后不是隨便找個(gè)地方放就行。打開(kāi)PDS軟件菜單欄找到License配置工具一般在開(kāi)始菜單的Pango Design Suite目錄下選擇指定License文件然后瀏覽到你存放License的路徑。這里有個(gè)關(guān)鍵點(diǎn)License文件的路徑也不能有中文而且建議放在PDS安裝目錄以外的固定位置比如C:\Licenses\pango_license.dat避免之后重裝軟件時(shí)被覆蓋。驗(yàn)證License是否生效的方法打開(kāi)PDS新建工程后在IP核倉(cāng)庫(kù)IP Catalog里搜索PCIe如果能看到PCIe IP核并且可以雙擊打開(kāi)配置界面說(shuō)明License正常。如果看不到或者提示License不支持回到License配置步驟重新檢查也可以運(yùn)行安裝目錄下的license_check工具查看具體報(bào)錯(cuò)。我遇到過(guò)一次比較坑的情況License明明正常但PCIe IP核仍顯示灰色不可用查了半天發(fā)現(xiàn)是PDS版本和License不匹配舊License只支持到2020.1版本換新版本后必須同步更新License。所以版本升級(jí)之前一定先確認(rèn)License支持范圍。2.3 檢查硬核資源PGL50H的PCIe硬核在Device視圖里可以確認(rèn)。打開(kāi)PDS新建一個(gè)空工程選擇PGL50H-6FBG484或者你板卡對(duì)應(yīng)的具體封裝在Device Overview里能看到芯片資源表格。PCIe硬核在資源列表里會(huì)以PCIe Hard IP或類(lèi)似條目標(biāo)識(shí)確認(rèn)存在后再進(jìn)行后續(xù)開(kāi)發(fā)。如果用的是更小規(guī)模的PGL25G或者更老的型號(hào)很可能沒(méi)有PCIe硬核那就得用軟核方案工程復(fù)雜度會(huì)上升一個(gè)數(shù)量級(jí)不在本教程范圍內(nèi)。3. PCIe IP核的生成與配置每個(gè)參數(shù)背后的原理3.1 IP核創(chuàng)建流程在PDS中創(chuàng)建PCIe IP核的路徑是IP Catalog - Interfaces - PCIe。雙擊打開(kāi)后會(huì)進(jìn)入IP配置界面。這個(gè)界面分幾個(gè)Tab下面逐個(gè)拆解。General配置項(xiàng)Component Name給IP核命名比如pcie_ep_0名字后面會(huì)作為生成文件的前綴。模式選擇Endpoint端點(diǎn)是設(shè)備端Root Complex是主機(jī)端。我們做開(kāi)發(fā)板插主機(jī)必須選Endpoint。這里特別解釋一下為什么是EndpointPCIe體系結(jié)構(gòu)是樹(shù)形的主機(jī)CPU和南橋芯片組屬于Root Complex根復(fù)合體掛在它下面的是各種Endpoint設(shè)備顯卡、網(wǎng)卡、SSD。RC負(fù)責(zé)枚舉和管理總線EP是被動(dòng)響應(yīng)的一方。PGL50H的硬核只支持Endpoint模式這決定了我們用它做的是被主機(jī)識(shí)別和控制的設(shè)備而不是控制其他設(shè)備的主機(jī)。Lane配置Lane寬度可選x1、x2、x4。PGL50H硬核最高支持x4板卡上實(shí)際走線能支持多少取決于硬件設(shè)計(jì)金手指或PCIe插槽的連接方式。如果板卡是x4的金手指直接選x4。如果板卡只是x1的插槽或走線也要選x1否則鏈路訓(xùn)練會(huì)失敗。速率可選2.5GT/sGen1和5GT/sGen2。建議初期開(kāi)發(fā)先用Gen1鏈路訓(xùn)練成功率更高排查問(wèn)題也更容易。后面穩(wěn)定后可以切Gen2測(cè)速。Reference Clock配置參考時(shí)鐘頻率100MHz是PCIe規(guī)范定的沒(méi)得選但需要指定時(shí)鐘源。一般開(kāi)發(fā)板會(huì)從PCIe插槽的REFCLK引腳引入主機(jī)側(cè)的100MHz時(shí)鐘在IP配置里選擇External或From Board并指定對(duì)應(yīng)的時(shí)鐘引腳。BAR空間配置 這是重點(diǎn)直接關(guān)系到主機(jī)怎么訪問(wèn)FPGA的寄存器空間。BARBase Address Register是PCIe設(shè)備向主機(jī)聲明自己資源范圍的寄存器。我們要做數(shù)據(jù)通信一般開(kāi)兩個(gè)BARBAR0作為控制寄存器空間大小設(shè)為4KB就夠了用來(lái)放狀態(tài)寄存器、控制寄存器、中斷控制位。映射方式選Memory內(nèi)存映射因?yàn)镮O空間在現(xiàn)代系統(tǒng)中已經(jīng)很少使用且效率低。BAR1作為數(shù)據(jù)緩沖區(qū)空間大小可以設(shè)到1MB或更大用于DMA傳輸時(shí)的緩沖區(qū)映射。同樣選Memory映射。中斷配置PCIe支持三種中斷機(jī)制Legacy INTx、MSIMessage Signaled Interrupt、MSI-X。強(qiáng)烈建議用MSI因?yàn)镮NTx在共享中斷時(shí)容易出問(wèn)題而MSI是直接寫(xiě)消息到主機(jī)內(nèi)存效率高且不占用共享中斷線。PGL50H硬核支持MSI在配置里可以設(shè)MSI的Capability結(jié)構(gòu)和中斷消息數(shù)量。前期調(diào)試建議先設(shè)1個(gè)中斷向量MSI Capability里的Multiple Message Enable設(shè)為1即可簡(jiǎn)化邏輯。3.2 生成IP核后的關(guān)鍵文件配置完成后點(diǎn)擊GeneratePDS會(huì)生成一組文件。你要重點(diǎn)關(guān)注這幾個(gè)頂層例化模板通常以_top.v結(jié)尾官方給的例化參考里面有IP核的端口定義和連接示例。IP核的仿真模型用于前仿真驗(yàn)證。IP核的用戶(hù)指南PDF這個(gè)一定要看里面是寄存器描述和接口時(shí)序比任何教程都詳細(xì)。4. 硬件設(shè)計(jì)檢查清單耦合電容和阻抗控制要命標(biāo)題里的熱搜詞提到了pcie耦合電容擺放位置說(shuō)明這是很多人栽過(guò)跟頭的地方。在我開(kāi)始寫(xiě)邏輯之前先花點(diǎn)篇幅把這里的硬件要點(diǎn)講透。4.1 AC耦合電容的基本要求PCIe協(xié)議規(guī)定每個(gè)發(fā)送端的差分信號(hào)線上必須串聯(lián)AC耦合電容電容值規(guī)范要求在75nF到200nF之間常用值是100nF。這個(gè)電容的作用是隔直流通交流讓鏈路雙方的共模電壓可以不同而不互相影響。擺放位置按照PCIe規(guī)范AC耦合電容要放在發(fā)送端一側(cè)且距離發(fā)送端封裝引腳最好在500mil以?xún)?nèi)一般設(shè)計(jì)上控制在0.1到0.5英寸之間。如果走線較長(zhǎng)電容的位置需要做阻抗補(bǔ)償通常是補(bǔ)線否則會(huì)造成阻抗不連續(xù)點(diǎn)影響信號(hào)完整性。對(duì)于PGL50H開(kāi)發(fā)板這種成品板耦合電容在出廠時(shí)已經(jīng)由板廠設(shè)計(jì)好了一般不需要你處理。但如果你是自己畫(huà)板子注意發(fā)送端的每一對(duì)差分線上都要放電容接收端可以不放。別兩邊都放兩邊都放會(huì)導(dǎo)致等效電容減半且引入兩個(gè)阻抗不連續(xù)點(diǎn)。4.2 差分阻抗控制PCIe Gen1/Gen2的差分阻抗要求是85歐姆±10%注意不是100歐姆很多新手按千兆網(wǎng)口習(xí)慣了100歐姆這里容易錯(cuò)。對(duì)于PGL50H的引腳扇出和PCB走線建議走線寬度、間距根據(jù)疊層計(jì)算表層微帶線參考地去層走線盡量短且等長(zhǎng)。熱搜詞里還有一個(gè)pcie的發(fā)送差分對(duì)間需不需要等長(zhǎng)——需要的。PCIe規(guī)范對(duì)差分對(duì)內(nèi)等長(zhǎng)要求非常嚴(yán)格Gen2速率下對(duì)內(nèi)偏差要控制在5mil以?xún)?nèi)對(duì)間等長(zhǎng)相對(duì)寬松但整體偏差最好控制在100mil內(nèi)因?yàn)榻邮斩擞袕椥跃彌_Elastic Buffer來(lái)處理跨時(shí)鐘域問(wèn)題但處理不了極端的skew。4.3 參考時(shí)鐘的走線檢查100MHz參考時(shí)鐘通常是從PCIe插槽引過(guò)來(lái)直接連到FPGA專(zhuān)用REFCLK引腳。檢查一下板卡的原理圖確認(rèn)REFCLK對(duì)有沒(méi)有做AC耦合有些板卡會(huì)在時(shí)鐘源與FPGA之間加電容有沒(méi)有串聯(lián)端接電阻。參考時(shí)鐘質(zhì)量差會(huì)直接導(dǎo)致鏈路訓(xùn)練失敗現(xiàn)象是設(shè)備管理器里根本看不到未知設(shè)備。5. 邏輯設(shè)計(jì)與關(guān)鍵接口時(shí)序5.1 最小可識(shí)別系統(tǒng)需要哪些邏輯要讓W(xué)indows設(shè)備管理器識(shí)別到設(shè)備FPGA內(nèi)部邏輯需要完成以下幾件事硬核PCIe初始化上電后硬核會(huì)自動(dòng)與主機(jī)RC進(jìn)行鏈路訓(xùn)練不需要用戶(hù)邏輯參與。配置空間應(yīng)答硬核已經(jīng)內(nèi)置了配置空間包括Vendor ID、Device ID、BAR、MSI Capability等。我們只需要在IP配置時(shí)傳入正確的ID參數(shù)。用戶(hù)邏輯訪問(wèn)BAR空間主機(jī)枚舉設(shè)備時(shí)會(huì)讀取配置空間來(lái)分配資源但如果后續(xù)主機(jī)要往BAR0寫(xiě)數(shù)據(jù)或讀狀態(tài)FPGA用戶(hù)邏輯必須響應(yīng)這些訪問(wèn)否則驅(qū)動(dòng)加載后會(huì)卡死。所以最小系統(tǒng)的用戶(hù)邏輯至少包含對(duì)BAR0空間的讀寫(xiě)應(yīng)答邏輯用一個(gè)簡(jiǎn)單的Register File即可。狀態(tài)寄存器比如一個(gè)固定值0xDEADBEEF讓驅(qū)動(dòng)能讀回并判斷設(shè)備是否正常工作。一個(gè)可寫(xiě)的控制寄存器讓驅(qū)動(dòng)能寫(xiě)值進(jìn)來(lái)。5.2 例化IP核與連接AXI接口PGL50H的PCIe硬核對(duì)外接口是AXI4或AXI4-Stream。大部分開(kāi)發(fā)場(chǎng)景建議選AXI4接口因?yàn)樗歇?dú)立的地址讀寫(xiě)通道適合做寄存器訪問(wèn)和DMA緩沖區(qū)訪問(wèn)。IP配置時(shí)可以選AXI4 Memory Mapped模式。IP核生成后的端口大致分幾組系統(tǒng)接口復(fù)位、時(shí)鐘、鏈路狀態(tài)指示。PCIe物理接口TX差分對(duì)、RX差分對(duì)、REFCLK。AXI接口讀地址通道、讀數(shù)據(jù)通道、寫(xiě)地址通道、寫(xiě)數(shù)據(jù)通道、寫(xiě)響應(yīng)通道。頂層邏輯要做的事就是把系統(tǒng)接口處理好復(fù)位同步、時(shí)鐘連接把AXI接口接到你的寄存器文件或FIFO上。鏈路狀態(tài)信號(hào)如link_up要引出來(lái)觀察調(diào)試時(shí)用LED或邏輯分析儀看能快速判斷鏈路是否訓(xùn)練成功。5.3 最簡(jiǎn)單的寄存器讀寫(xiě)邏輯以AXI4接口為例BAR0空間對(duì)應(yīng)一片地址映射。硬核會(huì)把主機(jī)發(fā)往BAR0地址的AXI事務(wù)轉(zhuǎn)換成AXI接口上的讀寫(xiě)請(qǐng)求。寄存器文件核心邏輯就是解析AXI地址并根據(jù)地址返回對(duì)應(yīng)寄存器的值。一個(gè)注意事項(xiàng)AXI接口的讀寫(xiě)時(shí)鐘是250MHzGen2 x4模式下而你自己的用戶(hù)邏輯可能工作在較低頻率兩個(gè)時(shí)鐘域之間的數(shù)據(jù)傳遞要處理好。最簡(jiǎn)單的辦法是把寄存器文件直接跑在AXI時(shí)鐘域避免跨時(shí)鐘域問(wèn)題。// 偽代碼寄存器文件 always (posedge axi_aclk or negedge axi_aresetn) begin if (!axi_aresetn) begin reg_status 32hDEADBEEF; reg_control 32h0; end else begin // 寫(xiě)通道處理 if (axi_awvalid axi_wvalid axi_wready) begin if (axi_awaddr[15:0] 16h0000) reg_control axi_wdata; end // 讀通道處理 if (axi_arvalid axi_arready) begin case (axi_araddr[15:0]) 16h0000: axi_rdata reg_control; 16h0004: axi_rdata reg_status; default: axi_rdata 32h0; endcase end end end這里踩過(guò)的一個(gè)坑是AXI的握手時(shí)序arready不能一直拉高必須和arvalid同步拉高一拍并保證arready是依賴(lài)狀態(tài)機(jī)的否則如果arvalid在高電平期間arready抖動(dòng)容易造成事務(wù)處理錯(cuò)亂。最穩(wěn)妥的做法是參考官方例化模板里的狀態(tài)機(jī)。5.4 時(shí)鐘復(fù)位處理PCIe硬核對(duì)復(fù)位時(shí)序有嚴(yán)格要求。IP核會(huì)輸出一個(gè)user_reset信號(hào)在鏈路訓(xùn)練完成后釋放用戶(hù)邏輯應(yīng)該用這個(gè)信號(hào)做全局復(fù)位而不是直接用外部按鍵復(fù)位或者上電復(fù)位。原因很簡(jiǎn)單如果鏈路還沒(méi)訓(xùn)練好你就開(kāi)始操作AXI接口事務(wù)大概率失敗。6. 綜合、布局布線到生成燒寫(xiě)文件6.1 約束文件的編寫(xiě)要點(diǎn)PCIe設(shè)計(jì)的時(shí)序約束里最關(guān)鍵的是兩個(gè)輸入時(shí)鐘約束REFCLK 100MHz要?jiǎng)?chuàng)建時(shí)鐘約束。輸出延遲約束PCIe接口是源同步接口IP核內(nèi)部已經(jīng)做了處理和時(shí)序例外通常不需要用戶(hù)額外約束但有時(shí)需要設(shè)置set_false_path跳過(guò)一些無(wú)關(guān)緊要的時(shí)序路徑。PDS的約束文件格式是SDC。一個(gè)最小約束示例create_clock -period 10.000 -name refclk [get_ports refclk_p]注意PCIe差分時(shí)鐘有正負(fù)兩端約束時(shí)通常只約束P端作為時(shí)鐘源。6.2 綜合參數(shù)的一個(gè)建議PDS的綜合策略里有幾個(gè)預(yù)設(shè)等級(jí)。PCIe工程建議選Performance性能優(yōu)先這會(huì)讓工具花更多時(shí)間在時(shí)序優(yōu)化上對(duì)高頻的AXI接口有好處。如果選了Area面積優(yōu)先有時(shí)會(huì)導(dǎo)致PCIe硬核周?chē)壿嫴季志o張出現(xiàn)時(shí)序違例。6.3 燒寫(xiě)方式bit文件與固化文件的區(qū)別PCIe工程的燒寫(xiě)方式有講究調(diào)試階段用JTAG下載bit文件到SRAM掉電丟失但下載快適合反復(fù)修改。固化階段生成.svf或.bin文件燒寫(xiě)到SPI Flash上電自動(dòng)加載。注意固化完成后要讓FPGA先加載配置再讓主機(jī)加電或復(fù)位PCIe鏈路順序反了可能導(dǎo)致鏈路訓(xùn)練時(shí)FPGA還沒(méi)起來(lái)。生成燒寫(xiě)文件時(shí)在PDS的工程菜單里選擇Generate Bitstream完成后在Output目錄下能找到bit文件如果做固化鏡像需要額外添加一個(gè)SPI Flash控制器IP或使用PDS的固化工具生成.mcs文件。7. 上板調(diào)試從鏈路訓(xùn)練到Windows識(shí)別7.1 上電后的第一件事看燈板子上如果有PCIe鏈路狀態(tài)指示燈很多開(kāi)發(fā)板把link_up信號(hào)引到了LED上電插進(jìn)主機(jī)PCIe插槽后開(kāi)機(jī)時(shí)觀察燈的狀態(tài)燈亮鏈路訓(xùn)練完成物理層已經(jīng)通。燈閃或不亮檢查參考時(shí)鐘、復(fù)位、配置引腳。如果沒(méi)有LED指示可以用JTAG連接PDS的ChipScope紫光同創(chuàng)的邏輯分析儀工具抓內(nèi)部信號(hào)看link_up信號(hào)的真值。7.2 Windows設(shè)備管理器的初次識(shí)別這里有個(gè)很多人不知道的知識(shí)點(diǎn)Windows對(duì)PCIe設(shè)備識(shí)別是即插即用的不需要進(jìn)操作系統(tǒng)前就看得到。上電開(kāi)機(jī)后BIOS/UEFI會(huì)做PCIe枚舉然后Windows繼續(xù)枚舉和分配資源。如果你的設(shè)備配置空間是正確的開(kāi)機(jī)進(jìn)入系統(tǒng)后打開(kāi)設(shè)備管理器應(yīng)該能在其他設(shè)備下看到一個(gè)新的未知設(shè)備顯示PCI Device或未知設(shè)備。如果整個(gè)設(shè)備管理器里完全沒(méi)有任何新設(shè)備出現(xiàn)排查順序是確認(rèn)板卡插好了金手指完全嵌入插槽。確認(rèn)REFCLK時(shí)鐘有沒(méi)有用示波器量FPGA的REFCLK引腳。確認(rèn)FPGA是否成功配置bit文件是否燒寫(xiě)成功指示燈是否正常。檢查硬核是否因?yàn)榕渲缅e(cuò)誤而一直處在Detect狀態(tài)。7.3 驅(qū)動(dòng)安裝完成識(shí)別最后一步Windows識(shí)別到未知設(shè)備后需要安裝驅(qū)動(dòng)才能看到設(shè)備管理器里正常的設(shè)備名。這里給兩種方案方案一使用WinDriver或類(lèi)似工具生成通用驅(qū)動(dòng)WinDriver可以自動(dòng)識(shí)別未知PCIe設(shè)備并生成一個(gè)基本的驅(qū)動(dòng)框架適合前期驗(yàn)證和調(diào)試。它會(huì)把Vendor ID和Device ID讀出來(lái)然后你分配一個(gè)驅(qū)動(dòng)綁定。方案二寫(xiě)一個(gè)最簡(jiǎn)單的WDF/KMDF驅(qū)動(dòng)如果做產(chǎn)品最終肯定要寫(xiě)正式驅(qū)動(dòng)。前期快速驗(yàn)證的話可以用Windows SDK里的示例代碼改一個(gè)最小驅(qū)動(dòng)主要做三件事在DriverEntry里設(shè)置AddDevice回調(diào)。在AddDevice里創(chuàng)建設(shè)備對(duì)象。根據(jù)設(shè)備的Vendor ID/Device ID判斷是否為我們的設(shè)備。一個(gè)用于快速驗(yàn)證的.inf文件關(guān)鍵部分如下[Version] Signature $WINDOWS NT$ Class System ClassGuid {4d36e97d-e325-11ce-bfc1-08002be10318} Provider %ProviderName% [Manufacturer] %ProviderName% DeviceList,NTamd64 [DeviceList.NTamd64] %DeviceDesc% PCIE_Device_Install, PCI\VEN_1D29DEV_4000 [PCIE_Device_Install] Include wdmsec.inf Needs wdmsec.inf里面VEN_1D29是紫光同創(chuàng)的Vendor ID不同批次或定制版本也可能是其他值DEV_4000是你在IP核配置里填的Device ID。這兩個(gè)ID必須和IP核配置的一致否則驅(qū)動(dòng)裝不上。右鍵未知設(shè)備 - 更新驅(qū)動(dòng)程序 - 手動(dòng)選擇.inf文件安裝成功后設(shè)備管理器里就會(huì)出現(xiàn)帶名字的設(shè)備條目比如PGL50H PCIe Device。7.4 快速驗(yàn)證讀寫(xiě)是否正常識(shí)別成功只是第一步還要驗(yàn)證數(shù)據(jù)通路。最直觀的方法是用一個(gè)簡(jiǎn)單的上位機(jī)工具比如使用PCITree或自寫(xiě)的WinDriver應(yīng)用往BAR0的0x0004地址讀數(shù)據(jù)應(yīng)該能讀到0xDEADBEEF往0x0000地址寫(xiě)一個(gè)值再讀回來(lái)驗(yàn)證一致性。這一步如果通過(guò)整套PCIe通路就已經(jīng)通了后面做DMA、中斷、大數(shù)據(jù)傳輸都是在已驗(yàn)證的通道上加功能。8. 從識(shí)別成功到穩(wěn)定傳輸要跨越的三個(gè)坎8.1 中斷MSI配置不當(dāng)導(dǎo)致設(shè)備報(bào)錯(cuò)很多人在中斷上卡殼。MSI的中斷消息是由硬核根據(jù)配置空間自動(dòng)生成的用戶(hù)邏輯只需要在IP核配置時(shí)設(shè)置MSI Capability寄存器然后在有事件時(shí)發(fā)出中斷請(qǐng)求。常見(jiàn)問(wèn)題MSI Enable位沒(méi)有置1驅(qū)動(dòng)或BIOS需要負(fù)責(zé)在配置空間把MSI Enable位寫(xiě)1。如果驅(qū)動(dòng)沒(méi)做這個(gè)操作設(shè)備發(fā)不出MSI中斷。調(diào)試時(shí)用ChipScope觀察硬核的中斷相關(guān)信號(hào)。中斷向量數(shù)量不匹配如果IP配置時(shí)設(shè)置了多個(gè)中斷向量但驅(qū)動(dòng)只申請(qǐng)了一個(gè)會(huì)導(dǎo)致中斷消息被主機(jī)忽略。8.2 DMA最大帶寬瓶頸在用戶(hù)邏輯PCIe Gen2 x4的理論帶寬是2GB/s單向?qū)嶋H上扣除協(xié)議開(kāi)銷(xiāo)實(shí)測(cè)能到1.2~1.5GB/s就很不錯(cuò)了。但很多人發(fā)現(xiàn)實(shí)際DMA速率遠(yuǎn)低于預(yù)期問(wèn)題往往不在PCIe本身而在用戶(hù)邏輯的數(shù)據(jù)源不夠快。比如如果你用一個(gè)低頻FIFO往AXI接口灌數(shù)據(jù)DMA自然跑不起來(lái)。要達(dá)到高帶寬數(shù)據(jù)路徑要設(shè)計(jì)好AXI數(shù)據(jù)寬度選128位硬核支持的最大值。突發(fā)長(zhǎng)度Burst Length要充分利用盡量一次發(fā)256字節(jié)的burst減少AXI握手開(kāi)銷(xiāo)。源數(shù)據(jù)用異步FIFO緩沖保證AXI時(shí)鐘域下數(shù)據(jù)不間斷。8.3 熱插拔和喚醒國(guó)產(chǎn)平臺(tái)的一個(gè)軟肋PCIe規(guī)范支持熱插拔和電源管理喚醒但國(guó)產(chǎn)FPGA的硬核在這方面的驗(yàn)證相對(duì)少。在實(shí)際產(chǎn)品里建議默認(rèn)關(guān)閉熱插拔特性要求用戶(hù)斷電插拔以免出現(xiàn)設(shè)備掛了但代碼沒(méi)問(wèn)題的情況。9. 排錯(cuò)手冊(cè)鏈路訓(xùn)練失敗的全套排查鏈路最后專(zhuān)門(mén)寫(xiě)一整套排查鏈路這也是我實(shí)際調(diào)試中總結(jié)出的經(jīng)驗(yàn)順序。遇到設(shè)備管理器不識(shí)別時(shí)按下述順序查效率最高。第一步確認(rèn)FPGA配置是否完成用JTAG連接在PDS里查看下載狀態(tài)。如果bit文件沒(méi)有正常下載注意上電后FPGA可能被主機(jī)復(fù)位邏輯提前喚醒導(dǎo)致配置失敗重新下載后拔插一次板卡或重啟主機(jī)。有些主板會(huì)在啟動(dòng)早期復(fù)位PCIe總線如果你的FPGA配置時(shí)間較長(zhǎng)可能錯(cuò)過(guò)第一次鏈路訓(xùn)練窗口此時(shí)主機(jī)重啟或關(guān)閉再開(kāi)啟就能識(shí)別。第二步檢查鏈路狀態(tài)寄存器用ChipScope抓link_up信號(hào)。如果link_up為0鏈路訓(xùn)練沒(méi)有完成。需要回頭查物理層信號(hào)和參考時(shí)鐘。第三步檢查REFCLK示波器量FPGA的REFCLK輸入引腳正常應(yīng)該看到100MHz、擺幅滿(mǎn)足要求的時(shí)鐘波形一般是差分LVDS或LVPECL電平。時(shí)鐘幅度偏小會(huì)直接導(dǎo)致鏈路訓(xùn)練失敗。第四步檢查硬核狀態(tài)輸出IP核有狀態(tài)輸出信號(hào)如ltssm_state鏈路訓(xùn)練狀態(tài)機(jī)的當(dāng)前狀態(tài)正常最終停在L0態(tài)。如果停在Polling.Active或Configuration.LanenumWait等狀態(tài)說(shuō)明對(duì)端主機(jī)沒(méi)有正確響應(yīng)這時(shí)查主板的PCIe插槽是否正常換個(gè)插槽試試。第五步檢查設(shè)備ID和驅(qū)動(dòng)匹配如果設(shè)備管理器中出現(xiàn)了未知設(shè)備但驅(qū)動(dòng)裝不上基本不是鏈路問(wèn)題而是.inf里Vendor ID和Device ID沒(méi)對(duì)上或者設(shè)備實(shí)例ID路徑格式錯(cuò)誤。重新確認(rèn)ID值。剛開(kāi)始做PCIe調(diào)試我建議你先在PCIe Gen1 x1模式下把所有通路跑通再切換到高配置因?yàn)殒溌匪俾试礁邔?duì)信號(hào)質(zhì)量的要求就越苛刻問(wèn)題排查的復(fù)雜度也成倍上升。10. 后續(xù)可以擴(kuò)展的三個(gè)方向整套流程走通后可以考慮在現(xiàn)有基礎(chǔ)上做下面幾個(gè)擴(kuò)展都基于同一套硬核和框架高速數(shù)據(jù)采集系統(tǒng)把ADC采樣數(shù)據(jù)通過(guò)AXI-Stream接口直接注入PCIe DMA通道實(shí)現(xiàn)連續(xù)采數(shù)上送主機(jī)。多通道DMA引擎在硬核的AXI接口上加DMA控制器實(shí)現(xiàn)多個(gè)描述符鏈批量搬移大塊數(shù)據(jù)。多板卡協(xié)同多塊PGL50H板卡插在同一主機(jī)上區(qū)分不同設(shè)備的實(shí)例枚舉用同一個(gè)驅(qū)動(dòng)管理多個(gè)設(shè)備實(shí)例。我個(gè)人在實(shí)際調(diào)試中體會(huì)最深的一點(diǎn)是PCIe調(diào)試的本質(zhì)不是調(diào)FPGA而是建立一個(gè)信號(hào)-時(shí)序-軟件配置三者聯(lián)動(dòng)的排錯(cuò)思維。同樣的報(bào)錯(cuò)現(xiàn)象可能來(lái)自PCB信號(hào)問(wèn)題也可能來(lái)自IP配置參數(shù)錯(cuò)誤還可能來(lái)自驅(qū)動(dòng)沒(méi)寫(xiě)對(duì)。每改一步都建議只動(dòng)一個(gè)變量否則問(wèn)題交織在一起時(shí)很難準(zhǔn)確定位。遇到卡殼時(shí)多做一次從物理層到應(yīng)用層的狀態(tài)確認(rèn)往往比盲目嘗試配置參數(shù)更有效。