XDMA ip core的使用


XDMA核的使用

一、   XDMA相關知識

絕對地址就是物理地址=段地址*16+偏移地址,也就是段地址<<4+偏移地址

主機host通過PCIe接口訪問DMA,DMA即外部設備不通過CPU而直接與系統內存(DDR)交換數據。

PIO模式下硬盤和內存之間的數據傳輸是通過CPU來控制的,而在DMA模式下,CPU只需向DMA控制下達命令,讓DMA來控制數據的發送,數據傳送完畢后再把數據反饋給CPU,這樣很大程度上減輕了 CPU的資源占有率。

DMA和PIO模式的區別就在於,DMA模式不過分依賴CPU,可以大大的節省系統資源,二者在傳輸速度上的差異並不明顯。

PIO模式:CPU通過執行端口IO指令來進行數據讀寫的交換方式。CPU占有率高。

在例程中數據傳輸使用XDMA方式,與DMA相同,CPU通過向DMA發送指令完成數據的讀寫。

讀寫部分分為兩種,一種是數據的讀寫,另一種數配置數據的讀寫,在數據讀寫部分,DMA通過MIG控制DDR完成數據讀寫。配置數據讀寫通過與BRAM通過AXI-lite總線連接完成,XDMA將PCIe配置信息存在BRAM,在進行配置信息讀寫時,將傳入主機映射到用戶邏輯的地址,然后與偏移地址處理(物理地址=段地址<<4+偏移地址),所以在bram設置時需要將其偏移地址設置的與主機地址映射的偏移地址相同。

對於DDR則不必,設置的話還減少了可使用的內存空間,只是一個袋子,寫在哪里就從哪里讀取即可,必須設置為0。

XDMA ip core的配置:

1、  Basic

Functional mode:功能模式,即DMA模式。

Mode:模式,選擇basic即可,basic與advanced的區別在於advanced模式開放更多的可選選項與功能,basic的話為默認。

Device/Port Type:選擇設備與端口類型,為端點設備。

PCIe Block Location:從可用的集成塊中選擇,以啟用生成特定位置的約束文件和輸出,產品能夠pg054datasheet截取的位置說明P249。

 

 

 

Lane width:通道寬度,根據接口進行選擇。

AXI Address width:AXI地址寬度選擇,只支持64bit(用戶手冊73頁)。

AXI Data Width:AXI總線上傳輸的數據寬度,可以是64bit、128bit、256bit、512bit(這個只有ultrascale+可以滿足,一分錢一分貨),根據datasheet進行配置即可P249,見下圖。

 

 

 

DMA Interface option:DMA的接口類型用於數據傳輸,有兩種AXI MM(memory mapped)與AXI ST(stream),二選一。

PCIe ID:

見之前推送。

PCIe BARs:

PCIe to AXI Lite Master Interface:使能,這樣可以在主機一側通過PCIe來訪問用戶邏輯側寄存器或者其他AXI-Lite總線設備。

       此處將配置信息存儲到BRAM,通過AXI-lite總線讀寫Bram。

(1)、BAR為32bit,不使能64bit,prefetchable表示預讀取,不使能。

(2)、映射空間選擇1M,大小隨意。

(3)、PCIe to AXI Translation:主機側BAR地址與用戶邏輯側地址不同,通過設置轉換地址實現BAR地址到AXI地址的轉換。比如主機一側BAR地址為0,則主機訪問BAR地址0轉換到AXI-Lite總線就是0x8000_0000.

PCIe to DMA Interface:數據傳輸寬度64bit,DMA控制器一般只支持數據8字節對齊的情況。

當數據從上位機通過PCIe接口發送到端點設備,XDMA內部自行解包對將數據與指令進行分析,得到讀寫操作的指令地址,並對DDR進行讀寫操作。操作的結果通過AXI接口返回XDMA,XDMA對數據進行組包,之后通過物理層發出,實現數據的DMA控制。

二、上位機設計

2.1 h2c_transfer函數

該函數的作用是向DDR中寫入數據,寫入大小固定的數據,根據寫入時間計算傳輸的速度(MB/s)。

