01使用fdma讀寫axi-bram(AXI4 FDMA數據緩存篇)


軟件版本:vitis2019.2(vivado2019.2)

操作系統:WIN10 64bit

硬件平台:適用XILINX A7/K7/Z7/ZU/KU系列FPGA(本文使用米聯客(milianke))MK7160FA開發板

登錄"米聯客"FPGA社區-www.uisrc.com視頻課程、答疑解惑!

1.1概述    

FDMA是米聯客的基於AXI4總線協議定制的一個DMA控制器。有了這個IP我們可以統一實現用FPGA代碼直接讀寫PL的DDR或者ZYNQ/ZYNQMP SOC PS的DDR或者BRAM。FDMA IP CORE 已經廣泛應用於ZYNQ SOC/Artix7/Kintex7 FPGA,同樣適用於ultrascale/ultrascale+系列FPGA/SOC。

如果用過ZYNQ/ZYNQMP的都知道,要直接操作PS的DDR 通常是DMA 或者VDMA,然而用過XILINX 的DMA IP 和VDMA IP,總有一種遺憾,那就是不夠靈活,還需要對寄存器配置,真是麻煩。XILINX 的總線接口是AXI4總線,自定義AXI4 IP掛到總線上就能實現對內存地址空間的讀寫訪問。因此,我們只要掌握AXI4協議就能完成不管是PS還是PL DDR的讀寫操作。

米聯客封裝的AXI4總線協議命名位uiFDMA,自動2018年第一版本發布后,就引起了很多FPGA工程師的興趣,並且得到了廣大FPGA工程師的好評,但是FDMA1.0版本還是有一些局限和BUG,再實際的應用中被FPGA工程師發現,因此給了我們很多寶貴意見。借此2021版本教程更新發布之際,我們也對FDMA1.0版本升級到FDMA3.0版本。

uiFDMA3.0新增特性:

1:支持多個FDMA IP同時掛帶AXI-interconnect總線,同時工作

2:支持自動計算AXI-Burst長度,使用起來非常簡單,只需要給出需要burst的長度。

從本文開始,我們從多個應用方案來演示FDMA的用途。

 

本文實驗目的:

1:掌握基於uiFDMA3.0的FPGA工程設計

2:利用uiFDMA3.0提供的接口,編寫BRAM測試程序

3:對AXI-BRAM讀寫仿真和測試

 

我們第一入門的demo選擇對BRAM仿真測試,是因為不管是仿真還是編譯測試,對AXI-BRAM速度都非常快,我們在下面一個DEMO中會給出對DDR的讀寫仿真測試。

1.2硬件接線

1.3搭建FPGA圖形化工程

1.3.1創建工程命名為fpga_prj

雙擊VIVADO軟件圖標啟動VIVADO

設置工程路徑,並且命名工程名為fpga_prj

以下設置FPGA或者ZYNQ或者ZYNQ-MPSOC芯片型號,必須和開發板保持一致,如果不清楚的請查閱自己開發板的硬件手冊或者根據選型手冊上參數確認

 

1.3.2創建Block Design並且命名為system

如下圖所示,圖形化system就是一個代碼容器,接着我們要添加一些圖像化的IP

 

1.3.3添加圖形化FPGA IP

首先設置自定義IP的路徑,這里讀者可以把我們配套工程根路徑下的uisrc文件夾復制到目前的工程根路徑,單擊Settings在彈出的Settings窗口選擇IP->Repository 設置如下路徑

添加+號添加IP

比如輸入關鍵詞FDMA就可以搜索到我們米聯客uiFDMA IP

用類似的方法添加必要的IP如下圖所示:

 

1.3.4完成IP之間的信號自動

這種簡單的工程可以先讓軟件先自動化線,然后根據結果手動一些調整

可以看到連線結果

1.3.5調整IP參數

1:BRAM參數設置

首先把IP的配置參數修改下,雙擊需要設置的IP可以進行參數設置

FDMA設置數據位寬128bit 可以訪問內存地址位寬16bit(BRAM大小有限這里設置64KB)

BRAM設置,使用BRAM Controller 為真雙口RAM

2:BRAM Controller參數設置

