? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??ZYNQ 、AXI協(xié)議、PS與PL內部通信?
三種AXI總線分別為:
AXI4:(For high-performance memory-mapped requirements.)主要面向高性能地址映射通信的需求,是面向地址映射的接口,允許最大256輪的數據突發(fā)傳輸;
AXI4-Lite:(For simple, low-throughput memory-mapped communication )是一個輕量級的地址映射單次傳輸接口,占用很少的邏輯單元。
AXI4-Stream:(For high-speed streaming data.)面向高速流數據傳輸;去掉了地址項,允許無限制的數據突發(fā)傳輸規(guī)模。
AXI4總線和AXI4-Lite總線具有相同的組成部分:
(1)讀地址通道,包含ARVALID, ARADDR, ARREADY信號;
(2)讀數據通道,包含RVALID, RDATA, RREADY, RRESP信號;
(3)寫地址通道,包含AWVALID,AWADDR, AWREADY信號;
(4)寫數據通道,包含WVALID, WDATA,WSTRB, WREADY信號;
(5)寫應答通道,包含BVALID, BRESP, BREADY信號;
(6)系統(tǒng)通道,包含:ACLK,ARESETN信號。
AXI4-Stream總線的組成:
(1)ACLK信號:總線時鐘,上升沿有效;
(2)ARESETN信號:總線復位,低電平有效
(3)TREADY信號:從機告訴主機做好傳輸準備;
(4)TDATA信號:數據,可選寬度32,64,128,256bit
(5)TSTRB信號:每一bit對應TDATA的一個有效字節(jié),寬度為TDATA/8
(6)TLAST信號:主機告訴從機該次傳輸為突發(fā)傳輸的結尾;
(7)TVALID信號:主機告訴從機數據本次傳輸有效;
(8)TUSER信號 :用戶定義信號,寬度為128bit。
三種AXI接口分別是:
AXI-GP接口(4個):是通用的AXI接口,包括兩個32位主設備接口和兩個32位從設備接口,用過改接口可以訪問PS中的片內外設。
AXI-HP接口(4個):是高性能/帶寬的標準的接口,PL模塊作為主設備連接(從下圖中箭頭可以看出)。主要用于PL訪問PS上的存儲器(DDR和On-Chip RAM)
AXI-ACP接口(1個):是ARM多核架構下定義的一種接口,中文翻譯為加速器一致性端口,用來管理DMA之類的不帶緩存的AXI外設,PS端是Slave接口。
我們可以雙擊查看ZYNQ的IP核的內部配置,就能發(fā)現上述的三種接口,圖中已用紅色方框標記出來,我們可以清楚的看出接口連接與總線的走向:
AXI協(xié)議之握手協(xié)議
AXI4所采用的是一種READY,VALID握手通信機制,簡單來說主從雙方進行數據通信前,有一個握手的過程。傳輸源產生VLAID信號來指明何時數據或控制信息有效。而目地源產生READY信號來指明已經準備好接受數據或控制信息。傳輸發(fā)生在VALID和READY信號同時為高的時候。VALID和READY信號的出現有三種關系:VALID先變高READY后變高,READY先變高VALID后變高,VALID和READY信號同時變高。無論什么情況信息傳輸立馬發(fā)生在VALID和READY信號同時為高且ACLK上升沿,時序圖如下:
需要強調的是,AXI的五個通道,每個通道都有握手機制,接下來我們就來分析一下AXI-Lite的源碼來更深入的了解AXI機制。
突發(fā)式讀
當地址出現在地址總線后,傳輸的數據將出現在讀數據通道上。設備保持VALID為低直到讀數據有效。為了表明一次突發(fā)式讀寫的完成,設備用RLAST信號來表示最后一個被傳輸的數據。
突發(fā)式寫
這一過程的開始時,主機發(fā)送地址和控制信息到寫地址通道中,然后主機發(fā)送每一個寫數據到寫數據通道中。當主機發(fā)送最后一個數據時,WLAST信號就變?yōu)楦?。當設備接收完所有數據之后他將一個寫響應發(fā)送回主機來表明寫事務完成。
PS與PL內部通信(用戶自定義IP)
??先要自定義一個AXI-Lite的IP,新建工程之后,選擇,菜單欄->Tools->Creat and Package IP:
選擇Next>>選擇Create AXI4 Peripheral>>然后Next默認,選擇Next>>注意這里接口類型選擇Lite,選擇Next>>選擇Edit IP,點擊Finish:
此后,Vivado會新建一個工程,專門編輯該IP,通過該工程,我們就可以看到Vivado為我們生成的AXI-Lite的操作源碼:
AXI-Lite 源碼分析
當打開頂層文件的時,是一堆AXI的信號。
PS向PL寫數據(PS作為Master,PL作為Slave)
先來看一段WDATA相關的代碼:
always?@(?posedge?S_AXI_ACLK?) begin ??if?(?S_AXI_ARESETN?==?1'b0?) ????begin ??????slv_reg0?<=?0; ??????slv_reg1?<=?0; ??????slv_reg2?<=?0; ??????slv_reg3?<=?0; ????end ??else?begin ????if?(slv_reg_wren) ??????begin ????????case?(?axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]?) ??????????2'h0: ????????????for?(?byte_index?=?0;?byte_index?<=?(C_S_AXI_DATA_WIDTH/8)-1;?byte_index?=?byte_index+1?) ??????????????if?(?S_AXI_WSTRB[byte_index]?==?1?)?begin ????????????????//?Respective?byte?enables?are?asserted?as?per?write?strobes ????????????????//?Slave?register?0 ????????????????slv_reg0[(byte_index*8)?+:?8]?<=?S_AXI_WDATA[(byte_index*8)?+:?8]; ??????????????end?? ??????????2'h1: ????????????for?(?byte_index?=?0;?byte_index?<=?(C_S_AXI_DATA_WIDTH/8)-1;?byte_index?=?byte_index+1?) ??????????????if?(?S_AXI_WSTRB[byte_index]?==?1?)?begin ????????????????//?Respective?byte?enables?are?asserted?as?per?write?strobes ????????????????//?Slave?register?1 ????????????????slv_reg1[(byte_index*8)?+:?8]?<=?S_AXI_WDATA[(byte_index*8)?+:?8]; ??????????????end?? ??????????2'h2: ????????????for?(?byte_index?=?0;?byte_index?<=?(C_S_AXI_DATA_WIDTH/8)-1;?byte_index?=?byte_index+1?) ??????????????if?(?S_AXI_WSTRB[byte_index]?==?1?)?begin ????????????????//?Respective?byte?enables?are?asserted?as?per?write?strobes ????????????????//?Slave?register?2 ????????????????slv_reg2[(byte_index*8)?+:?8]?<=?S_AXI_WDATA[(byte_index*8)?+:?8]; ??????????????end?? ??????????2'h3: ????????????for?(?byte_index?=?0;?byte_index?<=?(C_S_AXI_DATA_WIDTH/8)-1;?byte_index?=?byte_index+1?) ??????????????if?(?S_AXI_WSTRB[byte_index]?==?1?)?begin ????????????????//?Respective?byte?enables?are?asserted?as?per?write?strobes ????????????????//?Slave?register?3 ????????????????slv_reg3[(byte_index*8)?+:?8]?<=?S_AXI_WDATA[(byte_index*8)?+:?8]; ??????????????end?? ??????????default?:?begin ??????????????????????slv_reg0?<=?slv_reg0; ??????????????????????slv_reg1?<=?slv_reg1; ??????????????????????slv_reg2?<=?slv_reg2; ??????????????????????slv_reg3?<=?slv_reg3; ????????????????????end ????????endcase ??????end ??end這段程序的作用是,當PS那邊向AXI4-Lite總線寫數據時,PS這邊負責將數據接收到寄存器slv_reg。而slv_reg寄存器有0~3共4個。至于賦值給哪一個由axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]決定,根據宏定義其實就是由axi_awaddr[3:2] (寫地址中不僅包含地址,而且包含了控制位,這里的[3:2]就是控制位)決定賦值給哪個slv_reg。
PS讀取PL數據(PS作為Master,PL作為Slave)
我們繼續(xù)來看有關RADTA讀數據代碼:
//?Output?register?or?memory?read?data always?@(?posedge?S_AXI_ACLK?) begin ??if?(?S_AXI_ARESETN?==?1'b0?) ????begin ??????axi_rdata??<=?0; ????end ??else ????begin???? ??????//?When?there?is?a?valid?read?address?(S_AXI_ARVALID)?with ??????//?acceptance?of?read?address?by?the?slave?(axi_arready), ??????//?output?the?read?dada ??????if?(slv_reg_rden) ????????begin ??????????axi_rdata?<=?reg_data_out;?????//?register?read?data ????????end??? ????end end//當PS讀取數據時,程序會把reg_data_out復制給axi_rdata(RADTA讀數據)。 always?@(*) begin ??????//?Address?decoding?for?reading?registers ??????case?(?axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]?) ????????2'h0???:?reg_data_out?<=?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
? ? ZYNQ嵌入式設計時,用戶在PL中自定義的IP相當于PS(ARM的外設)掛在AXI總線上,他們之間是通過AXI總線進行數據傳輸。創(chuàng)建好哦IP后,文件自動的生成,用戶只需要做簡單的修改,寄存器賦值就可以。
?
評論
查看更多