日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > > ZYNQ

		


AXI Stream協(xié)議及視頻流格式

AXI Stream關(guān)鍵的只有兩根信號線,及tvalid核tready。tvalid是主設(shè)備驅(qū)動的信號,表示Stream上的數(shù)據(jù)是有效的,tready由從設(shè)備驅(qū)動,表示從設(shè)備下一個時鐘到來時能夠接收數(shù)據(jù)。AXI Stream的特點(diǎn)是這兩個信號不存在互相等待的關(guān)系,及數(shù)據(jù)傳輸只發(fā)生再兩者均有效的時候,從而效率很高,可以認(rèn)為是連續(xù)傳輸,避免了死鎖的情況。

AXI Stream還有一些附加信號,通常是伴隨再數(shù)據(jù)中傳輸,主要包括tuser,tlast,tkeep等。tlast在標(biāo)準(zhǔn)流協(xié)議中表示一個數(shù)據(jù)包結(jié)束,伴隨最后一個數(shù)據(jù)傳出,tuser可以很多位,是用戶定義信號,用來表達(dá)用戶自己需要傳輸?shù)臄?shù)據(jù)。tkeep是字節(jié)修飾符,位數(shù)位數(shù)據(jù)寬度/8,當(dāng)總線數(shù)據(jù)某字節(jié)有效時,tkeep對應(yīng)位就為高。

Xilinx 所有與視頻有關(guān)的IP均遵循一套AXI Stram視頻流協(xié)議,其中對tlast與tuser賦予了特殊的含義。視頻流中除了數(shù)據(jù)以外,包好start of frame和end of line信號,其中eol用tlast表示,sof用tuser表示。這兩個信號均伴隨像素?cái)?shù)據(jù)傳輸,只保持一次有效傳輸?shù)臅r間,sof和一幀第一個像素一起傳出,eol和一行最后一個像素一起傳輸。視頻流中有時會加入tkeep信號,無特殊情況時需全部拉高。

VDMA的詳細(xì)講解和使用

vdma  IP核配置界面

上面圖片就是在vivado中例化vdma的界面,首先對參數(shù)做些介紹:

基本配置 高級配置
地址線寬度 是否使能異步模式(自動)
幀存數(shù)量 寫通道幀同步
是否使能讀寫通道 寫通道GenLock模式選擇
數(shù)據(jù)線寬度 寫通道是否允許非對齊傳輸
觸發(fā)長度 讀通道幀同步
AXI-Stream流數(shù)據(jù)位寬 讀通道GenLock模式選擇
Line Buffer深度 讀通道是否允許非對齊傳輸

Frame Buffers :選擇vdma緩存幾幀圖像,這里默認(rèn)是寫通道和讀通道都設(shè)置相同的緩存幀數(shù),具體設(shè)置多少幀合適一般根據(jù)應(yīng)用來定,比如讀寫帶寬相同,想用ddr作為一個乒乓buffer,那就可以設(shè)置成2幀,寫第一個地址,讀第二個地址,寫第二個地址,讀第一個地址。這里面設(shè)置幾幀,就要在vdma寄存器配置的時候設(shè)置幾個幀起始地址。

Memory Map Data Width:代表數(shù)據(jù)到達(dá)AXI4總線上的位寬,比如這里設(shè)置成64,那就代表M_AXI_XX總線上的數(shù)據(jù)位寬是64bit,這時候如果stream上的數(shù)據(jù)是32bit,那vdma內(nèi)部會有一個帶寬轉(zhuǎn)換模塊,把數(shù)據(jù)拼成64bit。

Burst Size :AXI總線上突發(fā)傳輸?shù)拈L度,一般設(shè)置為16

Stream Data Width:vdma與pl邏輯部分通過axi stream協(xié)議交互數(shù)據(jù),這里代表stream數(shù)據(jù)位寬

Line Buffer Depth:vdma內(nèi)部會有一個行緩存fifo,stream數(shù)據(jù)會先寫入fifo,然后AXI總線邏輯會讀出到總線上,這個深度就代表fifo的深度。設(shè)置原則(個人理解):如果AXI總線數(shù)據(jù)帶寬是stream總線數(shù)據(jù)帶寬的1.5倍以上,這個fifo深度可以設(shè)置的小一點(diǎn),如果AXI總線帶寬小于1.5倍的stream總線帶寬,那fifo的深度至少要是圖像一個有效行的一半。

Advanced :這里面只說一下Fsync Options,這個信號是什么意思呢,就是告訴vdma什么時候開始運(yùn)行,一般s2mm通道選擇tuser,就是說在tuser 拉高的時候開始傳輸。mm2s通道,可以選擇none,也可以選擇 mm2s_fsync,這里介紹一下這兩個的區(qū)別。

none :就是沒有同步信號,但這并不是說沒有開始信號,而是只要mm2s_stream通道tready拉高,就開始傳輸,相當(dāng)于free模式 mm2s_fsync:當(dāng)這個信號發(fā)生一個下降沿的時候開始傳輸,如果沒有這個下降沿,即使mm2s_stream通道tready拉高也不會傳輸

詳細(xì)說明

對于S2MM通道:之前在講vdma配置的時候有一個Advanced選項(xiàng),里面有Fsync Options選項(xiàng),可選none,s2mm_fsync,s2mm_tuer,三種同步模式。

none就是只要vdma就緒,就立馬準(zhǔn)備接收數(shù)據(jù),不需要同步信號。

s2mm_fsync,當(dāng)選擇此。模式時,vdma 模塊會有一個s2mm_fsync引腳,一般情況下是把視頻幀同步信號連到這上面,當(dāng)檢測到s2mm_fsync引腳有一個下降沿的時候,vdma正式進(jìn)入傳輸狀態(tài)。

s2mm_tuer,這個信號和s2mm_fsync這個信號類似,但他是在stream協(xié)議里面的,vdma檢測到s2mm_tuer拉高以后(tuser只在一幀數(shù)據(jù)的第一個像素位置拉高),正式進(jìn)入傳輸狀態(tài)

對于MM2S通道,同樣在vdma配置的Advanced選項(xiàng)里面有 none,mm2s_fsync兩種選擇模式。

none不需要同步信號,只要axis_mm2s通道的tready拉高,就開始從ddr讀取數(shù)據(jù)進(jìn)行傳輸,選擇這種模式一般主要是把ddr里面的數(shù)據(jù)讀到pl里面進(jìn)行處理,而不是轉(zhuǎn)成視頻