AXI BRAM Controller設置axi4協議,數據位寬128bit 讀延遲1個時鍾

3:Clocking Wizard參數設置

4:AXI Interconnect IP設置

雙擊AXI Interconnect IP 進行設置

設置AXI Interconnect IP的性能參數,其中Enable Register Slice 用於改善時序,Enable Data FIFO用於增加FIFO大小,增加數據傳輸效率

1.3.6引出FPGA接口信號

分別右擊下圖uiFDMA IP,然后選擇Make External,把需要引出到頂層的FPGA信號引出

 

為了引出時鍾需先右擊信號PIN腳斷開連接,然后Make External,之后重新連接

 

右擊pin腳,彈出菜單選擇Make External

修改后重新連接時鍾

1.3.7修改信號名字

默認的時鍾名字不是很好,可以自己修改下

修改完成如下

1.3.8最后的優化

我們知道之類外部復位可以優化掉不使用,接到clk_wiz_0時鍾的locked腳

1.3.9視圖優化

右擊空白處,彈出菜單選擇Regenerate Layout優化下視圖

1.3.10地址分配

 

AXI總線必須分配地址,設置uiFDMA的地址空間分配,起始地址可以任意設置,我們設置從0x0000_0000開始,大小64KB

1.3.11自動校驗

保存工程

單擊下圖中的控件可以對圖形化編程進行校驗

1.3.12自動產生頂層文件

右擊system,在彈出的菜單中選擇Create HDL Wrapper

1.4編寫FDMA的BRAM測試代碼

剛剛以上自動產生的頂層文件,只是引出的信號接口,並不能完成對FDMA的控制,所以我們需要自定義一個頂層文件,可以復制剛才產生的文件,修改,這樣可以省一些編寫調用接口的時間。

為了方便文件的管理,我們新建一個fdma_bram_test.v文件,並且復制以上代碼,到這個文件夾。

右擊刪除剛剛自動產生的文件

添加fdma_bram_test.v文件

fdma_bram_test.v文件

 

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////

/*

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: 2021/04/25

Module Name: fdma_bram_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_bram_test(

input sysclk_p

);

 

wire [31:0] fdma_raddr;

reg fdma_rareq;

wire fdma_rbusy;

wire [127:0] fdma_rdata;

wire [15:0] fdma_rsize;

wire fdma_rvalid;

wire [31:0] fdma_waddr;

reg fdma_wareq;

wire fdma_wbusy;

wire [127:0] fdma_wdata;

wire [15:0] fdma_wsize;

wire fdma_wvalid;

wire [0:0] fdma_rstn;

wire ui_clk;

 

parameter TEST_MEM_SIZE = 32'd64*1024;//64KB

parameter FDMA_BURST_LEN = 16'd512;

parameter ADDR_MEM_OFFSET = 0;

parameter ADDR_INC = FDMA_BURST_LEN * 16;

 

parameter WRITE1 = 0;

parameter WRITE2 = 1;

parameter WAIT = 2;

parameter READ1 = 3;

parameter READ2 = 4;

 

reg [31: 0] t_data;

reg [31: 0] fdma_waddr_r;

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;

assign fdma_wdata ={t_data,t_data,t_data,t_data};

 

 

//delay reset

reg [8:0] rst_cnt = 0;

always @(posedge ui_clk)

if(rst_cnt[8] == 1'b0)

rst_cnt <= rst_cnt + 1'b1;

else

rst_cnt <= rst_cnt;

 

always @(posedge ui_clk)begin

if(rst_cnt[8] == 1'b0)begin

T_S <=0;

fdma_wareq <= 1'b0;

fdma_rareq <= 1'b0;

t_data<=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;

t_data <= 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 <= WAIT;

t_data <= 32'd0;

end

else if(fdma_wvalid) begin

t_data <= t_data + 1'b1;

end

end

WAIT:begin//not needed

T_S <= READ1;

end

READ1:begin

if(!fdma_rbusy)begin

fdma_rareq <= 1'b1;

t_data <= 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;

t_data <= 32'd0;

fdma_waddr_r <= fdma_waddr_r + ADDR_INC;//128/8=16

end

else if(fdma_rvalid) begin

t_data <= t_data + 1'b1;

end

end

default:

T_S <= WRITE1;

endcase

end

end

 

wire test_error = (fdma_rvalid && (t_data[15:0] != fdma_rdata[15:0]));

 

ila_0 ila_dbg (

    .clk(ui_clk),

    .probe0({fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wbusy}),

    .probe1({fdma_rdata[15:0],t_data[15:0],fdma_rvalid,fdma_rbusy,T_S,test_error})

);

 

system system_i

(.FDMA_S_0_fdma_raddr(fdma_raddr),

.FDMA_S_0_fdma_rareq(fdma_rareq),

.FDMA_S_0_fdma_rbusy(fdma_rbusy),

.FDMA_S_0_fdma_rdata(fdma_rdata),

.FDMA_S_0_fdma_rready(1'b1),

.FDMA_S_0_fdma_rsize(fdma_rsize),

.FDMA_S_0_fdma_rvalid(fdma_rvalid),

.FDMA_S_0_fdma_waddr(fdma_waddr),

.FDMA_S_0_fdma_wareq(fdma_wareq),

.FDMA_S_0_fdma_wbusy(fdma_wbusy),

.FDMA_S_0_fdma_wdata(fdma_wdata),

.FDMA_S_0_fdma_wready(1'b1),

.FDMA_S_0_fdma_wsize(fdma_wsize),

.FDMA_S_0_fdma_wvalid(fdma_wvalid),

.sysclk(sysclk_p),

.ui_clk(ui_clk)

);

 

endmodule

1.5RTL仿真

1.5.1仿真tb文件

編寫仿真tb文件,fdma_bram_test_tb.v,非常簡單,只需要給一個時鍾

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////

/*

Company : Liyang Milian Electronic Technology Co., Ltd.

Brand: 米聯客(milianke)

Technical forumuisrc.com

taobao: osrc.taobao.com

Create Date: 2021/04/25

Module Name: fdma_bram_test_tb

Description:

Copyright: Copyright (c) msxbo

Revision: 1.0

Signal description

1) _i input

2) _o output

3) _n activ low

4) _dg debug signal

5) _r delay or register

6) _s state mechine

*/

