軟件版本:vitis2020.2(vivado2020.2)
操作系統:WIN10 64bit
硬件平台:適用XILINX A7/K7/Z7/ZU/KU系列FPGA(米聯客(milianke)MZU07A-EG硬件開發平台)
登錄"米聯客"FPGA社區-www.uisrc.com視頻課程、答疑解惑!
10.1概述
FDMA是米聯客的基於AXI4總線協議定制的一個DMA控制器。有了這個IP我們可以統一實現用FPGA代碼直接讀寫PL的DDR或者PS的DDR。本文中FDMA的IP是開源的,在配套FPGA工程的uisrc/ip路徑下可以找到源碼。本文的IP已經利用VIVADO做了圖形化的封裝,所以可以直接通過圖形化連線設計,使用非常方便。
本文實驗目的:
1:利用米聯客自定一定FDMA2.0/3.0版本搭建SOC工程(最新發布的版本是3.0)
2:編寫FPGA測試代碼實現,PL寫入數據到PS DDR然后再讀出PS DDR中的數據,對比是否正確。
為了讓PS的DDR可以運行,必須新建一個vitis-sdk工程,這個工程主要是為了初始化PS DDR,我們可以簡單新建一個自帶的hello工程。
10.2搭建SOC系統工程
新建一個名為為zu_prj的工程,之后創建一個BD文件,並命名為system,添加並且配置好ZYNQ Ultrascale+ MPSOC IP。讀者需要根據自己的硬件類型配置好輸入時鍾頻率、內存型號、串口,連接時鍾等。新手不清楚這些內容個,請參考"3-2-01_ex_soc_base_07a-eg .pdf" "01 HelloWold/DDR/網口測試"這篇文章。
10.2.1PS部分設置
1:PS復位設置
2:PS AXI HP0 FPD設置
3:PL輸出時鍾設置
10.2.2添加自定義IP
1:設置IP路徑
本文中是我們第一次在BD圖形化設計中添加自定義的IP,自定義的IP需要設置IP路徑才能被識別到。默認情況下,我們自定的IP在配套工程的uisrc/ip路徑下:
2:添加IP
10.2.3PL圖像化編程
10.2.4添加FPGA FDMA讀寫代碼
上圖中源碼在配套fpga工程的uisrc/rtl路徑中,本文中我們修改了默認的system_wrapper.v文件名為system_wrapper_fdma.v這樣的好處是對默認文件和手動修改過的文件加以區分,以免幸苦修改的代碼一不小心,被軟件自動更新替換掉。
關鍵的代碼為fdma_test.v。在這個程序中,寫入一定數據到DDR中,然后再讀出,對比是否有錯誤,幾個關鍵參數:
TEST_MEM_SIZE:定義了測試內從空間的大小,以byte為單位,是整數倍的FDMA_BURST_LEN *(fdma_wdata/8)。
FDMA_BURST_LEN:定義每次FDMA傳輸的長度,這個長度是整數倍的fdma_wdata或者fdma_rdata。
ADDR_MEM_OFFSET:代碼了內從訪問的起始地址。
`timescale 1ns / 1ns /* Company : Liyang Milian Electronic Technology Co., Ltd. Brand: 米聯客(milianke) Technical forum:uisrc.com taobao: https://milianke.taobao.com https://osrc.taobao.com jd:https://milianke.jd.com Create Date: 2019/12/17 Module Name: fdma_test Description: Copyright: Copyright (c) milianke Revision: 1.0 Signal description: 1) _i input 2) _o output 3) _n activ lowpai 4) _dg debug signal 5) _r delay or register 6) _s state mechine */ //////////////////////////////////////////////////////////////////////////////////
module fdma_test# ( parameter TEST_MEM_SIZE = 32'd40960, parameter FDMA_BURST_LEN = 16'd1024, parameter ADDR_MEM_OFFSET = 1024*1024*500 ) ( input ui_clk, input fdma_rstn, output [31: 0] fdma_waddr, output reg fdma_wareq, output [15: 0] fdma_wsize, input fdma_wbusy, output reg [127:0] fdma_wdata, input fdma_wvalid, output reg fdma_wready,
output [31: 0] fdma_raddr, output reg fdma_rareq, output [15: 0] fdma_rsize, input fdma_rbusy, input [127:0] fdma_rdata, input fdma_rvalid, output reg fdma_rready ); parameter WRITE1 = 0; parameter WRITE2 = 1; parameter READ1 = 2; parameter READ2 = 3;
reg [31: 0] fdma_waddr_r; reg [16 :0] fdma_rcnt = 0; reg [2 :0] T_S = 0;
assign fdma_waddr = fdma_waddr_r + ADDR_MEM_OFFSET; assign fdma_raddr = fdma_waddr;
assign fdma_wsize = FDMA_BURST_LEN; assign fdma_rsize = FDMA_BURST_LEN;
reg [10:0] rst_cnt = 0;
always @(posedge ui_clk) if(fdma_rstn == 1'b0)begin rst_cnt <=0; end else begin if(rst_cnt[10] == 1'b0) rst_cnt <= rst_cnt + 1'b1; else rst_cnt <= rst_cnt; end
always @(posedge ui_clk)begin if(rst_cnt[10] == 1'b0)begin T_S <=0; fdma_wareq <= 1'b0; fdma_rareq <= 1'b0; fdma_wready <= 1'b0; fdma_rready <= 1'b0; fdma_wdata <=0; fdma_waddr_r <=0; end else begin case(T_S) WRITE1:begin if(fdma_waddr_r>TEST_MEM_SIZE) fdma_waddr_r<=0; if(!fdma_wbusy)begin fdma_wareq <= 1'b1; fdma_wready <= 1; fdma_wdata <= 0; end if(fdma_wareq&&fdma_wbusy)begin fdma_wareq <= 1'b0; T_S <= WRITE2; end end WRITE2:begin if(!fdma_wbusy) begin T_S <= READ1; fdma_wready <= 0; fdma_wdata <= 32'd0; end else if(fdma_wvalid) begin fdma_wdata <= fdma_wdata + 1'b1; end end
READ1:begin if(!fdma_rbusy)begin fdma_rareq <= 1'b1; fdma_rready <= 1; fdma_rcnt <= 0; end if(fdma_rareq&&fdma_rbusy)begin fdma_rareq <= 1'b0; T_S <= READ2; end end READ2:begin if(!fdma_rbusy) begin T_S <= WRITE1; fdma_rready <= 0; fdma_rcnt <= 32'd0; fdma_waddr_r <= fdma_waddr_r + FDMA_BURST_LEN*128/8; end else if(fdma_rvalid) begin fdma_rcnt <= fdma_rcnt + 1'b1; end end default: T_S <= WRITE1; endcase end end
wire test_error = ((fdma_rready&&fdma_rvalid) && (fdma_rcnt[15:0] != fdma_rdata[15:0]));
ila_0 ila_dbg ( .clk(ui_clk), .probe0({fdma_waddr[15:0],fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wready,fdma_wbusy}), .probe1({fdma_rdata[15:0],fdma_rcnt[15:0],fdma_rvalid,fdma_rready,fdma_rbusy,T_S,test_error}) );
endmodule |
10.2.5設置地址分配
10.2.6編譯並導出平台文件
1:單擊Block文件à右鍵àGenerate the Output ProductsàGlobalàGenerate。
2:單擊Block文件à右鍵à Create a HDL wrapper(生成HDL頂層文件)àLet vivado manager wrapper and auto-update(自動更新)。
3:生成Bit文件。
4:導出到硬件: FileàExport HardwareàInclude bitstream
5:導出完成后,對應工程路徑的zu_hw路徑下有硬件平台文件:system_wrapper.xsa的文件。根據硬件平台文件system_wrapper.xsa來創建需要Platform平台。
10.3搭建Vitis-sdk工程
創建zu_base sdk platform和APP工程的過程不再重復,可以閱讀本章節01~05相關demo。以下給出創建好zu_base sdk platform的截圖和對應工程APP的截圖。
10.3.1創建SDK Platform工程
10.3.2創建hello APP工程
10.4實驗結果
1:先運行hello app
2:打開設備
3:如果沒有出來下圖的hw_ila 波形窗口,右擊刷新
4:觀察在線邏輯分析結果
5:寫入過程
6:讀出過程