mm2s_fsync,選擇此同步模式,一般是把ddr的數(shù)據(jù)轉(zhuǎn)成視頻數(shù)據(jù),注意,這里重點(diǎn)講這個同步模式,當(dāng)vdma的讀通道選擇此同步模式的時候,vdma模塊會有一個mm2s_fsync信號,這個信號在讀操作中非常重要。當(dāng)vdma寄存器配置完成并開啟傳輸,mm2s通道進(jìn)入等待過程,一直等到mm2s引腳信號出現(xiàn)一個下降沿,這時候vdma啟動讀操作,會從ddr預(yù)讀一些數(shù)據(jù)到內(nèi)部linebuffer,等到axis_mm2s通道的tready信號拉高,數(shù)據(jù)就開始傳輸,進(jìn)入axis2video模塊的fifo,當(dāng)axis2video內(nèi)部fifo滿了以后,會拉低tready,這時候就會反饋到vdma,暫停讀操作,一直等到axis2video模塊的視頻時序輸入數(shù)據(jù)有效信號,這時候視頻開始輸出,axis2video內(nèi)部fifo數(shù)據(jù)減少,axis_mm2s通道開始恢復(fù)傳輸,繼續(xù)從vdma讀出數(shù)據(jù),vdma再通過axi總線從ddr讀取數(shù)據(jù),如此反復(fù),完成ddr數(shù)據(jù)到video數(shù)據(jù)的轉(zhuǎn)換

下面是接口介紹:

接口 介紹
M_AXI_XX axi4總線接口,用來與ddr交互數(shù)據(jù)
M_AXIS_XX , S_AXIS_XX axi stream接口,用來與pl交互數(shù)據(jù)
S_AXI_LITE 控制總線,接到ps的gp口或者寫一個axilite master總線去配置

其他接口不做介紹 。

為什么要用VDMA

在講解VDMA之前,先來探討一下為什么要學(xué)習(xí)和使用VDMA,以明確學(xué)習(xí)目的。由于使用VDMA可以方便地實(shí)現(xiàn)雙緩沖和多緩沖機(jī)制,所以本小節(jié)引入了幀緩存和緩沖機(jī)制的概念。另外,VDMA可以很好地契合Zynq內(nèi)部架構(gòu),縮短開發(fā)周期。再加上VDMA本身能夠高效地實(shí)現(xiàn)數(shù)據(jù)存取,所以在基于Zynq(也包括其他Xilinx FPGA)圖像、視頻處理系統(tǒng)中,VDMA可謂是必不可少的。

什么是幀緩存

幀緩沖存儲器(Frame Buffer):簡稱幀緩存或顯存,它是屏幕所顯示畫面的一個直接映象,又稱為位映射圖(Bit Map)或光柵。幀緩存的每一存儲單元對應(yīng)屏幕上的一個像素,整個幀緩存對應(yīng)一幀圖像。

在開發(fā)者看來,F(xiàn)rameBuffer 是一塊顯示緩存,往顯示緩存中寫入特定格式的數(shù)據(jù)就意味著向屏幕輸出內(nèi)容。所以說FrameBuffer就是一塊畫布,系統(tǒng)在畫布上繪制好畫面之后,就可以通知顯示設(shè)備讀取Frame Buffer進(jìn)行顯示了。

注意,筆者這里所說的Frame Buffer和Linux的Frame Buffer不是同一個概念,這里僅指顯示緩存(畫布)本身,并不是Linux下的一個設(shè)備。

雙緩沖機(jī)制

最早解釋多緩沖區(qū)如何工作的方式,是通過一個現(xiàn)實(shí)生活中的實(shí)例來解釋的。在一個陽光明媚的日子,你想將水池里的水打滿,而又找不到水管的時候,就只能用手邊的木桶來灌滿水池。水桶滿了之后,關(guān)掉水龍頭,將水提到水池旁邊,倒進(jìn)去,然后走回到水龍頭。重復(fù)上述工作,如此往復(fù)直到將水池灌滿。這就類似單緩沖工作過程,當(dāng)你想將木桶里的水倒出的時候,你必須關(guān)掉水龍頭。

現(xiàn)在假設(shè)你用兩個木桶來做上面的工作。你會注滿第一個木桶然后將第二個木桶換到水龍頭下面,這樣,在第二個水桶注滿的時間內(nèi),你就可以將第一個木桶里面的水倒進(jìn)水池里面,當(dāng)你回來的時候,你只需要再將第一個木桶換下第二個注滿水木桶,當(dāng)?shù)谝粋€木桶開始注水的時候你就將第二個木桶里面的水倒進(jìn)水池里面。重復(fù)這個過程直到水池被注滿。很容易看得到用這種技術(shù)注滿水池將會更快,同時也節(jié)省了很多等待木桶被注滿的時間,而這段時間里你什么也做不了,而水龍頭也就不用等待從木桶被注滿到你回來的這段時間了。

當(dāng)你雇傭另外一個人來搬運(yùn)一個被注滿的木桶時,這就有點(diǎn)類似于三個緩沖區(qū)的工作原理。如果將搬運(yùn)木桶的的時間很長,你可以用更多的木桶,雇傭更多的人,這樣水龍頭就會一直開著注滿木桶了。

在計(jì)算機(jī)圖形學(xué)中,雙緩沖是一種畫圖技術(shù),使用這種技術(shù)可以使得畫圖沒有(至少是減少)閃爍、撕裂等不良效果,并減少等待時間。

雙緩沖機(jī)制的原理大概是:所有畫圖操作將它們畫圖的結(jié)果保存在一塊系統(tǒng)內(nèi)存區(qū)域中,這塊區(qū)域通常被稱作“后緩沖區(qū)(back buffer)”,當(dāng)所有的繪圖操作結(jié)束之后,將整塊區(qū)域復(fù)制到顯示內(nèi)存中,這個復(fù)制操作通常要跟顯示器的光棧束同步,以避免撕裂。雙緩沖機(jī)制必須要求有比單緩沖更多的顯示內(nèi)存和CPU消耗時間,因?yàn)椤昂缶彌_區(qū)”需要顯示內(nèi)存,而復(fù)制操作和等待同步需要CPU時間。

基于雙緩沖機(jī)制可以實(shí)現(xiàn)頁交換,頁交換初始狀態(tài)如下圖所示:

如上圖所示,此時由于處于初始狀態(tài),畫圖操作的結(jié)果都在后緩沖區(qū)中,而屏幕上顯示的則是前緩沖區(qū)中的內(nèi)容。此時畫圖操作尚未完成,畫圖操作完成之后,頁轉(zhuǎn)換操作開始執(zhí)行,示意圖如下圖所示:

