構建SoC系統,畢竟是需要實現PS和PL間的數據交互,而像上一講那樣PL主機與PL從機之間通過AXI4-Lite總線進行交互有點殺雞用牛刀了。
如果PS與PL端進行數據交互,可以直接設計PL端為從機,PS端向PL端的reg寫入數據即可,但是對于圖像處理等大數據量的數據交互來說,PL端的BRAM畢竟容量有限,很難用BRAM作為兩者間的數據緩存器。對于這樣的應用來說,利用DDR3作為PS端與PL端之間交互的數據緩存器是最合適不過的。
1.工程規劃
再ZedBoard板子的硬件設計方案中,DDR芯片的管腳是綁定到Zynq的DDR接口上的。
而Zynq系統的這個DDR總線接口有是鏈接在其內部“Memory Interfaces”中的“DDR2/3,LPDDR2 Controller”可配置硬核上的。
因此,要想PL訪問板上的DDR3存儲器,必須借道Zynq中的“Memory Interfaces----DDR2/3,LPDDR2 Controller”(后文簡稱“DDR3 Controller”)。根據之前的經驗,在Zynq系統中,ARM Core(CPU)能夠訪問硬核“DDR3 Controller”,根據經驗可以確定“DDR3 Controller”一定是一個從設備,而PL要想訪問“DDR3 Controller”的話,PL一定要是一個主設備,由PL發起讀寫操作。
“DDR3 Controller”是封裝在Zynq子系統中的,因此,PL必須連接Zynq的從機接口。從上圖可以看出,Zynq有兩個從機接口,分別是“32b GP AXI Slave Ports”和“High Performance AXI 32b/64b Slave Ports”根據名稱可以看出,一個是高性能的,另一個應該是普通的。之前Zynq作為主機連接AXI4-Lite從設備時,走的是“32b GP AXI Master Ports”,可以輔助證明,對于本節應用,走的接口應該是“32b GP AXI Slave Ports”。
交互數據將會經過Zynq子系統的內部總線(用空再考證一下是什么名稱)控制器“Central Interconnect”轉發給Memory Interfaces。具體數據交互路徑如下圖所示:
根據上述分析,SoC系統集成方案框圖如下:
根據之前的經驗,利用向導生成的PL端AXI4-Lite Master IP 用戶用例再txn負脈沖觸發下,主機模塊的邏輯是連續4次(次數默認為4,可通過修改參數C_M00_AXI_TRANSACTIONS_NUM的數值改變次數)向遞增的地址區間寫入4組測試數據,測試數據每次加1。然后主機模塊自動讀取剛才寫入數據的地址內的數據,將讀的的數據與寫入數據進行比較,如果正確,主機IP的ERROR信號保持低電平,如果錯誤,ERROR給出高電平。
本文后面的行為仿真證明:再次給主機IP模塊一個txn的觸發信號,重新執行4次寫入操作+4次讀取操作+比較操作。只不過每次觸發都從原始基地址開始操作,目標寄存器地址并不增加。
本節的測試工程本著少改動邏輯代碼的原則,仍基本采用此邏輯。每次按鍵觸發,執行4次寫操作+4次讀操作+比對檢查操作,增加利用4個LED燈表示每個地址比對結果是否正確(如果正確LED燈亮)。但是當再次按下按鈕,LED燈全滅,松開按鈕后再執行一組(4次寫操作+4次讀操作+比對檢查)操作,只是新的一組操作地址會遞進增加。
2.Zynq系統裁剪
創建工程后,添加一個Zynq IP核,然后調用官方對ZedBoard板中Zynq子系統的默認配置。
得到默認的Zynq硬核配置如下圖所示:
對應的Zynq封裝如下圖所示:
明顯看出有很多Zynq中的硬核在本項目中是不需要的,修改配置,將其裁剪掉。
修改后的Zynq配置顯示如下:
Zynq的封裝圖如下所示:
輸出端的FCLK_CLK0和FCLK_RESET0_N是輸出時鐘和復位信號。這兩個信號的出處已在前一個圖中進行標注。
ZedBoard開發板的ARM端時鐘由IC18有源晶振提供33.33333MHz的時鐘信號,綁定到Zynq芯片的F7(PS_CLK)管腳上,該管腳是Zynq子系統(PS)的時鐘信號。如果工程中添加了Zynq子系統,Vivado會自動將F7綁定到Zynq子系統的PS_CLK管腳上(其實也不需要綁定,這是固話的。F7本身就是專用引腳,但是從硬件結構上也可以看出一個工程只能實例化一個Zynq子系統)。該綁定在約束文件上看不到,而在“Synthesis Design”的“I/O Planning”頁面中可以看到。(因為這個管腳是專用管腳,不需要綁定)這里欠個圖,后文會有,記著啊!!!
FCLK_CLK0是經過一個時鐘管理模塊(類似V4中的DCM)生成的,可以修改其參數。Zynq中包含了4個時鐘生成模塊。配置界面如下:
如果取消勾選,Zynq將不輸出時鐘信號。
那對于PL端的時序邏輯模塊,需要另外尋找時鐘信號,在ZedBoard開發板上,IC17有源晶振提供100MHz的GCLK時鐘信號,連接到Y9上,可用PL端使用。但是這種方案PS端和PL端由獨立的時鐘分別驅動,必須考慮跨時鐘域問題。
取消FCLK_CLK0的勾選后,Zynq的封裝圖如下所示:
FCLK_CLK0管腳就沒有了,但是FCLK_RESET0_N仍然存在,因為Zynq中的Resets模塊是不可配置的。但是Resets有四路輸出,為什么這里只有1個呢?是不是跟FCLK_CLKx有綁定呢?
【添加,事后發現,FCLK_RESET0_N也是可以關閉的,操作如下】
太強大的軟件了,永遠別覺得自己學明白了!!!
為了驗證上述疑問,勾選兩路FCLK_CLK0和FCLK_CLK2,觀察之后的Zynq模塊封裝如下所示:
沒有喚出其余的幾路Resets信號。如何召喚其他幾路復位信號,還得研究研究。
【個人猜想】:這個FCLK_RESET0_N應該是跟Zynq子系統的復位工作是同步的,有可能Zynq子系統收到復位信號(PS-RST,BTN7,C9,低電平復位)后,FCLK_RESET0_N被拉低,等待一定時間保證Zynq子系統復位完成后,再延時一段時間,再拉高,是的PL端的模塊完成復位進入正常工作狀態時,Zynq子系統一定已經正常工作。
本項目中,Zynq子系統裁剪完畢后,封裝圖采用下圖方案。
利用FCLK_CLK0驅動PL端的時序邏輯。而將Y9管腳引入的100MHzGCLK信號旁路。
再來看看S_AXI_GP0,即AXI4總線接口(兼容AXI4-Lite)。如下圖所示:
終于,畫箭頭的管腳我們都熟悉了。其他的以后再說。
至此,Zynq子系統我們裁剪完畢了。
【還有個問題】:“DDR3 Controller”硬核在Zynq子系統內部的內存映射還沒有看到。打開Address Editor頁面,也沒有配置信息。
另外,作為從機接口,讀寫地址總線均為32bits,而不像之前的驗證方案,從機的讀寫地址去掉高位的段地址只留下低位的offset Address,這樣的地址接口,能跟PL端的AXI InterConnect匹配嗎?
3.PL端主機IP核設計編碼
根據之前的經驗,利用向導生成一個AXI4-Lite Master IP示例代碼,構建主從模塊直連的測試系統,從機模塊默認內部寄存器數量為4個,構建本仿真系統時,將從機模塊內部寄存器數量設置為32個,其余不用修改。
功能仿真文件(詳見附錄2),模擬連續兩次觸發txn信號,設置參數,每次txn觸發執行兩次寫讀操作,對應的仿真結果如下圖所示。
每次txn觸發,起始地址均歸零,即恢復成初始地址0x4000_0000,寫入的數據也變為初始值0xaa00_0000。跟工程設計的邏輯需求不一致。
因此根據需求改造代碼邏輯,底層模塊的源碼詳見附錄。編碼時一定避免Multi-Driver禁告。修改后的邏輯仿真結果如下所示。
可也看出主機模塊的功能滿足設計要求。
之后將該IP核加入到工程的IP Catalog中。
4.在Block Design中增加PL端IP核
首先在Block Design中實例化一個AzIP_AXI_Master_3的一個IP模塊,如下圖所示,此時沒有連接。
點擊頁面上的Run Connection Audomation按鈕,自動創建連接。整形以后如下圖所示。新加的兩個模塊都是老朋友了,基本邏輯核管腳時序都基本明確了。此時再來看這個連接,基本上就沒有問題了。圖中用彩色標注出了PL端的時鐘信號和復位信號。均由Zynq子系統產生。
同樣按F6鍵檢查連接,如果檢查無誤,表示這個系統的“原理圖”畫的基本沒有問題了。
5.內存映射分析
點擊Address Editor標簽,看一看,這個圖前文在zynq子系統配置完后曾經出現過,但是當時是沒有數據的,現在我們放在一起對比一下:
下面我們嘗試解讀一下,第一幅圖時,軟件僅僅檢測到存在一個AXI Slave接口GP0,當時沒有匹配的,所以沒有數據,但是當我們加上自行設計的AXI Master接口IP后,軟件將二者匹配上了,通過層級結構發現,Zynq上的GP0的Slave接口是匹配用戶IP的主機接口的,然后軟件自動分配了地址。有一個Base Name,名字是GP0_DDR_LOWOCM,這個名字沒看過,不過猜也知道是跟GP0口和DDR相關的,神奇軟件怎么知道我想操作DDR呢?猜想應該是配置Zynq時,配置了DDR,所以在Zynq中的總線控制其中激活了DDR相關的段地址,即DDR_LOWCOM。
為了驗證上述想法,在Zynq中裁剪掉DDR,具體操作如下:
得到的Zynq封裝如下:
可以看到Zynq子系統各種去掉了DDR Control模塊,再看Address Editor頁面。
可以看到,由于GP0模塊的存在,對于Zynq內部總線接口來說,它配置了一個地址GP0_LOW_OCM,關鍵詞是OCM,經過查詢,得知OCM的意思是片上存儲器(On-Chip Memory),說白了就是內存映射地址。Zynq內部任何一個可配置的外設硬核,其電路均已經硬件實現了,對應的Zynq內部片地址也是固定的,增加外設,應該就會有新的片內地址。
增加了外設USRT1,SD0,USB0,ENET0,QUARD SPI,注意此時沒有激活DDR Controller模塊。先來看看Zynq的封裝。
再來看Address Editor頁面
可以看到,對于Quard SPI模塊,有單獨的地址映射GP0_QSPI_LINEAR,而USRT1,SD0,USB0,ENET0等外設沒有,根據Zynq的結構圖,大膽猜測,USRT1,SD0,USB0,ENET0等外設均包含在IO Peripherals模塊內,因此它們的統一片內地址映射(OCM)的基地址均為GP0_IOP,其中IOP應該就是IO Peripherals的簡寫。
開始這些數據都沒有分配地址,但是前面說了,Zynq中,由于硬件結構都是固定的,剪裁操作是指不激活某些功能模塊,個人猜測目的可能是為了低功耗,但是對應的功能模塊的內存地址映射都是固定的,跟用戶設計的SoC工程無關。
所以這些Zynq內部的映射應該是固定的,我們怎么能夠看到呢?點擊Address Editor中的Auto Assign Address按鈕,如下圖所示,系統就會自動填寫響應內存映射的Offset Address和Range了。這些都應該是經由GP0路由到這些外設硬核的映射地址。
【補充】LOW_OCM應該就是低速(低性能)存儲器地址。有低速對應的肯定就有高速。如下所示。
勾選上圖所示項,應該能夠打開HIGH_OCM
從上文看出,對于GP0_QSPI_LINEAR和GP0_IOP的命名并沒有LOW和OCM等信息。Zynq外設配置不變,僅僅是勾選上圖Allow Access to High OCM項,地址映射數據如下。其中HIGH_OCM應該是個獨立的內存區域。
去除USRT1,SD0,USB0,ENET0,QUARD SPI等外設,啟動DDR Control,仍然勾選Allow Access to High OCM項,得到的Zynq封裝如下圖:
對應的Address Editor頁面如下:
可以看出DDR還是屬于LOW_OCM,而HIGH_OCM應該是Zynq系統中的一個特殊區域,具體在哪還不確定,因為跟DDR無關,這里暫時就不關注了。
由于PL中的IP核對Zynq管理的DDR操作是通過地址進行的,因此我們需要對DDR的內存映射整明白。下面再研究研究。
GP0_LOW_OCM已經沒有了,但是其對應的地址被包含在GP0_DDR_LOWOCM地址段的低位區間上。
回想《筆記3:PS讀寫DDR3存儲》中的內存映射:
對應的片外DDR3存儲芯片的地址的起始位為0x00100000,和這個有點意思。
當然,Address Editor頁面中的Offset Address參數和Range參數是可以修改的,而High Address參數是根據前兩個參數計算出來的。
必須對Zynq子系統的內存映射原理特別明白,才能正確修改這些參數,因此我們在深入研究研究,看看能不能整明白。
為了深度研究這個問題,在Xilinx Documentation Navigator中搜索OCM,得到如下信息。
可以看到OCM還分為指令OCM和數據OCM。但是這些文件都是比較老的,不是針對Zynq芯片的。沒有收獲。
上圖這些文件也沒用,這些講到都是在PL端用HDL編碼實現一個與DDR直接向量的接口控制器的使用方案,而不是設計到Zynq的地址映射方案。
換個思路,查詢Zynq的技術文檔。
在該文檔中得到一些信息,先摘錄如下:
Zynq內部有256KB的RAM,就是前面GP0_LOW_OCM或者GP0_HIGH_OCM映射的嗎?這個有意思,一定想辦法找到。因為之前實驗中C語言程序可能就運行在這個內存空間中。
這是前文提到的I/O Peripherals中的內容。
ZedBoard板子用到的芯片是XC7Z020,封裝為clg484,但是由于芯片上覆蓋了個散熱片,不知道是-?。有空問問供貨商。
難道是-1???可憐啊,CPU主頻最高為667MHz。上圖應該是從配置文件中獲得的,硬件具體是-?其實還是從芯片絲印看最可靠。不過應該差別不會太大,畢竟是通用開發板,不是為了最求性能的。
下面圖很重要!
250KB的RAM(OCM)在圖中箭頭處。
我的猜測,前面出現的內存映射Base Name,應該指的是Central Interconnect的出口,示意圖如下:
找到了,就是在這篇文檔中,有下列信息:
從上圖看到,0x0000_0000是DDR and OCM,
0xFFFC_0000是OCM
那么Zynq內的256KB RAM(OCM)到底怎么訪問呢????郁悶
最后的DDR內存映射配置按照系統默認的,如下:
記得主機模塊開發是,使用的默認起始地址是0x4000_0000,這個在代碼中定義的。不過利用IP核的GUI也能看到。
從前文知道,這個地址是向PL AXI Slave Port #0,即GP0的,Size是1G。
【問題】PL 中的Master IP向0x4000_0000地址寫入數據,經過PL中的AXI Interconnect直連,將會轉發給GP0,GP0收到后,怎么在轉給DDR呢????
【個人猜測】:傳入的地址-0x4000_0000,然后進行路由判斷嗎?假設是這樣的,跑起來看看。
至此,本實驗的硬件設計完畢。保存后,退出Block Design頁面。
6.封裝?& Synthesis
然后記得創建HDL Wrapper,
之后對這個工程進行Run Synthesis。
結果沒有error和critical warning。
7.行為仿真
原想對這個包含Zynq的頂層模塊進行行為仿真,但是看了一眼端口定義。
跟DDR相關的接口時序我根本沒法設定,故此放棄了。
直接下板測試吧。
8.管腳綁定
綜合完成后,進入Synthesized Design頁面,先看看Schematic
然后重點看I/O Planning
根據原理圖,PS_CLK(F7)和PS_POR_B(B5)是在Bank500上,驅動電壓是3.3V,而PS_RST(C9)是在Bank501上,驅動電壓是1.8V。但是這幾項是Fixed,改不了,就這樣吧。
只能綁定用戶管腳,最后的配置圖如下:
之后會創建約束文件。
之后,執行Run Implementation和Generate Bitstream。
9.是否還需要啟用SDK
直接下板嘗試。
沒有反應啊。郁悶!Why????
時序邏輯沒反應,先檢查時鐘信號和復位信號,在本實驗系統中,PL端的時鐘信號和復位信號均是從Zynq子系統中輸出的,因此對工程做如下改變,將時鐘信號和復位信號引到板上的LED燈處,用于顯示和測量。
該工程Synthesis & Implementation后,仍然通過Hardware Manager下載后,現象為FCLK_CLK0驅動的LED燈常亮,使用示波器檢測輸出為持續高電平,FCLK_RESET0_N驅動的LED燈不亮。根據現象猜測,Zynq子系統中的時鐘單元沒有正常工作。
原因分析(個人觀點):因為Zynq其實是一個ARM系統,其內部的硬核要想按照配置正常工作,應該是在初始化階段對相應硬核的控制寄存器進行初始化配置,如果是使用Hardware Manager下載是無法操作這一步的。因此嘗試使用SDK進行SoC工程配置。
10.是否還需要啟用SDK
根據之前的學習,使用SDK有下列幾步,不清楚的參看之間的學習筆記。
第一步:Vivado中Export Hardware...(其中需要Include Bitstream)
第二步:Vivado中Launch SDK
第三步:SDK中創建板載支持庫函數,Board Support Package
第四步:創建用戶工程,Application Project
第五步:編譯
第六步:Program FPGA
下面對其中跟本實驗有關的進行簡單說明
(1)在第三步中,啟用SDK可以看到內存映射信息,跟內存相關的一個是DDR,一個是Zynq系統內部的RAM,內存地址如下,根據標題分析,應該是Zynq子系統內部,對于CPU來說的地址設定。
個人猜測:從上圖可以看出在Zynq內部,對于兩個CPU Core,同一個硬核,操作地址是相同的,從而能夠實現雙核的數據交互。比如ps7_cortexa9_0能夠直接對0x0010_0000的DDR讀寫數據,同樣的ps7_cortexa9_1也可以對該地址的DDR直接讀寫數據。同時這將會帶來一個問題就是同步。另外,還有個問題就是如果是雙核運行,每個核都將有自己獨立的代碼段和棧空間(這兩個空間是程序運行時系統使用的,用戶不能強行進行讀寫操作),而堆空間是用戶自行申請使用的內存空間,通常用來進行用戶數據存儲,也就是說堆空間才是雙core可以公用的。而無論代碼段、棧空間、堆空間的物理載體都是內存(RAM or DDR),因此c語言嵌入式程序對物理內存直接讀寫時,要避免對代碼段和棧空間的地址進行操作。而對代碼段和棧空間的配置應該是在編譯過程中的link階段配置的。具體配置接口如下:
這是配置界面,與傳統ARM開發對應的配置文件如下所示,相應的詳細原理參考傳統ARM開發的相關知識。
(2)對Zynq子系統中各個硬核的初始化配置。
前面分析過,對于Zynq子系統,在不使用CPU Core的架構設計中,如果僅僅使用HardWare下載,Zynq子系統內部的外設硬核也是不能正常工作的。前面分析認為是沒有進行初始化配置,在SDK軟件中,打開ps7_init.tcl文件如下圖所示,從名字可以看出,這是一個初始化的腳本配置文件,既然是tcl文件,應該就不需要c語言調用,而是直接配置,下面截圖可以看出是對PLL硬核,Clock硬核、DDR硬核控制寄存器的初始化配置。
其中猜測:mask_write 0XF8000008 0x0000FFFF 0x0000DF0D
應該表示的是向0xF800_0008地址寫入數據0x0000_ffff_0000_df0f(共計32bits)
在Run時,SDK軟件會在配置“Run ps7_init”項對應的邏輯狀態下自動調用該tcl文件完成初始化操作的。
(3)在第四步創建用戶工程(Application Project)時,如果還按照之前的經驗選擇“Hello World”,將會顯示如下信息:
提示信息為:目前硬件項目設計中沒有Uart外設硬核,因此該示例不能創建,真丟本實驗,僅有Peripheral Tests和Empty Application兩項可以使用。經過驗證,利用這兩個模版都可以實現實驗要求,這里只介紹Empty Application模版
使用Empty Application模版,創建的工程如下所示:
可以看出并沒有任何c語言文件。
在src中創建一個c語言文件main.c(文件名可以隨便起),其中自行輸入一個main函數(必須是這個函數名),保存后,SDK會自動編譯,生成一個debug文件和binaries項。
可以看出,這里main函數里什么都沒有做。
【補充】對內存分配的進一步分析研究
雙擊Binaries下的elf文件,顯示如下信息:
可以看出,編譯完成之后,編譯軟件對嵌入式程序進行的內存劃分。而且系統空間大小地址都分配在ddr的低地址區間,因本實驗測試時,選用的DDR地址空間應以高地址空間為宜。
在詳細分析elf文件中對內存的劃分,重點看下圖部分。
編譯軟件分析完畢后,得到的棧空間其實地址為0010_a030,棧空間大小為0000_3800(14K Bytes)。(0010_a030+0000_3800=0010_d830)
c語言嵌入式軟件中,如果不是直接地址操作,本實驗編譯后的軟件使用的數據空間為:0010_0000~0010_d830,空間大小為:54.046875K Bytes。
因此,本實驗中對DDR的內存讀寫測試,測試的內存地址區間從0020_0000開始為宜。
另外前文分析時說過,板載DDR為512MB,但是在vivado生成的system.hdf文件中,定義的ps7_ddr_0的內存空間范圍只有511MB,少了1MB,當時不知道這1MB時怎么被貪污的。
【個人猜測】但是再看elf文件,可以看到0000_0000開始的空間,是用來進行Debug調試的,因此被Vivado+SDK系統給扣下了,對用戶不可見。
創建完用戶邏輯后,配置Run As...項,用于下載程序。
其中,Run Configurations頁面前面已經見過很多次,這次重點說明的地方已經框出:
其中“Reset Processor”僅僅時重新下載C語言嵌入式程序,download to processor
當選中“Reset Entire System”項,會先下載PL端的bit文件,然后再下載C語言嵌入式程序,download to processor。
具體說明如下所示。
選擇reset processor項后,run成功,SDK Log窗口顯示如下信息,可以看出,先執行ps_init.tcl腳本,配置PS的硬核,在運行ps7_post_config(具體工作內容還沒整明白),然后復位ps7_cortexa9_0(是的c語言程序從main函數開始運行)。
在開發板上,程序下載成功后,如果按BTN6(PROG),相當于Program FPGA這一項需要重做。因此開發板不再有反應。
在開發板上,程序下載成功后,如果按BTN9(PS-RST),相當于zynq子系統復位,而非CPU(ps7_cortexa9_0)復位,此時需要重新執行Run ps7_init這一項。因此開發板不再有反應。
【結果】下載成功后,開發板反應如設計所示。實驗結果表明:
當設置PL端的Master設備訪問的地址為0x4020_0000(0x4000_0000為32b GP AXI Slave Port的地址?+ 0x0020_0000為DDR內的地址)時,下板運行結果表明內存讀寫操作是失敗的。
當設置PL端的Master設備訪問的地址為0x0020_0000(為Zynq子系統內CPU對DDR訪問的地址段)時,下板運行結果表明內存讀寫操作是成功的。
【結論】:
1. 只要SoC系統中,用到了Zynq子系統,無論邏輯上是否激活CPU,都需要使用SDK進行下載,原因時初始化Zynq子系統中硬核。
2. PL端對Zynq子系統中的寄存器進行操作,不需要考慮進行二次內存封裝,直接使用Zynq內設定的地址即可。即整個芯片PL+PS是采用統一地址映射的。
編輯:黃飛
?
評論
查看更多