1、變量定義

Double型變量bd,用於寄存傳輸速度。

Double型變量time_sec,用於保存傳輸定量數據所需時間。

LARGE_INTEGER型變量變量start和stop用於保存頻率計數值。還有freq,用於保存機器內部計時器的時鍾頻率。

2、函數操作

2.1 獲取傳輸所需時間

獲取傳輸所需時間,則需要三個量:機器時鍾頻率,傳輸開始前后計數器的計數值。

獲取機器內部計時器的時鍾

QueryPerformanceFrequency(&freq);

      QueryPerformanceCounter(&start);

      ……    //數據傳輸

  QueryPerformanceCounter(&stop);

頭文件為<Windows.h>,函數原型為:

BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);

在定時前先調用QueryPerformanceFrequency函數獲得機器內部計時器的時鍾頻率,然后在嚴格計時的時間發生前后調用QueryPerformanceCounter函數,獲得兩次計數的差值經過轉換得到事件耗費的精准時間。

LARGE_INTEGER為一個typedef定義的變量,其原型為:

typeef union _ LARGE_INTEGER

{

struct

{

DWORD LowPart;

LONG HighPart;

};

LONGLONG QuadPart;

} LARGE_INTEGER;

2.2 數據寫入操作

    使用的是自定義的write_device()函數,操作語句為:write_device(h2c0_device,FPGA_DDR_START_ADDR+0x20000000,size,h2c_align_mem_tmp);四個參數分別為:設備句柄,傳輸目的地址,傳輸的數據大小(單位為字節),寫入數據的緩存區地址。

在write_device函數中,重點是變量與函數語句:

變量:

DWORD wr_size:用於保存寫入的字節數

unsigned int transfers;傳輸次數,每次傳輸的最大字節數為0x800000,也就是8MB,根據要傳輸的字節數計算所需傳輸的次數。

函數語句:

數據的寫入通過WriteFile()函數完成,操作語句為WriteFile(device, (void *)(buffer+i*MAX_BYTES_PER_TRANSFER), MAX_BYTES_PER_TRANSFER, &wr_size, NULL),傳入參數分別為:系統文件句柄,寫入數據的存儲地址,每次傳輸的字節數,成功寫入的字節數。

WriteFile()函數的返回值為bool類型,操作成功為true,操作失敗返回-1,實際寫入的字節數與設定的寫入字節數不同時返回-2。

在數據寫入之前,需要先設置一個文件在設備的對應地址中的操作位置,FILE_BEGIN表示在文件的起始位置接收傳輸的數據。

 

unsigned int h2c_transfer(unsigned int size)
{
    double bd=0;
    double time_sec;
    LARGE_INTEGER start;
    LARGE_INTEGER stop;
    LARGE_INTEGER freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start); write_device(h2c0_device,FPGA_DDR_START_ADDR+0x20000000,size,h2c_align_mem_tmp);
    QueryPerformanceCounter(&stop);
    time_sec = (unsigned long long)(stop.QuadPart - start.QuadPart) / (double)freq.QuadPart;
    bd = ((double)size)/(double)(time_sec)/1024.0/1024.0;

    return (unsigned int)bd;
}

2.3 數據讀取操作

    與數據寫入類似,讀取的起始地址為寫入時的起始地址。

unsigned int c2h_transfer(unsigned int size)

{

    double bd=0;

    double time_sec;

    LARGE_INTEGER start;

    LARGE_INTEGER stop;

    LARGE_INTEGER freq;

 

    QueryPerformanceFrequency(&freq);

    QueryPerformanceCounter(&start);

    read_device(c2h0_device,FPGA_DDR_START_ADDR+0x10000000,size,c2h_align_mem_tmp);

    QueryPerformanceCounter(&stop);

    time_sec = (unsigned long long)(stop.QuadPart - start.QuadPart) / (double)freq.QuadPart;

    bd = ((double)size)/(double)(time_sec)/1024.0/1024.0;

 

    return (unsigned int)bd;

}

 


免責聲明!

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



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