如上圖所示,畫圖操作結(jié)束,下一個畫圖操作的結(jié)果保存對象指向前緩沖區(qū),屏幕的顯示對象指向后緩沖區(qū),此時前緩沖區(qū)變成實(shí)際意義上的后緩沖區(qū),后緩沖區(qū)變成實(shí)際意義上的前緩沖去,即實(shí)現(xiàn)“頁交換”操作。

有時候也在頁交換鏈中設(shè)置多個“后緩沖區(qū)”,這是就需要多緩沖區(qū)機(jī)制的支持。

Zynq硬件架構(gòu)

在Zynq芯片內(nèi)部,PS和PL是共享DDR控制器的。PS訪問DDR十分簡單,只要操作DDR映射的虛擬地址即可。對于PL而言,要接入DDR,必須通過AXI_HP端口。

Zynq共有四個AXI_HP通道,通道數(shù)據(jù)寬度可以配置為32位或64位,這些接口通過FIFO控制器連接PL到存儲接口上,其中有兩條連接到DDR存儲控制器上,還有一條是連接到雙端口的OCM上的,下圖是AXI_HP訪問DDR和OCM的連接圖。

由上圖可以看出,AXI_HP接口也是遵循AXI協(xié)議的,因此利用VDMA可以直接連接HP端口。除了使用VDMA,當(dāng)然也可以自己開發(fā)出符合AXI協(xié)議的IP,但是綜合考慮設(shè)計(jì)成本,沒太有必要自己實(shí)現(xiàn)。此外,自己實(shí)現(xiàn)的IP功能也不見得比VDMA強(qiáng)大。

VDMA的作用

VDMA數(shù)據(jù)接口可以分為讀、寫通道,用戶可以通過寫通道將AXI-Stream類型的數(shù)據(jù)流寫入DDR3,通過讀通道可以從DDR3讀取數(shù)據(jù),并以AXI-Stream類型的格式輸出。由此可知,VDMA本質(zhì)上是一個數(shù)據(jù)搬運(yùn)IP,為數(shù)據(jù)進(jìn)、出DDR3提供了一種便捷的方案。

將數(shù)據(jù)存入DDR之后,CPU就可以進(jìn)行一些處理(縮放、裁剪等),然后再送至顯示設(shè)備,達(dá)到期望的應(yīng)用目的。當(dāng)然,也可能是簡單地對捕獲的視頻進(jìn)行解析,將數(shù)據(jù)存入幀緩存,以供顯示。

VDMA可以控制多達(dá)32個幀存,并可以自由地進(jìn)行幀存切換,所以就能夠輕松地實(shí)現(xiàn)雙緩沖和多緩沖操作。這也是一個很重要的特性,在后續(xù)進(jìn)行系統(tǒng)設(shè)計(jì)的時候,通常是采用多緩沖的方式實(shí)現(xiàn)顯示。

由以上分析可以發(fā)現(xiàn),在基于Zynq的圖像、視頻處理系統(tǒng)中使用VDMA是十分有必要的。

VDMA概述

AXI VDMA是Xilinx提供的軟核IP,用于將AXI Stream格式的數(shù)據(jù)流轉(zhuǎn)換為Memory Map格式或?qū)emory Map格式的數(shù)據(jù)轉(zhuǎn)換為AXI Stream數(shù)據(jù)流,從而實(shí)現(xiàn)與DDR3進(jìn)行通信。

許多視頻類應(yīng)用都需要幀緩存來處理幀率變化或者進(jìn)行圖像的縮放、裁剪等尺寸變換操作。AXI VDMA設(shè)計(jì)的初衷就是用于高效地實(shí)現(xiàn)AXI4-Stream視頻流接口和AXI4接口之間的數(shù)據(jù)傳輸。

VDMA的關(guān)鍵特性&優(yōu)勢有以下幾點(diǎn):

? 使視頻流能夠高帶寬直接接入內(nèi)存

? 高效的二維DMA操作

? 獨(dú)立的異步讀寫通道操作

? Gen-Lock幀存同步機(jī)制

? 最多支持32個幀存

? 支持視頻格式動態(tài)切換

? 猝發(fā)長度和行緩存深度可調(diào)節(jié)

? 處理器可以控制IP的初始化、狀態(tài)、中斷和管理寄存器

? 基礎(chǔ)AXI流數(shù)據(jù)位寬為8的整數(shù)倍,如8,16,24,32等,最大可達(dá)1024個位

AXI VDMA框圖如下所示。

主要有以下幾種接口類型:

? AXI-lite:PS通過該接口來配置VDMA

? AXI Memory Map write:映射到存儲器寫

? AXI Memory Map read:映射到存儲器讀

? AXI Stream Write(S2MM):AXI Stream視頻流寫入圖像

? AXI Stream Read(MM2S):AXI Stream視頻流讀出圖像

從框圖中可以看出,VDMA主要由控制和狀態(tài)寄存器、數(shù)據(jù)搬運(yùn)模塊、行緩沖這幾部分構(gòu)成。數(shù)據(jù)進(jìn)出DDR要經(jīng)過行緩沖進(jìn)行緩存,然后由數(shù)據(jù)搬運(yùn)模塊寫入或者讀出數(shù)據(jù)。數(shù)據(jù)搬運(yùn)模塊具體如何工作,由相關(guān)寄存器負(fù)責(zé)控制。VDMA的工作狀態(tài)可以通過讀取狀態(tài)寄存器進(jìn)行獲取。

VDMA詳細(xì)介紹

接口

時鐘和復(fù)位

各種總線都有自己的時鐘信號,不用特別說明,需要指出的是,這些時鐘是異步的,并不需要用同一個時鐘。但在設(shè)計(jì)過程中,如無特別需求,可以使用相同的時鐘,以降低設(shè)計(jì)難度。

同步復(fù)位信號axi_resetn,同步時鐘為s_axi_lite_aclk,低電平有效(至少要保持16個時鐘周期的低電平,才能夠生效),有效時復(fù)位整個IP核。

AXI總線相關(guān)信號

  • AXI4-Lite接口(S_AXI_LITE)

  • AXI4讀接口(M_AXI_MM2S)

  • AXI4寫接口(M_AXI_S2MM)

  • AXI4-Stream主接口(M_AXI_MM2S)

  • AXI4-Stream從接口(S_AXI_S2MM)

前綴S_、M_分別表示Slave和Master;后綴MM2S、S2MM說明數(shù)據(jù)流向是從memory map到stream還是從stream到memory map。

視頻同步接口信號

信號名稱 方向 詳細(xì)描述
mm2s_fsync Frame Sync MM2S幀同步輸入。使能該信號后,VDMA操作開始于fsync每個下降沿。該信號至少要持續(xù)一個m_axis_mm2s_aclk時鐘周期
s2mm_fsync Frame Sync S2MM幀同步輸入。使能該信號后,VDMA操作開始于fsync每個下降沿。該信號至少要持續(xù)一個s_axis_s2mm_aclk時鐘周期

