PCIE_DMA實例四:xapp1052在Xilinx 7系列(KC705/VC709)FPGA上的移植

PCIE_DMA實例四:xapp1052在Xilinx 7系列(KC705/VC709)FPGA上的移植

一:前言

這段時間有個朋友加微信請求幫忙調試一塊PCIe採集卡。該採集卡使用xilinx xc7k410t做控制器,上位機爲XP系統,原有的驅動和測試軟件都是基於xapp1052寫的。衆所周知,Xilinx升級到7系列後,原來的pcie ip核trn接口統統轉換成了axis接口,這可愁壞了之前用xapp1052的朋友,一下子不好用了,如何把xapp1052移植到K7系列FPGA上,貌似很有市場。博主本着利人利己的原則,翻出了三五年前玩剩的xapp1052,稍加改動,完成了一版能在K7上使用的BMD工程。另外針對專門做採集卡的朋友,博主提供了一個由FIFO作爲用戶接口的BMD工程。

二:前期準備

1、pcie基礎還是要有,尤其是協議部分。推薦一本電子書,很經典,請耐心讀它(Addison.Wesley.PCI.Express.System.Architecture.eBook-LiB.chm)下載地址:http://download.csdn.net/download/yuzeren48/7723815

2、pg054

3、Vivado2018.2套件

4、Windriver

5、Visual studio 2010

三:移植步驟

1、在vivado中創建一個K7 pcie ipcore的example工程。

2、在xilinx官網下載xapp1052.pdf與xapp1052.zip

3、將1和2兩個工程的代碼融合並稍作修改,形成BMD工程,可選擇64位寬(4x 2.5G )或128位寬(4x 5G),代碼層級如下:

4,關鍵代碼分析

1)、BMD_EP_MEM-Control/Status Registers 所有的用戶狀態寄存器在模塊BMD_EP_MEM中。我們一切的DMA傳輸首先是要控制這 些寄存器,然後進行DMA傳輸,傳輸完成後在讀取狀態寄存器的值獲取傳輸狀態。

2)、EP_RX_ENGINE-Target 這個模塊的功能在EP_RX_ENGINE裏面實現,負責接收讀寫TLP命令,並且提交完成讀 寫內存的完成響應。EP_RX_ENGINE裏面,Target接收PC發過來的32bit不帶數據的存儲 器讀請求和帶1個DW字的32bit 存儲器寫請求。控制狀態寄存器就是通過Target讀寫。

3)、EP_RX_ENGINE-Rx引擎 Rx引擎除了負責接PC讀寫存儲器請求,也要完成開發板發出的讀內存請求的完成響應 (DMA傳輸)。

4)、BMD_EP_MEM-Tx引擎 Tx引擎除了負責接發送DMA數據到PC,也要發送PC發送的讀寫TLP包的完成響應。

5)、BMD_EP_MEM-Control/Status Registers 所有的用戶狀態寄存器在模塊BMD_EP_MEM中。我們一切的DMA傳輸首先是要控制這 些寄存器,然後進行DMA傳輸,傳輸完成後在讀取狀態寄存器的值獲取傳輸狀態。

6)、Interface 總線接口,pcie-app_7x就是包含了BMD所有的總線接口。

7)、AXI4-Stream轉BMD協議接口 axi_trn_rx模塊和axi_trn_tx實現了最新的AXI4-Stream協議轉BMD協議。有讀者可能 會懷疑轉換的協議可能影響傳輸效率,實際上不會有任何效率的犧牲,因爲這裏是FPGA直 接完成了協議的轉換,沒有任何的延遲。

筆者對關鍵邏輯部分代碼做了非常詳細的註釋,讀者可在文末根據需求自行購買。

5,上位機軟件代碼分析

裝好windriver後,我們可以在windriver安裝目錄下找到BMD工程對應的驅動文件

使用VS2010打開後,文件目錄如下,如需獲取每個C文件中函數的功能定義,請在文末購買相應資料。

運行該測試程序,並打開VIVADO工程抓包,看上去是V5的測試代碼,但可以通過輸入VendorID和DeviceID來找到我們自己的板卡。

 

在4x GEN1(2.5G)的情況下,做連續讀寫測試,實測PCIe寫帶寬約爲840MB/s,PCIe讀帶寬約爲761MB/s,基本上接近滿帶寬了。

四、工程化範例

以上工程就是xapp1052在K7上的移植測試,但對於做工程應用的朋友來說,這個工程並不實用,所有DMA讀寫的數據都是根據我們用戶自己配置的一個patten寄存器固定死的,如果要把FIFO中的數據通過xapp1052 DMA傳輸到系統內存,則需要修改部分源代碼。這裏,博主有償爲大家提供了一個FIFO接口的BMD工程。

用戶接口如下:

