VDMA操作相關,VDMA實現流水線


 

1.CSDN 上的原文 -*----HLS圖像處理系列——在ZEDBoard搭建DDR圖像處理通路

ZYNQ芯片內包含一個豐富特性的基於雙核ARM Cortex-A9的處理子系統(Processing System,PS)和Xilinx 28nm可編程邏輯(Programmable Logic,PL)。PS除了核心外還包括片上存儲器、外部存儲器接口以及大量外設連接接口。

利用ARM,我們可以做嵌入式操作系統相關的任務,如圖形界面、用戶輸入、網絡、DDR3控制等,由於ARM本身具有豐富的外設接口,而且支持多級流水線,處理這些事務游刃有余,但對於計算量較大的應用卻捉襟見肘,因為ARM本身還是典型的串行處理器,不適合做大數據、實時性較高的處理任務。FPGA恰好彌補了這一點,利用可編程邏輯可以實現並行處理,只要邏輯資源夠用,我們可以采用以空間換時間的策略,使多個計算單元同時進行,可大大縮短處理時間。

用ZYNQ進行圖像處理具有架構上的優勢,因此對於用ZYNQ做視頻相關的開發人員,一套ZYNQ上的圖像通路是必須的。本博文介紹的是一種攝像頭+HLS圖像處理+DDR存儲+VGA顯示的圖像通路。該通路是本人和另外一位同事合作實現,本人負責攝像頭的FPGA驅動、HLS圖像處理IP的實現以及系統的后期優化。由於涉及公司項目,因此不能提供工程文件,只提供框架和思路。

系統框架如下:

 

重點模塊介紹:

Camera:采用ov7725攝像頭,幀率60fps,分辨率640*480。關於攝像頭時序的詳解,請參考本人博文《教程——在ZEDBoard實現圖像通路(Block Ram版本)》

封裝后的攝像頭IP如下圖:

VDMA:在本設計中,VDMA的地位和通常設計中的DMA相似。但是,和DMA不同的是,VDMA專門為視頻流數據提供的高度存儲訪問模塊。其通過AXI-Stream協議接收視頻數據,而控制信號(比如幀緩沖的大小,DMA功能的開啟和關閉,以及一些其他的設置)則通過AXI-Lite從其他接口訪問。

VDMA擁有兩條DMA通路,S2MM通路將輸入的AXI4-Stream數據流映射到指定的幀緩沖,而MM2S則相反,將幀緩沖輸出為AXI4-Stream類型的數據流。

VDMA的配置界面如圖:

 

其中可以看到一些對於數據幀的配置信息,以及FrameBuffers數量的設置。FrameBuffers數量至少為3個,因為如果少於3個,那么會出現寫入DDR與讀取DDR的沖突,導致圖像出現斷層現象。在本設計中,FrameBuffers設置為3個。

Video In to AXI4-Stream 與 AXI4-Stream to Video Out:由於攝像頭傳入的信號使用的協議並非AXI4-Stream,而VDMA卻需要接收AXI4-Stream類型的數據,所以需要有專門的IP核來進行兩者之間的轉換。

這兩個IP核是:

Video In to AXI4-Stream,該IP將視頻數據轉化為AXI4-Stream類型。本工程中,視頻數據來自於camera模塊,只需要camera提供四路信號:行同步、場同步、24bit的像素、數據有效信號。

AXI4-Stream to Video Out,該IP將AXI4-Stream類型數據轉化為視頻數據。視頻數據即為VGA信號,包含行同步、場同步、數據有效信號以及像素。該模塊有一個timing的輸入,在本系統中,來自於video timing control IP。video timing control模塊給AXI4-Stream to Video Out IP提供一個640*480p的VGA時序信號。

下圖為Video In to AXI4-Stream IP與AXI4-Stream to Video Out IP:

 

這兩個IP核在本設計中處於橋梁地位,用於連接外部IO和VDMA。在這兩個模塊內部的視頻數據都是AXI4-Stream類型,省去了地址,因此速度更快、更容易處理。一般而言,HLS硬件圖像處理模塊都會放在這兩個IP核之間。