GenLock相關(guān)信號

在下一節(jié)將詳細(xì)介紹這些信號的作用和應(yīng)用場合。

信號名稱 方向 詳細(xì)描述
mm2s_frame_ptr_in(5:0) 輸入 輸入的幀編號
mm2s_frame_ptr_out(5:0) 輸出 輸出當(dāng)前幀的編號
s2mm_frame_ptr_in(5:0) 輸入 輸入的幀編號
s2mm_frame_ptr_out(5:0) 輸出 輸出當(dāng)前幀的編號

VDMA幀存格式

在講述寄存器時,需要設(shè)定和顯示(幀存)相關(guān)的參數(shù),為了方便讀者的理解,這里先介紹VDMA數(shù)據(jù)存放框架,如下圖所示,黑色實(shí)線內(nèi)的區(qū)域?yàn)閷?shí)際存儲畫面的幀存。

圖中H_STRIDE代表水平方向上的跨度,H_SIZE表示水平方向數(shù)據(jù)總量,V_SIZE表示豎直方向總共有多少行。

至于幀存內(nèi)部數(shù)據(jù)如何組織,就取決于軟件代碼和硬件邏輯如何匹配了,通常來講,數(shù)據(jù)存放格式為RGB+Alpha或者Alpha+RGB。

讀寫通道工作時序

清晰地理解VDMA讀寫通道的工作時序,對以后的設(shè)計(jì)有很大的幫助,很多設(shè)計(jì)都是根據(jù)本小節(jié)所示的樣例時序設(shè)計(jì)出來的。

讀通道(MM2S)時序

下圖描述了讀通道的時序,5行,每行16字節(jié),跨度為32字節(jié)。

從圖中可以看出:在收到mm2s_fsync信號后,VDMA在m_axi_mm2s_araddr的起始地址處發(fā)出m_axi_mm2s_arvalid信號。M_axi_mm2s_arvalid總共有效5次,分別獲取一幀的5行數(shù)據(jù)。從MM讀取的數(shù)據(jù)存儲在行緩存里,當(dāng)收到來自axi-stream端的m_axis_mm2s_tvalid信號后,將數(shù)據(jù)發(fā)送到axi-stream端。每一行的結(jié)束,axi-stream端會使m_axis_mm2s_tlast有效。

寫通道(S2MM)時序

下圖描述了寫通道的時序,5行,每行16字節(jié),跨度為32字節(jié)。

從圖中可以看出:在收到s2mm_fsync信號后,VDMA發(fā)出s2mm_fsync_out和s_axis_s2mm_tready表明已經(jīng)準(zhǔn)備好接收來自axi-stream端的數(shù)據(jù)。讀取到的數(shù)據(jù)存儲在行緩存里,m_axi_s2mm_awvalid有效后,緊接著有效m_axi_s2mm_wvalid信號,同時將數(shù)據(jù)放至m_axi_s2mm_wdata。

寄存器

VDMA的寄存器如下表所示。所有寄存器都被映射到非緩存內(nèi)存空間。該內(nèi)存空間必須按照AXI字(32位)進(jìn)行對齊,換句話說,寄存器偏移地址至少間隔4個字節(jié)。

寄存器名稱 偏移地址 詳細(xì)描述
MM2S_VDMACR 00h MM2S VDMA控制寄存器
MM2S_VDMASR 04h MM2S VDMA狀態(tài)寄存器
保留 08h~10h N/A
MM2S_REG_INDEX 14h MM2S寄存器索引
保留 18h~24h N/A
PARK_PRT_REG 28h MM2S和S2MM Park指針寄存器
VDMA_VERSION 2Ch VDMA版本寄存器
S2MM_VDMACR 30h S2MM VDMA控制寄存器
S2MM_VDMASR 34h S2MM VDMA狀態(tài)寄存器
保留 38h N/A
S2MM_VDMA_IRQ_MASK 3Ch S2MM錯誤中斷掩碼寄存器
保留 40h N/A
S2MM_REG_INDEX 44h S2MM寄存器索引
保留 48h~4Ch N/A
MM2S_VSIZE 50h MM2S垂直方向顯示大小寄存器
MM2S_HSIZE 54h MM2S水平方向顯示大小寄存器
MM2S_FRMDLY_STRIDE 58h MM2S幀延遲和跨度寄存器
MM2S_START_ADDRESS(1~16) 5Ch~98h MM2S幀存起始地址(1~16)
保留 9Ch N/A
S2MM_VSIZE A0h S2MM垂直方向顯示大小寄存器
S2MM_HSIZE A4h S2MM水平方向顯示大小寄存器
S2MM_FRMDLY_STRIDE A8h S2MM幀延遲和跨度寄存器
S2MM_START_ADDRESS(1~16) ACh~E8h S2MM幀存起始地址(1~16)

所有寄存器字節(jié)序都是小端格式,如下圖所示。

各個寄存器的名稱和大致作用從上表就可以看出,接下來,筆者會詳細(xì)介紹重要寄存器的具體bit的作用。明白了每個bit的作用之后,自然就知道寫入什么值能夠達(dá)到自己的控制目的。

從上表可以看出,寄存器可以分為兩組,分別對應(yīng)MM2S通道和S2MM通道,兩組寄存器的功能是相似的,區(qū)別僅在于偏移地址和所服務(wù)的對象。因此,在學(xué)習(xí)完MM2S通道的所有寄存器之后,只要大致瀏覽一下S2MM通道對應(yīng)的寄存器的關(guān)鍵位即可(個別位不相同),在使用高級功能時,再仔細(xì)查閱VDMA用戶手冊。

MM2S VDMA 控制寄存器(00h)

顧名思義,該寄存器用于控制VDMA,具體可以實(shí)現(xiàn)復(fù)位、使能鎖相同步、設(shè)定幀存切換模式、啟動VDMA讀寫通道等操作。每一位作用如下圖所示,低4位是最重要的,接下來會詳細(xì)介紹。

MM2S VDMA 狀態(tài)寄存器(04h)

該寄存器用于獲取VDMA工作狀態(tài)。每一位作用如下圖所示,低4位是最重要的,接下來會詳細(xì)介紹。

PARK_PTR_REG停留指針寄存器(28h)

該寄存器用于管理讀、寫通道的數(shù)據(jù)傳輸。

學(xué)習(xí)了這個寄存器之后,就可以發(fā)現(xiàn):當(dāng)VDMA工作在Parked模式下,通過操作該寄存器,就能夠?qū)崿F(xiàn)幀緩存的切換,建立自己想要的緩存切換機(jī)制。

