ZYNQ學習之路4.ZYNQ通過GP口讀取PL內部RAM數據

實驗環境:window 7 64 bit, vivado 2017.1, ZTURN board.

參考手冊:Xilinx Distributed Memory Generator

        在ZYNQ開發中,經常需要PS與PL進行數據交互。當數據量比較大時往往需要先緩存一部分然後批量傳輸到Linux系統,否則中斷響應時間無法滿足要求,使用雙端口RAM或許是一種不錯的方法。本文詳細描述PS端讀寫PL端片的雙端口RAM數據的實驗過程。本次實驗使用FPGA內部的Block Memory,PS端通過Master GP0端口向RAM寫數據,通過Master GP1端口讀出數據,本次實驗涉及到AXI BRAM Controller和Block Memory Generator等IP核。

一. SRAM介紹

1.1 雙端口RAM結構

        Xilinx的ZYNQ7Z010內部FPGA是virtex7系列,內部有32KB的Block Memory,可以用它作爲ROM,Single-Port RAM, Dual-Port RAM或Simple Dual-Port RAM, RAM的區別在於讀寫數據線與地址總線的數量的區別,根據自己的需求進行選擇。

RAM類型

功能

數據總線數量

地址總線數量

Single-Port

通過一個端口進行數據的讀寫操作

1

1

Dual-Port

通過兩個端口讀寫數據

2

2

Simple Dual-Port

一個端口進行寫操作,另一個端口進行讀操作

1

2

        雙端口RAM示意圖如下:

圖1-1.雙端口RAM示意圖題

        雙端口RAM相比其他幾種RAM更復雜,所以本文只介紹雙端口RAM的使用。

1.2 雙端口RAM控制信號

        上文中的示意圖中只列出了基本且常用的信號,其他特殊信號在次不做介紹。常用控制信號功能定義如下:

信號

方向

描述

din[31:0]

Input

數據總線輸入,32位寬

addr[31:0]

Input

地址總線輸入,32位寬,地址從0開始,有效至容量大小

clk

Input

時鐘信號輸入,1位,寫同步時鐘

en

Input

使能讀,寫,復位選項

rst

Input

復位或置位讀出鎖存寄存器,如果要讀出需要置置

wea[3:0]

Input

寫使能

dout[31:0]

Output

數據輸出,32位寬

        雙端口RAM的工作模式有三種,寫優先、讀優先和無變化模式。

寫優先模式:數據同時寫入到內存並輸出到數據端口,時序如圖1-2所示:

圖1-2: Write First Mode Example

讀優先模式:當要寫入內存數據時,先前存儲的數據在寫地址有效前存儲到數據輸出總線上。時序圖如圖1-3所示:

圖1-3:Read First Mode Example

無變化模式: 輸出鎖存器在寫入內存期間不改變值。時序圖如圖1-4所示:

圖1-4:No Change Mode Example

1.3 字節寫操作

在使用32爲數據總線時,數據按32位同時變化,如果只寫入8,16,24位的數據或者間隔一個字節寫入兩個不連續的字節,這是可以使用WE信號,首先看看圖1-5時序圖。

圖1-5: Byte-write Example標題

圖中第一個上升沿到來之時,數據輸入0xFFEEDD,WEA=0x011,寫入內容變爲0x00FFDD,只有後面兩個字節寫入成功,可以發現WEA的某個bit位置1時對應數據輸入的字節將被寫入,其他字節屏蔽寫操作,32爲數據總線時WEA爲4位,從低到高依次對應數據總線低到高的四個字節的掩碼,置位可寫,復位屏蔽,也就是說寫32位數據時WEA[3:0]=b1111.

二. PL端硬件設計

2.1 新建一個vivado工程,選擇開發板所對應的芯片型號。

2.2 Add IP, 添加ZYNQ,雙擊設置屬性,保留uart1,選擇M AXI GP0 interface和M AXI GP1 interface

圖2-1: ZYNQ IP核GP端口設置

2.3 Add IP, 添加一個Block memory Generator,選擇true dual Port RAM類型。

圖2-2: Block Ram設置

2.4 Add IP,添加兩個AXI BRAM Controller,把number of BRAM interfaces改成1。

圖2-3: AXI BRAM Controler設置

2.5 點擊run connection automation,把axi_bram_ctl_0的Master選擇爲GP0, axi_bram_ctl_1的Master選擇爲GP1,interconnect ip都選擇爲 new AXI Interconnect。

圖2-4: 設置AXI連接

2.6 點擊重新佈局,最後得到如下結構。

圖2-5: 雙端口RAM系統結構

2.7 點擊Address Editor,可以看到GP0和GP1的地址已經自動分配好。

圖2-6: RAM地址分配

2.8 在sources下選擇block design右擊,點擊Create HDL wrapper,生成系統的頂層模塊,在system_wrapper上右擊,選擇generate output products...。

2.9 編譯綜合工程,最後generate bitstream,導出硬件(包含bitstream),launch SDK。

 

三. PS端軟件的編寫與測試

3.1 新建一個以helloworld爲模板的工程,SDK自動創建了硬件的bsp,設置終端串口爲uart1。

 

3.2 在main函數中編寫代碼如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include <sleep.h>
#include "xil_io.h"
#include "xparameters.h"

int main()
{
    int a[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    int b[16] = {0};
    init_platform();

    print("------The test is start...------\n\r");
    xil_printf( "Write data:\n\r");
    memcpy((void *)0x40000000, a, 16*4);
    for(int i = 0;i<16;i++)
    {
    xil_printf( "%x  ",a[i]);
    }
    xil_printf( "\n\r");
    sleep(1);
    xil_printf( "Read data:\n\r");
    memcpy(b, (void*)0x80000000, 4*16);
    for(int i = 0;i<16;i++)
    {
    	xil_printf( "%x  ",b[i]);
    }

    xil_printf( "\n\r");

    xil_printf("------The test is end!------\n\r");
    cleanup_platform();
    return 0;
}

程序開始向地址0x40000000處複製數組a的內容,並打印數組a,然後將地址0x80000000開始的64字節(數組a大小)內容複製到數組b中,然後打印數組b。如果不復制到數組b,顯然數組b是全零數組,上電啓動初始狀態內存中全部爲爲0。0x40000000和0x80000000分別是雙端口RAM的兩個端口的起始地址,如果寫入與讀取的內容一致,則說明雙端口RAM的兩套讀寫地址操作的是同一個存儲空間,說明實驗是成功的。

3.3 連接好仿真器和串口終端,先下載FPGA程序,然後運行PS的軟件,在終端顯示如下:

可以看出讀取的與寫入的數據完全一樣,然而讀取的地址不一樣,說明實驗是成功的。

說明:由於BRAM是連接在GP0和GP1接口上通過AXI總線進行讀寫操作,在地址空間上尋址可以直接使用指針操作,因此memcpy這樣的C基本庫函數可以直接對GP0和GP1地址空間進行操作,在訪問速度上比使用循環指針操作要快很多。

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