XDMA ip core 的ADC采集應用


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;

}

三、基於PCIe的下位機設計

3.1 簡介

首先是選用一個AD轉換器進行電壓數據的采集,之后自定義一個AXI—Full類型的IP封裝,調用XDMA ip core連接AXI封裝,AXI封裝將連接一個fifo模塊,從fifo中讀取出來的數據通過AXI-Full總線送至XDMA的AXI主接口,XDMA會將數據進行自動封裝,封裝成TLP包,等到上位機發出數據讀取請求時候,將數據發送到上位機進行波形顯示。

PCIe設計模塊:

 

 

分析其信號:

1.1 輸入信號

pkg_rdy: package ready信號,表示數據部分准備好進行讀取。

pkg_data[63:0]: 64bit的數據輸入。

pcie_ref:XDMA的驅動時鍾輸入,雙極性,經過一個緩沖之后接入到XDMA ip core。

pcie_rst_n: XDMA復位控制。

1.2 輸出信號

pkg_rd_en: 由AXI Slave core發出的讀取fifo使能信號。

pcie_mgt: PCIe電氣接口信號,TX與RX,7030為PCIe2.0,lane width: x2。

axi_aclk:AXI總線驅動時鍾,該時用於fifo的數據讀取。

Clk_50M:通過時鍾功能核clocking Wizard生成,作用是驅動AD7606的驅動。

Rst_n:復位信號,控制AD驅動與fifo的復位。

3.2 項目設計

1.1 AD驅動設計

AD采集芯片為AD7606,按照數據與例程設計。

1.2 fifo使用

將AD采集得到的數據存儲到fifo中,fifo的接口類型為本地native類型,fifo的實現方式為獨立時鍾的塊ram,即數據的讀取與寫入使用獨立的時鍾,寫入的數據寬度為64bit,是AD0~AD3的16bit數據拼接得到的64bit寫入數據,寫入深度為4096,數據讀取同。引出寫入數據的計數器,用於通知AXI-Salve core數據讀取允許。

通過AD采集模塊的數據采集完成標志作為fifo數據寫入的使能信號,寫入的數據個數通過Write Data Count來指示,以下為摘取自fifo datasheet中關於該信號的介紹:

Write Data Count

Write Data Count: This bus indicates the number of words written into the FIFO. The count is guaranteed to never under-report the number of words in the FIFO, to ensure you never overflow the FIFO. The exception to this behavior is when a write operation occurs at the rising edge of wr_clk/clk, that write operation will only be reflected on wr_data_count at the next rising clock edge. If D is less than log2(FIFO depth)-1, the bus is truncated by removing the least-significant bits.

Note: wr_data_count is also available for UltraScale devices using a common clock Block RAM-based FIFO when the Asymmetric Port Width option is enabled.

注:datasheet真是個好東西,問啥告訴啥!

使用fifo的半滿信號作為AXI Slave ip core的包准備好信號。

AXI Slave ip core在輸入的包讀取使能信號(pkg_rdy)之后,將自身的valid信號置一,等待AXI總線可以進行數據讀取,輸入數據為fifo的內部數據。

四、上位機設計

上位機顯示使用了QWT環境,QWT環境的設置可以參考博文:https://www.cnblogs.com/luxinshuo/p/12316037.html

QT中的程序最重要的一點為設置一個定時器,定時器定時滿后關聯數據更新槽函數。

 


免責聲明!

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



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