MM2S 幀存起始地址(0x5C~0x98)

有最多32個寄存器用于存放幀存起始地址,其分別存在于兩個寄存器bank上:bank0和bank1,每個bank上有16個寄存器。這兩個bank上有相同的起始偏移地址(0x5C),選擇這兩個bank可以通過MM2S_REG_INDEX的值進(jìn)行選擇。假如想訪問第1個寄存器,則給MM2S_REG_INDEX賦值為0,并設(shè)定偏移地址為0x5C;如果想訪問第17個寄存器,需要將MM2S_REG_INDEX設(shè)為1,并設(shè)定初始偏移地址為0x5C。

MM2S_FRMDLY_STRIDE MM2S幀延遲和跨度(58h)

該寄存器有兩個作用,第一是bit24~bit28指定幀延遲,僅用于Genlock從模式,指定從接口比主接口至少要延遲多少個幀;第二是低16位指定水平方向的跨度,同樣以字節(jié)為單位。所謂跨度是指每兩行第一個像素之間間隔的數(shù)據(jù)個數(shù),具體請參考22.3.2小節(jié),VDMA幀存格式。

MM2S_HSIZE MM2S水平方向尺寸(54h)

該寄存器的低16位用于指定每一行有多少字節(jié)的數(shù)據(jù)需要傳輸。例如顯示分辨率為640480,每個像素4個字節(jié)(RGB+Alpha),該值應(yīng)該設(shè)定為6404。

MM2S_VSIZE MM2S垂直方向尺寸(50h)

該寄存器有兩個作用,第一是用低13位指定總共有多少行;第二是啟動MM2S的傳輸。當(dāng)MM2S_VDMACR.RS=1,對該寄存器的寫操作會將所有設(shè)定參數(shù)傳遞給VDMA內(nèi)部寄存器模塊,用于VDMA控制。對某個通道進(jìn)行配置時,必須在最后一步設(shè)置該寄存器。

S2MM VDMA 控制寄存器(30h)

顧名思義,該寄存器用于控制VDMA S2MM通道,具體可以實(shí)現(xiàn)復(fù)位、使能鎖相同步、設(shè)定幀存切換模式、啟動VDMA讀寫通道等操作。每一位作用如下圖所示,低4位是最重要的,接下來會詳細(xì)介紹。

S2MM VDMA 狀態(tài)寄存器(34h)

該寄存器用于獲取S2MM工作狀態(tài)。每一位作用如下圖所示,低4位是最重要的,接下來會詳細(xì)介紹。

S2MM 幀存起始地址(0xAC~0xE8)

有最多32個寄存器用于存放幀存起始地址,其分別存在于兩個寄存器bank上:bank0和bank1,每個bank上有16個寄存器。這兩個bank上有相同的起始偏移地址(0x5C),選擇這兩個bank可以通過S2MM_REG_INDEX的值進(jìn)行選擇。假如想訪問第1個寄存器,則給S2MM_REG_INDEX賦值為0,并設(shè)定偏移地址為0x5C;如果想訪問第17個寄存器,需要將MM2S_REG_INDEX設(shè)為1,并設(shè)定初始偏移地址為0x5C。

S2MM_FRMDLY_STRIDE S2MM幀延遲和跨度(A8h)

該寄存器有兩個作用,第一是bit24~bit28指定幀延遲,僅用于Genlock從模式,指定從接口比主接口至少要延遲多少個幀;第二是低16位指定水平方向的跨度,同樣以字節(jié)為單位。所謂跨度是指每兩行第一個像素之間間隔的數(shù)據(jù)個數(shù),具體請參考22.3.2小節(jié),VDMA幀存格式。

S2MM_HSIZE S2MM水平方向尺寸(A4h)

該寄存器的低16位用于指定每一行有多少字節(jié)的數(shù)據(jù)需要傳輸。例如顯示分辨率為640480,每個像素4個字節(jié)(RGB+Alpha),該值應(yīng)該設(shè)定為6404。

S2MM_VSIZE S2MM垂直方向尺寸(A0h)

該寄存器有兩個作用,第一是用低13位指定總共有多少行;第二是啟動S2MM的傳輸。當(dāng)S2MM_VDMACR.RS=1,對該寄存器的寫操作會將所有設(shè)定參數(shù)傳遞給VDMA內(nèi)部寄存器模塊,用于VDMA控制。對某個通道進(jìn)行配置時,必須在最后一步設(shè)置該寄存器。

幀同步選項(xiàng)

VDMA支持以下三種幀同步源:

? 基于AXI4-Stream的幀同步(使用tuser(0)信號)

? 讀通道使用m_axis_mm2s_tuser(0)作為幀起始信號

? 寫通道使用s_axis_s2mm_tuser(0)作為幀起始信號

? S2MM幀同步(s2mm_fsync)

? MM2S幀同步(mm2s_fsync)

Genlock同步機(jī)制

什么是Genlock?

Genlock,同步鎖相,可以使一套或多套系統(tǒng)與同一同步源實(shí)現(xiàn)同步。能夠使視頻的刷新和外部視頻源保持一致。當(dāng)提供了一個適當(dāng)?shù)男盘柡?,系統(tǒng)就會把它的顯示刷新率和這個信號進(jìn)行鎖定 。

在許多視頻應(yīng)用中,輸入端產(chǎn)生數(shù)據(jù)的速率往往不同于輸出端數(shù)據(jù)速率,為了避免由速率不一致導(dǎo)致的潛在錯誤,幀緩沖的使用是很有必要的。幀緩沖機(jī)制開辟多個緩沖頁,用于保存數(shù)據(jù),輸入和輸出端分別操作不同的幀存,從而避免了沖突。

VDMA的鎖相同步特性正是用于阻止讀、寫通道同時操作同一個幀存。VDMA的每個通道都可以選擇自己的操作類型(同步鎖相主/從或者動態(tài)同步鎖相主/從),利用該特性,禁止主從接口同時訪問同一緩存,從而保持同步。

VDMA支持四種模式的鎖相同步,分別為:

? Genlock Master(鎖相同步主端)

? Genlock Slave(鎖相同步從端)

? Dynamic Genlock Master(動態(tài)鎖相同步主端)

? Dynamic Genlock Slave(動態(tài)鎖相同步從端)

Genlock Master

讀通道(MM2S):當(dāng)配置為Genlock Master時,該通道不會跳過或者重復(fù)任一幀數(shù)據(jù),并把當(dāng)前幀的編號輸出在mm2s_frame_ptr_out端口。通道不會檢測mm2s_frame_ptr_in端口提供的幀編號。Genlock Slave通道應(yīng)跟隨Genlock Master通道變化,但有一定的延遲。延遲大小預(yù)定義在寄存器中(*frmdly_stride[28:24])。

