很多人用zynq平台做視頻圖像開發,但是對vdma了解比較少,上手起來稍微有些困難,我針對這一現象,做了一個基於vivado和modelsim的仿真和應用測試工程,並寫篇文章做些介紹,希望能對大家有幫助。
一:xilinx vdma IP例化以及接口介紹
上面圖片就是在vivado2015.4中例化vdma的界面,首先對參數做些介紹:
Frame Buffers :選擇vdma緩存幾幀圖像,這里默認是寫通道和讀通道都設置相同的緩存幀數,具體設置多少幀合適一般根據應用來定,比如讀寫帶寬相同,想用ddr作為一個乒乓buffer,那就可以設置成2幀,寫第一個地址,讀第二個地址,寫第二個地址,讀第一個地址。這里面設置幾幀,就要在vdma寄存器配置的時候設置幾個幀起始地址。
Memory Map Data Width:代表數據到達AXI4總線上的位寬,比如這里設置成64,那就代表M_AXI_XX總線上的數據位寬是64bit,這時候如果stream上的數據是32bit,那vdma內部會有一個帶寬轉換模塊,把數據拼成64bit。
Burst Size : AXI總線上突發傳輸的長度,一般設置為16
Stream Data Width:vdma與pl邏輯部分通過axi stream協議交互數據,這里代表stream數據位寬
Line Buffer Depth:vdma內部會有一個行緩存fifo,stream數據會先寫入fifo,然后AXI總線邏輯會讀出到總線上,這個深度就代表fifo的深度。設置原則(個人理解):如果AXI總線數據帶寬是stream總線數據帶寬的1.5倍以上,這個fifo深度可以設置的小一點,如果AXI總線帶寬小於1.5倍的stream總線帶寬,那fifo的深度至少要是圖像一個有效行的一半。
Advanced : 這里面只說一下Fsync Options,這個信號是什么意思呢,就是告訴vdma什么時候開始運行,一般s2mm通道選擇tuser,就是說在tuser 拉高的時候開始傳輸。mm2s通道,可以選擇none,也可以選擇 mm2s_fsync,這里介紹一下這兩個的區別。
none : 就是沒有同步信號,但這並不是說沒有開始信號,而是只要mm2s_stream通道tready拉高,就開始傳輸,相當於free模式
mm2s_fsync:當這個信號發生一個下降沿的時候開始傳輸,如果沒有這個下降沿,即使mm2s_stream通道tready拉高也不會傳輸
下面是接口介紹:
M_AXI_XX : axi4總線接口,用來與ddr交互數據
M_AXIS_XX , S_AXIS_XX : axi stream接口,用來與pl交互數據
S_AXI_LITE :控制總線,接到ps的gp口或者寫一個axilite master總線去配置
其他接口不做介紹
二:下面開始一步步的詳解如何搭建一個vdma的仿真工程
FPGA的開發,離不開仿真,很少有人能直接寫好代碼上板就成功的,仿真必不可少。但是有些應用要用到vdma,vdma又要和ddr做數據交互,這樣做起來就很麻煩了,我這里就實現了一個簡單的方法,可以測試vdma,又不用去例化MIG搞什么ddr。下面開始!
系統框圖:
(1)因為是要仿真vdma,vdma顧名思義就是video dma,那肯定要先做一個視頻模塊,注意,我這里除了vdma和fifo用xilinx的ip。其他的都不用ip,這樣更通用性。
我這里就把這個視頻發生模塊叫做sensor,可以理解為xilin的tpg模塊,sensor模塊的接口如下:
eg1:
我這里構建了一個圖像傳感器,總像素數是600*800,有效像素是 480*640,水平有效像素開始位置是80,垂直有效像素開始位置是60,這個模塊會讀取一個本地圖像數據,rgb格式,這里為了測試方便,直接把像素輸出位寬設置為32bit。
(2)video轉axis模塊,相當於 xilinx的vid in to stream模塊,接口如下:
eg2:
這個模塊主要用到一個fifo來做數據緩存,只要注意一下stream協議的握手操作即可,由於stream協議比較簡單,這里就不多說了。至此,video數據就轉換到了stream數據。
(3)axis轉video模塊,接口如下:
eg3:
這個模塊相當於xilinx的vid out模塊,我這里是簡化版的,xilinx的ip寫的太復雜了,而且不容易用起來,其實也就是用一個fifo做數據緩存,然后根據外部video時序從fifo讀出到輸出。
(4)video timing gen模塊,接口如下:
eg4:
此模塊產生視頻時序,提供給 axis2video模塊,相當於xilinx的vtc模塊。
(5) axi slave模塊,接口如下:
eg5:
這塊模塊是根據xilinx官方提供的參考設計基礎上修改而來的(xapp1168),協議部分完全沒有改動,這里拿他當做ddr,具體修改是這樣的,
reg [31:0] mem [32’h01000000:0];
用寄存器組來模擬ddr
此模塊會根據axi master的時序來計算出要讀寫的地址
assign write_mem_address = axi_awv_awr_flag ? axi_awaddr: 0;
assign read_mem_address = axi_arv_arr_flag ? axi_araddr: 0;
寫操作:mem[write_mem_address>>2] <= #1 S_AXI_WDATA;
讀操作:mem_data_out <= mem[read_mem_address>>2];
做此修改以后,這個模塊就可以當做ddr來用,為仿真提供了很大的方便
(6)vdma模塊,這個就用xilinx的vdma ip,注意,我這里不是在block design里面例化,所以端口需要自己在hdl里面做連接的。
這里還有一個模塊是 axi lite master模塊,作用是用來配置vdma的寄存器,這個模塊也是xilinx提供的,只需要做小量修改即可
eg6:
我這里是把ddr作為一個乒乓buffer,所以vdma緩存幀數選擇2幀,寄存器配置里面就配置兩個傳輸地址。這樣就完成了對vdma的寄存器配置。
編寫test bench top文件,把這些模塊連接起來,至此,仿真工程就全部寫好了。
三:仿真
(1)vdma工作流程介紹
第一步,對vdma寄存器進行配置,並打開使能,這時候vdma處於待命狀態,什么時候開始傳輸呢,下面詳細介紹
對於S2MM通道:之前在講vdma配置的時候有一個Advanced選項,里面有Fsync Options選項,可選none,s2mm_fsync,s2mm_tuer,三種同步模式。
none就是只要vdma就緒,就立馬准備接收數據,不需要同步信號。
s2mm_fsync,當選擇此模式時,vdma 模塊會有一個s2mm_fsync引腳,一般情況下是把視頻幀同步信號連到這上面,當檢測到s2mm_fsync引腳有一個下降沿的時候,vdma正式進入傳輸狀態。
s2mm_tuer,這個信號和s2mm_fsync這個信號類似,但他是在stream協議里面的,vdma檢測到s2mm_tuer拉高以后(tuser只在一幀數據的第一個像素位置拉高),正式進入傳輸狀態
對於MM2S通道,同樣在vdma配置的Advanced選項里面有 none,mm2s_fsync兩種選擇模式。
none不需要同步信號,只要axis_mm2s通道的tready拉高,就開始從ddr讀取數據進行傳輸,選擇這種模式一般主要是把ddr里面的數據讀到pl里面進行處理,而不是轉成視頻
mm2s_fsync,選擇此同步模式,一般是把ddr的數據轉成視頻數據,注意,這里重點講這個同步模式,當vdma的讀通道選擇此同步模式的時候,vdma模塊會有一個mm2s_fsync信號,這個信號在讀操作中非常重要。當vdma寄存器配置完成並開啟傳輸,mm2s通道進入等待過程,一直等到mm2s引腳信號出現一個下降沿,這時候vdma啟動讀操作,會從ddr預讀一些數據到內部linebuffer,等到axis_mm2s通道的tready信號拉高,數據就開始傳輸,進入axis2video模塊的fifo,當axis2video內部fifo滿了以后,會拉低tready,這時候就會反饋到vdma,暫停讀操作,一直等到axis2video模塊的視頻時序輸入數據有效信號,這時候視頻開始輸出,axis2video內部fifo數據減少,axis_mm2s通道開始恢復傳輸,繼續從vdma讀出數據,vdma再通過axi總線從ddr讀取數據,如此反復,完成ddr數據到video數據的轉換
(2)仿真實踐
首先在vivado平台例化一個vdma ip,然后添加進上述的各個模塊,代碼層級如下:
eg7:
四:總結
通過對vdma的仿真,可以更深入的了解vdma的工作原理,工作流程,給實際應用做好准備工作。同時,這么做也有更多的意義,對於一些需要DDR緩存才能完成的圖像算法,比如視頻3D降噪,運動物體檢測幀差法,HDR圖像合成等等,完全可以在此基礎上進行仿真,能更大程度的模擬FPGA實際工作狀況,提高算法移植效率