HLS圖像處理模塊:本設計中,構建了一個簡單的Sobel圖像處理模塊,由HLS工具生成打包成IP。關於HLS工具不多介紹,可以參考本人博客《HLS圖像處理系列——前言》來初步了解HLS。HLS生成的IP輸入輸出視頻流都符合AXI4-Stream協議。

然后,附上vivado的工程截圖:

在SDK工程,主要是進行HLS IP的初始化與VDMA的初始化。只有初始化之后,整個圖像通路才能正確運行。HLS初始化源碼短短幾行,但也是折磨了我好久,因為需要關閉中斷,好長時間內都沒有發現這個問題。初始化重點源碼如下:

 

  1.  
    /************config hls ip********/
  2.  
    void ConfigureHlsIP(XImgprocess_top *ImgProcess)
  3.  
    {
  4.  
    ImgProcess->Control_bus_BaseAddress = XPAR_IMGPROCESS_TOP_0_S_AXI_CONTROL_BUS_BASEADDR;
  5.  
    ImgProcess->IsReady = XIL_COMPONENT_IS_READY;
  6.  
     
  7.  
    XImgprocess_top_EnableAutoRestart(ImgProcess);
  8.  
    XImgprocess_top_SetRows(ImgProcess, 480);
  9.  
    XImgprocess_top_SetCols(ImgProcess, 640);
  10.  
     
  11.  
    XImgprocess_top_InterruptDisable(ImgProcess, 0xFFFFFFFF);
  12.  
    XImgprocess_top_InterruptGlobalDisable(ImgProcess);
  13.  
    XImgprocess_top_Start(ImgProcess);
  14.  
    }
  15.  
     
  16.  
    int main()
  17.  
    {
  18.  
    init_platform();
  19.  
    usleep( 100000);
  20.  
    print( "Hello World\n\r");
  21.  
    ConfigureHlsIP(&ImgProcess);
  22.  
    // MM2S
  23.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x00, 0x008B); // enable run, circular_park, GenlockEn, GenlockSrc
  24.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x5C, 0x01000000); // Start address of the 1st frame(3 frames in all)
  25.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x60, 0x02000000); // Start address of the 2nd frame(3 frames in all)
  26.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x64, 0x03000000); // Start address of the 3rd frame(3 frames in all)
  27.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x58, 0x0780); // Stride number
  28.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x54, 0x0780); // number of bytes per line(640 x 3)
  29.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x50, 0x01E0); // number of lines per frame(480)
  30.  
     
  31.  
    //S2MM
  32.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x30, 0x108B); // enable run, circular_park
  33.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xAC, 0x01000000); // Start address of the 1st frame(3 frames in all)
  34.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xB0, 0x02000000); // Start address of the 2nd frame(3 frames in all)
  35.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xB4, 0x03000000); // Start address of the 3rd frame(3 frames in all)
  36.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA8, 0x0780); // Stride number
  37.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA4, 0x0780); // number of bytes per line(640 x 3)
  38.  
    Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA0, 0x01E0); // number of lines per frame(480)
  39.  
     
  40.  
    return 0;
  41.  
    }
     
    2.對上位的注解如下:
    HSIZE為每行的點數,單位byte;如果是rgb格式的數據就要在每行的點數上*3;
    VDMA IP中設置幀buffer為3,在寄存器設置時,就對應設置三個start address,對應每幀buffer的起始起始地址;在這里是VDMA實現乒乓幀,流水線操作的關鍵;genlock mode circular mode  internal genlock
    stride number 單位byte; 每次行突發的步進值;這個值小於等於HSIZE;
      雙擊查看原圖
    手冊中這段文字,一是解析VDMA在處理S2MM/MM2S兩端對DDR總線的帶寬資源的占用是如何進行仲裁的。
    二是,在這里更加體現VDMA 的乒乓流水特性;
     
     
     
     
     


免責聲明!

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



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