寫通道(S2MM):當(dāng)配置為Genlock Master時,該通道不會跳過或者重復(fù)任一幀數(shù)據(jù),并把當(dāng)前幀的編號輸出到s2mm_frame_ptr_out端口。通道不會檢測s2mm_frame_ptr_in端口提供的幀編號。Genlock Slave通道應(yīng)跟隨Genlock Master通道變化,但有一定的延遲。延遲大小預(yù)定義在寄存器中(*frmdly_stride[28:24])。

Genlock Slave

讀通道(MM2S):當(dāng)配置為Genlock Slave時,該通道會通過跳過或者重復(fù)一些幀的方式,嘗試與Genlock Master同步。通道會對mm2s_frame_ptr_in端口進(jìn)行采樣,獲取Genlock Master的幀編號。為了實(shí)現(xiàn)狀態(tài)反饋,通道會把當(dāng)前幀的編號輸出到mm2s_frame_ptr_out端口。

指定通道工作在Genlock Slave模式,必須進(jìn)行如下操作。

? 將GenlockEn置1(MM2S_VDMACR[3]=1),使能主、從通道之間的Genlock同步。

? 將GenlockSrc置1(MM2S_VDMACR[7]=1),使能內(nèi)部Genlock模式。如果在Vivado IDE中同時使能讀、寫通道,該位默認(rèn)置位。當(dāng)GenlockSRC=1時,VDMA默認(rèn)支持內(nèi)部同步鎖相總線。這樣一來就沒有必要在外部對幀指針端口(frame_ptr_out和_frame_ptr_in)進(jìn)行連接了。

? 根據(jù)主從通道的幀率,使用mm2s_frmdly_stride[28:24]設(shè)定合適的延遲時間。

寫通道(S2MM):當(dāng)配置為Genlock Slave時,該通道會通過跳過或者重復(fù)一些幀的方式,嘗試與Genlock Master同步。通道會對s2mm_frame_ptr_in端口進(jìn)行采樣,獲取Genlock Master的幀編號。為了實(shí)現(xiàn)狀態(tài)反饋,通道會把當(dāng)前幀的編號輸出到s2mm_frame_ptr_out端口。

指定通道工作在Genlock Slave模式,必須進(jìn)行如下操作。

? 將GenlockEn置1(S2MM_VDMACR[3]=1),使能主、從通道之間的Genlock同步。

? 將GenlockSrc置1(S2MM_VDMACR[7]=1),使能內(nèi)部Genlock模式。如果在Vivado IDE中同時使能讀、寫通道,該位默認(rèn)置位。當(dāng)GenlockSRC=1時,VDMA默認(rèn)支持內(nèi)部同步鎖相總線。這樣一來就沒有必要在外部對幀指針端口(frame_ptr_out和_frame_ptr_in)進(jìn)行連接了。

? 根據(jù)主從通道的幀率,使用mm2s_frmdly_stride[28:24]設(shè)定合適的延遲時間。

Dynamic Genlock Master

動態(tài)Genlock Master與Genlock Master的區(qū)別在于,主通道會跳過從通道正在操作的幀。舉例而言,對于三幀存而言,動態(tài)Genlock Master會按照0,1,2,0,1,2的順序循環(huán)使用幀存,一旦檢測到Master即將操作Slave正在操作的幀,就會跳過該幀繼續(xù)循環(huán)。因此,如果Slave通道一直在操作幀存1,那么Master通道就會在幀0和幀2之間來回切換。

Dynamic Genlock Slave

Dynamic Genlock Slave通道會操作Dynamic Genlock Master通道上一周期操作的幀。

下圖描述了一種簡單的Genlock操作時序。在這個示例中,S2MM通道是Genlock Master,MM2S通道是Genlock Slave,并且寫通道幀率高于讀通道幀率。

由于讀通道幀率慢于寫通道,所以讀通道僅處理幀2和幀0,跳過幀1不做處理。

軟件控制流程

以下步驟是最簡單的VDMA控制初始化操作。

? 寫VDMACR寄存器,將VDMACR.RS設(shè)為1,啟動VDMA通道。

? 設(shè)定有效的幀緩存起始地址。

? 設(shè)定幀延遲(僅針對Genlock從模式)以及跨度到FRMDLY_STRIDE寄存器。

? 設(shè)定水平方向字節(jié)數(shù)到HSIZE寄存器。

? 設(shè)定豎直方向行數(shù)到VSIZE寄存器。啟動通道的數(shù)據(jù)傳輸。

在VDMA運(yùn)行過程中,可以動態(tài)的進(jìn)行顯示參數(shù)配置,但是需要注意的是,想要使參數(shù)生效,必須在設(shè)置的最后一步,對VSIZE寄存器進(jìn)行寫操作。

最后,給出一段通過VDMA對DDR讀寫傳輸?shù)倪M(jìn)行初始化的示例代碼:

//VDMA configurateAXI VDMA0

/*****************從DDR讀數(shù)據(jù)設(shè)置**********************/

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x0, 0x4); //reset

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x0, 0x8); //gen-lock

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x5C, 0x08000000);

//  AXI4 Data Width為32位,是4個字節(jié)數(shù)

//  0x0A000000   0x0015F900

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x5C+4, 0x0A000000);

//   0x09000000  0x002BF200

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x5C+8, 0x09000000);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x54, 640);// 640

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x58, 0x01000280);

//   第0位: 運(yùn)行 - 啟動VDMA操作,在運(yùn)行VDMA時,其狀態(tài)寄存器中的停止位賦值為0      第一位:循環(huán)模式 -通過連續(xù)循環(huán)幀緩沖

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x0, 0x03);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x50, 480);//480

/***********  寫入DDR設(shè)置*************************/

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x30, 0x4); //reset

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x30, 0x8); //genlock

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0xAC, 0x08000000);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0xAC+4, 0x0A000000);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0xAC+8, 0x09000000);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0xA4, 640);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0xA8, 0x01000280);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0x30, 0x03);

XAxiVdma_WriteReg(XPAR_AXIVDMA_0_BASEADDR, 0xA0, 480);

搭建VDMA圖像系統(tǒng)

構(gòu)架方案圖

可以看到VMDA的圖像系統(tǒng)和前面介紹的DMA系統(tǒng)相比非常類似。實(shí)際上他們都是屬于DMA系統(tǒng),只是VDMA在配置完成后,可以無需依賴CPU可以獨(dú)立運(yùn)行,有點(diǎn)類似顯卡的功能了。