////////////////////////////////////////////////////////////////////////////////

module fdma_bram_test_tb();

 

 

reg sysclk_p;

 

fdma_bram_test fdma_bram_test_inst

(

.sysclk_p(sysclk_p)

);

 

initial begin

sysclk_p = 0;

#100;

end

 

always #5 sysclk_p = ~sysclk_p;

 

endmodule

添加fdma_bram_test_tb.v到工程中

1.5.2仿真測試

進行RTL行為仿真

放大后觀察數據

我們也可以繼續深入看FDMA源碼里面的信號工作情況,這個讀者可以自己區分析下,我們米聯客計划出一份專門講解AXI總線部分的教程,里面詳細分析FDMA的設計過程,以及信號仿真。本章節主要是側重FDMA的應用,只要會熟練應用可以了!

1.6編譯測試

添加ila IP CORE 和fpga pin定義

ila的設置如下

 

編譯產生bit

下載程序到開發板測試,通過在線邏輯分析儀觀察

 

1.7程序分析

1.7.1FDMA的寫時序

fdma_wready設置為1,當fdma_wbusy=0的時候代表FDMA的總線非忙,可以進行一次新的FDMA傳輸,這個時候可以設置fdma_wreq=1,同時設置fdma burst的起始地址和fdma_wsize本次需要傳輸的數據大小(以bytes為單位)。當fdma_wvalid=1的時候需要給出有效的數據,寫入AXI總線。當最后一個數寫完后,fdma_wvalid和fdma_wbusy變為0。

1.7.2FDMA的讀時序

fdma_rready設置為1,當fdma_rbusy=0的時候代表FDMA的總線非忙,可以進行一次新的FDMA傳輸,這個時候可以設置fdma_rreq=1,同時設置fdma burst的起始地址和fdma_rsize本次需要傳輸的數據大小(以bytes為單位)。當fdma_rvalid=1的時候需要給出有效的數據,寫入AXI總線。當最后一個數寫完后,fdma_rvalid和fdma_rbusy變為0。

1.7.3讀寫狀態機

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM