MiZ702學習筆記13——ZYNQ通過AXI-Lite與PL交互


在《MiZ702學習筆記7——嘗試自制帶總線IP》,我曾提到了AXI4-Lite的簡單用法,驅動了下流水燈,只涉及到了寫總線。今天,我想利用之前的VGA模塊,將AXI4-Lite的讀寫都應用上。這篇文章主要是思想的介紹,以及AXI4-Lite讀的方法。一些細節請先閱讀《MiZ702學習筆記7——嘗試自制帶總線IP》。

具體思路為如下框圖所示:

clip_image002

所以這次,我們需要兩條AXI4-Lite總線,一條負責給VGA模塊提供RGB數據(寫),一條讀取VGA模塊提供的掃描的坐標信息(讀)。

點擊下圖中的加號,就能為我們額外的添加一條AXI4-Lite總線:

clip_image004

因此在我們的IP工程里可以看到兩套總線框架:

clip_image006

IP打包好之后是這個樣子:

clip_image008

我們將S00這條總線作為寫數據用,將S01作為讀數據總線。當然一條總線是既可以讀也可以寫的,但是VGA這個工程決定了讀和寫必須是同行進行的不可復用。

其他的就和之前講到一樣了,接下來AXI4-Lite的讀和寫。PL為了和PS通訊,是需要一些邏輯去支持的。而這些邏輯在我們生成AXI4-Lite IP的時候,vivado就幫我們自動生成了。我們要做的部分很少,只需要增改一些內容即可,就如《MiZ702學習筆記7——嘗試自制帶總線IP》提到的那樣。

這個工程中,對於總線的寫而言就是給VGA模塊送去RGB數據,“寫”我們只需要增加自己的邏輯即可:

reg [11:0]rlcd_rgb;

always @( posedge S_AXI_ACLK )

begin

if ( S_AXI_ARESETN == 1'b0 )

begin

rlcd_rgb <= 12'd0;

end

else

begin

rlcd_rgb <= S_AXI_WDATA[11:0];

end

end

assign lcd_rgb = rlcd_rgb;

對於總線的讀而言,我們需要將框架進行稍微的改動:

//寫總線測試修改!!!!!!!!!

wire[31:0]wlcd_xy;// = {10'd0,lcd_xy};

assign wlcd_xy = {10'd0,lcd_xy};

assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

always @(*)

begin

// Address decoding for reading registers

case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

2'h0 : reg_data_out <= wlcd_xy;//slv_reg0;

2'h1 : reg_data_out <= slv_reg1;

2'h2 : reg_data_out <= slv_reg2;

2'h3 : reg_data_out <= slv_reg3;

default : reg_data_out <= 0;

endcase

end

這里其實,也就改了一個地方,本來是reg_data_out <= slv_reg0;被我改成了reg_data_out <= wlcd_xy;這樣就能通過總線讀取wlcd_xy的值了。

在回到這張框架圖:

clip_image002[1]

到這了,我們的AXI IP已經具備了和ZYNQ以及VGA交互的能力,它就是PS和PL之間的橋梁,現在我們只差一個VGA IP,而這個IP就是個普通IP,沒錯就是《MiZ702學習筆記12——封裝一個普通的VGA IP》講的那樣,我們將程序稍加修改,在進行IP打包,就能得到。

最后,我們分別添加這幾個IP,進行連線就完成了硬件的搭建。其實我提一些細節。

我們配置下ZNYQ的輸出時鍾:

clip_image010

其中FCLK0一般添加zynq核時是默認引出的,這里主要是給AXI4-Lite IP提供時鍾,大小我設置是250M,再高就提示出錯了。

FCLK1將其設置為25M,主要給VGA IP提供時鍾,應為VGA掃描是25M。

硬件平台准備好之后,就可以開始SDK的編程了。首先,我們得根據地址訪問到AXI4-Lite IP,通過xparameter.h這個頭文件可以得知S00這條總線的地址:

/* Definitions for driver MYVGAIP */

#define XPAR_MYVGAIP_NUM_INSTANCES 1

/* Definitions for peripheral MYVGAIP_0 */

#define XPAR_MYVGAIP_0_DEVICE_ID 0

#define XPAR_MYVGAIP_0_S00_AXI_BASEADDR 0x43C00000

#define XPAR_MYVGAIP_0_S00_AXI_HIGHADDR 0x43C0FFFF

但是頭文件並未看到S01這條總線的地址,不過可以猜想,S00總線寬帶是32位的,且首地址是0x43C00000,那么如果地址是連續的總線S01的首地址應該就是0x43C1ffff。

通過查看system.hdf可以確定以上推測是正確的:

clip_image012

於是定義如下:

#define RGB_AXI_BASEADDR 0x43C00000

#define LCDXY_AXI_BASEADDR 0x43C10000

首先進行彩條的測試,先通過Xil_In32,這個函數讀總線,得到VGA模塊輸出的坐標值。其中低11位是Y坐標的值,高11位是X坐標的值:

temp = Xil_In32(LCDXY_AXI_BASEADDR);

lcd_ypos = temp & 0x7ff;

lcd_xpos = (temp>>11) & 0x7ff;

就可以測試橫向彩條:

//橫向彩條

if (lcd_ypos >= 0 && lcd_ypos < (V_DISP/8)*1)

Xil_Out32(RGB_AXI_BASEADDR, RED);

else if(lcd_ypos >= (V_DISP/8)*1 && lcd_ypos < (V_DISP/8)*2)

Xil_Out32(RGB_AXI_BASEADDR, GREEN);

else if(lcd_ypos >= (V_DISP/8)*2 && lcd_ypos < (V_DISP/8)*3)

Xil_Out32(RGB_AXI_BASEADDR, BLUE);

else if(lcd_ypos >= (V_DISP/8)*3 && lcd_ypos < (V_DISP/8)*4)

Xil_Out32(RGB_AXI_BASEADDR, WHITE);

else if(lcd_ypos >= (V_DISP/8)*4 && lcd_ypos < (V_DISP/8)*5)

Xil_Out32(RGB_AXI_BASEADDR, BLACK);

else if(lcd_ypos >= (V_DISP/8)*5 && lcd_ypos < (V_DISP/8)*6)

Xil_Out32(RGB_AXI_BASEADDR, YELLOW);

else if(lcd_ypos >= (V_DISP/8)*6 && lcd_ypos < (V_DISP/8)*7)

Xil_Out32(RGB_AXI_BASEADDR, CYAN);

else if(lcd_ypos >= (V_DISP/8)*7 && lcd_ypos < (V_DISP/8)*8)

Xil_Out32(RGB_AXI_BASEADDR, ROYAL);

結果和想象中一樣完美~~~

接下來測試,總線彩條:

//豎向掃描有點問題,

if (lcd_xpos >= 0 && lcd_xpos < (H_DISP/8)*1)

Xil_Out32(RGB_AXI_BASEADDR, RED);

else if(lcd_xpos >= (H_DISP/8)*1 && lcd_xpos < (H_DISP/8)*2)

Xil_Out32(RGB_AXI_BASEADDR, GREEN);

else if(lcd_xpos >= (H_DISP/8)*2 && lcd_xpos < (H_DISP/8)*3)

Xil_Out32(RGB_AXI_BASEADDR, BLUE);

else if(lcd_xpos >= (H_DISP/8)*3 && lcd_xpos < (H_DISP/8)*4)

Xil_Out32(RGB_AXI_BASEADDR, WHITE);

else if(lcd_xpos >= (H_DISP/8)*4 && lcd_xpos < (H_DISP/8)*5)

Xil_Out32(RGB_AXI_BASEADDR, BLACK);

else if(lcd_xpos >= (H_DISP/8)*5 && lcd_xpos < (H_DISP/8)*6)

Xil_Out32(RGB_AXI_BASEADDR, YELLOW);

else if(lcd_xpos >= (H_DISP/8)*6 && lcd_xpos < (H_DISP/8)*7)

Xil_Out32(RGB_AXI_BASEADDR, CYAN);

else

Xil_Out32(RGB_AXI_BASEADDR, ROYAL);

結果就不想想象中那么完美了:

clip_image014

我們發現彩條的邊緣有鋸齒,這是為什么呢?原因是橫向彩條的掃描依據是lcd_ypos的值,縱向彩條的掃描依據是lcd_xpos。而VGA掃描是水平掃描,這意味着X的更新頻率是Y更新頻率的N倍。

也就是說AXI4-Lite的讀寫速度跟上了lcd_ypos的變化,卻沒能完全跟上lcd_xpos的值。

有的讀者可能要發問了,之前給AXI4-Lite IP提供了250M的時鍾嗎,而VGA掃描才25M,怎么可能速度上跟不上?

這只能說AXI4-Lite本身,並不適合做大量傳輸數據這件事。AXI4-Lite只適合做一些簡單的IO控制,配置寄存器用。

還記得在選擇總線類型的時候嗎?

clip_image016

我們選擇的是Lite,其實還有其他類型可選,如:AXI4,以及AXIStream類型。這些就是我們接下來的任務了。

最近,路飛開4檔了,實在太帥了,我最終的目的本來是想將他顯示在VGA上的,奈何一開始選錯了總線類型,只能將就着看了:

clip_image018

總結:

雖然最終的結果不算成功,但是過程還是能學到不少東西,這里例子可以很好的體現ZYNQ的優勢:

1、利用PL部分驅動VGA,充分的發揮FPGA的優勢。為PS分擔的不小的任務。

2、利用PS完成數據的提供,數據方便存儲,且更加多變,正好彌補了FPGA這方面的缺點。

接下來的教程里,就開始探究AXI4以及AXIStream,必將完善次項目,就到這里吧。東莞今天居然下雪了,不說了拿電吹風取暖去了。明天回家了,祝我一路順風吧~~

工程文件,待會上傳~~~


免責聲明!

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



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