構(gòu)BLOCK模塊化設(shè)計(jì)方案圖

PS部分

main函數(shù)

本課程提供了二種方式啟動VDMA,第一種是通過庫函數(shù)版本,第二種是通過寄存器版本。寄存器版本主要是驗(yàn)證我們對VDMA的寄存器掌握情況。庫函數(shù)具備更強(qiáng)的功能,和可維護(hù)性。

 #include "sys_intr.h" #include "xaxivdma.h" #include "xaxivdma_i.h" #define VTC_BASEADDR XPAR_MIZ702_VTG_VGA_0_BASEADDR #define DDR_BASEADDR        0x00000000 //#define UART_BASEADDR       0xe0001000 #define VDMA_BASEADDR       XPAR_AXI_VDMA_0_BASEADDR #define H_STRIDE            640 #define H_ACTIVE            640 #define V_ACTIVE            480 #define pi 3.14159265358 #define COUNTS_PER_SECOND (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ)/64 #define VIDEO_LENGTH  (H_STRIDE*V_ACTIVE) #define VIDEO_BASEADDR0 DDR_BASEADDR + 0x2000000 #define VIDEO_BASEADDR1 DDR_BASEADDR + 0x3000000 #define VIDEO_BASEADDR2 DDR_BASEADDR + 0x4000000 u32 *BufferPtr[3];

unsigned int srcBuffer = (XPAR_PS7_DDR_0_S_AXI_BASEADDR  + 0x1000000);

int run_triple_frame_buffer(XAxiVdma* InstancePtr, int DeviceId, int hsize,

int vsize, int buf_base_addr, int number_frame_count,

int enable_frm_cnt_intr);

int main(void)

{

u32 Status;

Miz702_EMIO_init();

ov7725_init_rgb();

XAxiVdma InstancePtr;

xil_printf("Starting the first VDMA \n\r");

Status = run_triple_frame_buffer(&InstancePtr, 0, 640, 480,

srcBuffer, 2, 0); if (Status != XST_SUCCESS) {

xil_printf("Transfer of frames failed with error = %d\r\n",Status); return XST_FAILURE;

} else {

xil_printf("Transfer of frames started \r\n");

} print("TEST PASS\r\n");

//VDMA configurateAXI VDMA0

/****************往DDR寫數(shù)據(jù)設(shè)置**********************/

/*Xil_Out32((VDMA_BASEADDR + 0x030), 0x00000003);// enable circular mode

Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2); // start address

Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*4)); // h offset (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*4)); // h size (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE);*/ // v size (480)

/*****************從DDR讀數(shù)據(jù)設(shè)置**********************/

/*Xil_Out32((VDMA_BASEADDR + 0x000), 0x00000003); // enable circular mode

Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2); // start address

Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4)); // h offset (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4)); // h size (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); // v size (480)

*/ while (1) ; return XST_SUCCESS;

}

vdma_api.c函數(shù)

XAxiVdma_LookupConfig函數(shù)是XILINX 庫函數(shù)的標(biāo)準(zhǔn)調(diào)用方式,可以獲取到硬件的默認(rèn)配置參數(shù)。默認(rèn)的配置參數(shù)保存在 參數(shù)表XAxiVdma_ConfigTable 中。

表6-6-2-1 XAxiVdma_LookupConfig

/*****************************************************************************/

/**

* Look up the hardware configuration for a device instance

*

* @param DeviceId is the unique device ID of the device to lookup for *

* @return * The configuration structure for the device. If the device ID is not found,

* a NULL pointer is returned.

*

******************************************************************************/

XAxiVdma_Config *XAxiVdma_LookupConfig(u16 DeviceId)

{

extern XAxiVdma_Config XAxiVdma_ConfigTable[];

XAxiVdma_Config *CfgPtr = NULL;

int i; for (i = 0; i < XPAR_XAXIVDMA_NUM_INSTANCES; i++) { if (XAxiVdma_ConfigTable[i].DeviceId == DeviceId) {

CfgPtr = &XAxiVdma_ConfigTable[i]; break;

}

} return CfgPtr;

}

表6-6-2-2 XAxiVdma_ConfigTable參數(shù)表

XAxiVdma_Config XAxiVdma_ConfigTable[] =

{

{

XPAR_AXI_VDMA_0_DEVICE_ID,

XPAR_AXI_VDMA_0_BASEADDR,

XPAR_AXI_VDMA_0_NUM_FSTORES,

XPAR_AXI_VDMA_0_INCLUDE_MM2S,

XPAR_AXI_VDMA_0_INCLUDE_MM2S_DRE,

XPAR_AXI_VDMA_0_M_AXI_MM2S_DATA_WIDTH,

XPAR_AXI_VDMA_0_INCLUDE_S2MM,

XPAR_AXI_VDMA_0_INCLUDE_S2MM_DRE,

XPAR_AXI_VDMA_0_M_AXI_S2MM_DATA_WIDTH,

XPAR_AXI_VDMA_0_INCLUDE_SG,

XPAR_AXI_VDMA_0_ENABLE_VIDPRMTR_READS,

XPAR_AXI_VDMA_0_USE_FSYNC,

XPAR_AXI_VDMA_0_FLUSH_ON_FSYNC,

XPAR_AXI_VDMA_0_MM2S_LINEBUFFER_DEPTH,

XPAR_AXI_VDMA_0_S2MM_LINEBUFFER_DEPTH,

XPAR_AXI_VDMA_0_MM2S_GENLOCK_MODE,

XPAR_AXI_VDMA_0_S2MM_GENLOCK_MODE,

XPAR_AXI_VDMA_0_INCLUDE_INTERNAL_GENLOCK,

XPAR_AXI_VDMA_0_S2MM_SOF_ENABLE,

XPAR_AXI_VDMA_0_M_AXIS_MM2S_TDATA_WIDTH,

XPAR_AXI_VDMA_0_S_AXIS_S2MM_TDATA_WIDTH,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_1,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_5,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_6,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_7,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_9,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_13,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_14,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_INFO_15,

XPAR_AXI_VDMA_0_ENABLE_DEBUG_ALL,

XPAR_AXI_VDMA_0_ADDR_WIDTH

}

};

WriteSetup VDMA寫通道設(shè)置,主要設(shè)置分辨率,延遲參數(shù),開啟CircularBuf 模式,使能Gen-Lock。更底層的分析讀者可以順藤摸瓜下去。

表6-6-2-3 WriteSetup

/*****************************************************************************/

/**

*

* This function sets up the write channel

*

* @param dma_context is the context pointer to the VDMA engine..

*

* @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise.

*

* @note None.

*

******************************************************************************/