module  pcie_app_7x#(
   parameter C_DATA_WIDTH = 64,            // RX/TX interface data width
   // Do not override parameters below this line 
   parameter KEEP_WIDTH = C_DATA_WIDTH / 8  ,             // TKEEP width
   parameter REM_WIDTH  = (C_DATA_WIDTH == 128) ? 2 : 1 // trem/rrem width
    
)(

  input                         user_clk,
  input                         user_reset,
  input                         user_lnk_up, 

  // Tx
  input  [5:0]                  tx_buf_av,
  input                         tx_cfg_req,
  input                         tx_err_drop,
  output                        tx_cfg_gnt,

  input                         s_axis_tx_tready,
  output  [C_DATA_WIDTH-1:0]    s_axis_tx_tdata,
  output  [KEEP_WIDTH-1:0]      s_axis_tx_tkeep,
  output  [3:0]                 s_axis_tx_tuser,
  output                        s_axis_tx_tlast,
  output                        s_axis_tx_tvalid, 
  
  // Rx
  output                        rx_np_ok,
  output                        rx_np_req,
  input  [C_DATA_WIDTH-1:0]     m_axis_rx_tdata,
  input  [KEEP_WIDTH-1:0]       m_axis_rx_tkeep,
  input                         m_axis_rx_tlast,
  input                         m_axis_rx_tvalid,
  output                        m_axis_rx_tready,
  input    [21:0]               m_axis_rx_tuser,

  // Flow Control
  input  [11:0]                 fc_cpld,
  input  [7:0]                  fc_cplh,
  input  [11:0]                 fc_npd,
  input  [7:0]                  fc_nph,
  input  [11:0]                 fc_pd,
  input  [7:0]                  fc_ph,
  output [2:0]                  fc_sel,  


  // CFG
  input  [31:0]                 cfg_do,
  input                         cfg_rd_wr_done,
  output [31:0]                 cfg_di,
  output [3:0]                  cfg_byte_en,
  output [9:0]                  cfg_dwaddr,
  output                        cfg_wr_en,
  output                        cfg_rd_en,

  output                        cfg_err_cor,
  output                        cfg_err_ur,
  output                        cfg_err_ecrc,
  output                        cfg_err_cpl_timeout,
  output                        cfg_err_cpl_abort,
  output                        cfg_err_cpl_unexpect,
  output                        cfg_err_posted,
  output                        cfg_err_locked,
  output [47:0]                 cfg_err_tlp_cpl_header,
  input                         cfg_err_cpl_rdy,
  output                        cfg_interrupt,
  input                         cfg_interrupt_rdy,
  output                        cfg_interrupt_assert,
  output [7:0]                  cfg_interrupt_di,
  input  [7:0]                  cfg_interrupt_do,
  input  [2:0]                  cfg_interrupt_mmenable,
  input                         cfg_interrupt_msienable,
  input                         cfg_interrupt_msixenable,
  input                         cfg_interrupt_msixfm,
  output                        cfg_turnoff_ok,
  input                         cfg_to_turnoff,
  output                        cfg_trn_pending,
  output                        cfg_pm_wake,
  input   [7:0]                 cfg_bus_number,
  input   [4:0]                 cfg_device_number,
  input   [2:0]                 cfg_function_number,
  input  [15:0]                 cfg_status,
  input  [15:0]                 cfg_command,
  input  [15:0]                 cfg_dstatus,
  input  [15:0]                 cfg_dcommand,
  input  [15:0]                 cfg_lstatus,
  input  [15:0]                 cfg_lcommand,
  input  [15:0]                 cfg_dcommand2,
  input   [2:0]                 cfg_pcie_link_state,

  output [1:0]                  pl_directed_link_change,
  input  [5:0]                  pl_ltssm_state,
  output [1:0]                  pl_directed_link_width,
  output                        pl_directed_link_speed,
  output                        pl_directed_link_auton,
  output                        pl_upstream_prefer_deemph,
  input  [1:0]                  pl_sel_link_width,
  input                         pl_sel_link_rate,
  input                         pl_link_gen2_capable,
  input                         pl_link_partner_gen2_supported,
  input  [2:0]                  pl_initial_link_width,
  input                         pl_link_upcfg_capable,
  input  [1:0]                  pl_lane_reversal_mode,
  input                         pl_received_hot_rst,

  output [63:0]                 cfg_dsn,
//user port
  output [63:0]                 RX_FIFO_DATA_o,
  output                        RX_FIFO_WR_o,
  input  [63:0]                 TX_FIFO_DATA_i,
  output                        TX_FIFO_RD_o, 
  output [7:0]                  pcie_tap
)

 

這個接口可以直接連在xilinx的PCIe IP核接口上,用戶接口對於做數據採集卡的朋友非常友好。這裏做一個利用XAPP1052 通過FIFO採集數據的例子。爲了驗證數據的方便,我們在開發板上通過一個計數器計數,把計數的值發送到上位機上。測試結果如下:

另外需要補充一點,這個工程在DMA寫數據,也就是FPGA寫數據到PC的時候,沒有任何問題。但是在DMA讀數據的時候,也就是FPGA從PC端讀大量數據的時候,會出現返回的數據包亂序的現象。這是xapp1052的通病,對於做採集卡的朋友,這個問題並無影響,因爲不需要從PC端讀數據。如果有朋友需要讀寫都正確無誤的PCIe DMA工程,可單獨聯繫我,本人有全套PCIe DMA源代碼,可用於各種系列的FPGA,但源碼價格不菲哦。

五、附件

1、xapp1052 K7移植工程,附硬件代碼註釋和windows驅動說明(200元一份)

2、xapp1052 K7移植工程(FIFO接口),附硬件代碼註釋和windows驅動說明以及測試程序(500元一份)

3、支持XILINX全系列的多通道PCIe DMA IP核(價格詳談) 

有需要請微信(330853172)聯繫

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章