static int WriteSetup(vdma_handle *vdma_context)

{

int Index;

u32 Addr;

int Status;

vdma_context->WriteCfg.VertSizeInput = vdma_context->vsize;

vdma_context->WriteCfg.HoriSizeInput = vdma_context->hsize;

vdma_context->WriteCfg.Stride = vdma_context->hsize;

vdma_context->WriteCfg.FrameDelay = 0;  /* This example does not test frame delay */

vdma_context->WriteCfg.EnableCircularBuf = 1;

vdma_context->WriteCfg.EnableSync = 1;  /*  Gen-Lock */

vdma_context->WriteCfg.PointNum = 0;

vdma_context->WriteCfg.EnableFrameCounter = 0; /* Endless transfers */

vdma_context->WriteCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */

/* Configure the VDMA is per fixed configuration, This configuration

* is being used by majority of customers. Expert users can play around

* with this if they have different configurations

*/

Status = XAxiVdma_DmaConfig(vdma_context->InstancePtr, XAXIVDMA_WRITE, &vdma_context->WriteCfg); if (Status != XST_SUCCESS) {

xil_printf( "Write channel config failed %d\r\n", Status); return Status;

}

/* Initialize buffer addresses

*

* Use physical addresses

*/

Addr = vdma_context->buffer_address;

/* If Debug mode is enabled write frame is shifted 3 Frames

* store ahead to compare read and write frames

*/ #if DEBUG_MODE Addr = Addr + vdma_context->InstancePtr->MaxNumFrames * \

(vdma_context->WriteCfg.Stride * vdma_context->vsize); #endif for(Index = 0; Index < vdma_context->InstancePtr->MaxNumFrames; Index++) {

vdma_context->WriteCfg.FrameStoreStartAddr[Index] = Addr; #if DEBUG_MODE xil_printf("Write Buffer %d address: 0x%x \r\n",Index,Addr); #endif Addr += (vdma_context->hsize * vdma_context->vsize);

}

/* Set the buffer addresses for transfer in the DMA engine */

Status = XAxiVdma_DmaSetBufferAddr(vdma_context->InstancePtr,

XAXIVDMA_WRITE,

vdma_context->WriteCfg.FrameStoreStartAddr); if (Status != XST_SUCCESS) {

xil_printf("Write channel set buffer address failed %d\r\n",

Status); return XST_FAILURE;

}

/* Clear data buffer

*/ #if DEBUG_MODE memset((void *)vdma_context->buffer_address, 0,

vdma_context->ReadCfg.Stride * vdma_context->ReadCfg.VertSizeInput * vdma_context->InstancePtr->MaxNumFrames); #endif return XST_SUCCESS;

}

ReadSetup VDMA讀通道設(shè)置,主要設(shè)置分辨率,這里的延遲參數(shù)1,否則圖像會有卡頓,開啟CircularBuf 模式,使能Gen-Lock。更底層的分析讀者可以順藤摸瓜下去。

表6-6-2-4 ReadSetup

/*****************************************************************************/

/**

*

* This function sets up the read channel

*

* @param vdma_context is the context pointer to the VDMA engine.

*

* @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise.

*

* @note None.

*

******************************************************************************/

static int ReadSetup(vdma_handle *vdma_context)

{

int Index;

u32 Addr;

int Status;

vdma_context->ReadCfg.VertSizeInput = vdma_context->vsize;

vdma_context->ReadCfg.HoriSizeInput = vdma_context->hsize;

vdma_context->ReadCfg.Stride = vdma_context->hsize;

vdma_context->ReadCfg.FrameDelay = 0;  /* This example does not test frame delay */

vdma_context->ReadCfg.EnableCircularBuf = 1;

vdma_context->ReadCfg.EnableSync = 1;  /* Gen-Lock */

vdma_context->ReadCfg.PointNum = 0;

vdma_context->ReadCfg.EnableFrameCounter = 0; /* Endless transfers */

vdma_context->ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */

/* Configure the VDMA is per fixed configuration, This configuration is being used by majority

* of customer. Expert users can play around with this if they have different configurations */

Status = XAxiVdma_DmaConfig(vdma_context->InstancePtr, XAXIVDMA_READ, &vdma_context->ReadCfg); if (Status != XST_SUCCESS) {

xil_printf("Read channel config failed %d\r\n", Status); return XST_FAILURE;

}

/* Initialize buffer addresses

*

* These addresses are physical addresses

*/

Addr = vdma_context->buffer_address; for(Index = 0; Index < vdma_context->InstancePtr->MaxNumFrames; Index++) {

vdma_context->ReadCfg.FrameStoreStartAddr[Index] = Addr;

/* Initializing the buffer in case of Debug mode */ #if DEBUG_MODE {

u32 i;

u8 *src;

u32 total_pixel = vdma_context->ReadCfg.Stride * vdma_context->vsize;

src = (unsigned char *)Addr;

xil_printf("Read Buffer %d address: 0x%x \r\n",Index,Addr); for(i=0;i#endif Addr +=  vdma_context->hsize * vdma_context->vsize;

}

/* Set the buffer addresses for transfer in the DMA engine

* The buffer addresses are physical addresses

*/

Status = XAxiVdma_DmaSetBufferAddr(vdma_context->InstancePtr, XAXIVDMA_READ,

vdma_context->ReadCfg.FrameStoreStartAddr); if (Status != XST_SUCCESS) {

xil_printf( "Read channel set buffer address failed %d\r\n", Status); return XST_FAILURE;

} return XST_SUCCESS;

}

		

StartTransfer 啟動VDMA讀寫通道

表6-6-2-5 StartTransfer

/*****************************************************************************/

/**

*

* This function starts the DMA transfers. Since the DMA engine is operating

* in circular buffer mode, video frames will be transferred continuously.

*

* @param InstancePtr points to the DMA engine instance

*

* @return * - XST_SUCCESS if both read and write start successfully

* - XST_FAILURE if one or both directions cannot be started

*

* @note None.

*

******************************************************************************/

static int StartTransfer(XAxiVdma *InstancePtr)

{

int Status;

/* Start the write channel of VDMA */

Status = XAxiVdma_DmaStart(InstancePtr, XAXIVDMA_WRITE); if (Status != XST_SUCCESS) {

xil_printf("Start Write transfer failed %d\r\n", Status); return XST_FAILURE;

}

/* Start the Read channel of VDMA */

Status = XAxiVdma_DmaStart(InstancePtr, XAXIVDMA_READ); if (Status != XST_SUCCESS) {

xil_printf("Start read transfer failed %d\r\n", Status); return XST_FAILURE;

} return XST_SUCCESS;

}

測試結(jié)果

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