通過前面的幾個(gè)例子,我們可以看出,在使用Zynq做設(shè)計(jì)時(shí),合理使用Xilinx已有的IP核非常的關(guān)鍵,可以極大地方便與簡(jiǎn)化我們的開發(fā)。但是有的時(shí)候我們需要根據(jù)自己的需要設(shè)計(jì)自己的IP核,即所謂的用戶IP。這篇文章就通過一個(gè)完整的例子介紹如何設(shè)計(jì)用戶IP,并且會(huì)對(duì)驅(qū)動(dòng)級(jí)的應(yīng)用程序設(shè)計(jì)流程進(jìn)行一個(gè)詳細(xì)的介紹。
用戶IPCore
用戶IPCore就是用戶自定義的IP核,用以和官方提供的IP核做區(qū)別。IPCore屬于PL部分,所以在Zynq上創(chuàng)建IPCore時(shí)就需要考慮如何跟PS交換數(shù)據(jù)。對(duì)于一般的IP核來說,有兩種可行的方案,一是通過EMIO交換數(shù)據(jù)(GPIO、SPI等),二是制作滿足AXI協(xié)議的IP核。第一個(gè)方案其實(shí)是將PL的IP核看做系統(tǒng)的外設(shè),在數(shù)據(jù)交互性能和效率上都有很大的欠缺,常用的方法是第二種,Xilinx提供的IP核也都屬于第二種。但是第二種方案的問題在于,制作的IP核和AXI協(xié)議密切相關(guān),這提高了IP核設(shè)計(jì)的難度。為了降低難度,Xilinx提供了用戶IP向?qū)В╓izard)。它會(huì)自動(dòng)生成總線(AXI)相關(guān)的代碼,做好地址譯碼邏輯、讀寫控制邏輯,并在用戶工作區(qū)生成一些寄存器。我們寫的PL邏輯通過讀寫這些寄存器和PS交互。這里我們介紹一個(gè)PWM發(fā)生器的例子,介紹一下用戶IPCore的開發(fā)流程。這個(gè)PWM發(fā)生器內(nèi)部只有兩個(gè)寄存器,一個(gè)是調(diào)節(jié)周期的周期寄存器,另一個(gè)是調(diào)節(jié)占空比的占空比寄存器。其中周期寄存器的最高位是狀態(tài)位,控制PWM波最后是否產(chǎn)生。該例參考自《ZYNQ嵌入式系統(tǒng)軟硬件協(xié)同設(shè)計(jì)實(shí)戰(zhàn)指南》一書。
設(shè)計(jì)流程
PS:下面的設(shè)計(jì)流程中,很多是和以前一樣的,所以相同部分不再詳細(xì)講解,如果忘了,可以回頭再去看一下《ZYNQ-7000使用總結(jié)(3)——PS和PL部分配合使用》中的流程。
PlanAhead中的工作——1
和前面的幾個(gè)例子一樣,我們現(xiàn)在PlanAhead里面創(chuàng)建工程(我創(chuàng)建的工程名為pwm_ip),并且創(chuàng)建system.xmp文件,然后會(huì)打開XPS。因?yàn)榍懊嬉呀?jīng)有比較詳細(xì)的圖文并茂式的介紹,這里就直接略過。
XPS中的工作
打開XPS后,我們首先和以前一樣是添加處理器實(shí)例IP,然后導(dǎo)入自帶的模板,我這里導(dǎo)入的zc702的模板。接下來我們正式開始用戶IPCore的創(chuàng)建。
在菜單欄,依次打開Hardware——Create and Import Peripheral,然后便會(huì)進(jìn)入到用戶IP創(chuàng)建向?qū)В?/p>
這里我們選擇創(chuàng)建IP,而不是導(dǎo)入IP,存儲(chǔ)位置的話,選擇默認(rèn)即可。然后Next,
上面第一幅圖中,我們填入要?jiǎng)?chuàng)建的IP名稱,名稱只能使用小寫字母或下劃線,這里起名為pwm_ip,Wizard會(huì)幫我們編一個(gè)版本號(hào)。
第二幅圖選擇AXI4總線類型(前面的文章已經(jīng)介紹過),因?yàn)槲覀円谱鞯腎P核只受一個(gè)Master控制,而且沒有考慮大數(shù)據(jù)傳輸?shù)?,所以這里選擇AXI4-Lite,單擊Next。
第三幅圖總共有四個(gè)選項(xiàng)?!癠ser logic master support”表示IP核內(nèi)部是否要加入Master接口,這一版用在比較復(fù)雜的外設(shè)里。下面的“Software reset”和“Include data phase timer”分別表示是否開啟軟件中斷和數(shù)據(jù)周期計(jì)時(shí)器。我們這個(gè)IP核比較簡(jiǎn)單,只選擇“User logic Software register”就行了。這樣的選項(xiàng)最后生成的IP核沒有多余的模塊,例如沒有AXI Master接口、Software復(fù)位模塊、數(shù)據(jù)周期計(jì)數(shù)器模塊等。
繼續(xù)點(diǎn)Next往下走,
上面第一幅圖選擇我們使用的寄存器的數(shù)量,根據(jù)前面的介紹,我們這里只需要2個(gè)即可,分別是PWM波的占空比寄存器和周期寄存器。這個(gè)選項(xiàng)設(shè)置的寄存器數(shù)量是我們最后可以使用的寄存器。這個(gè)Wizard可以幫我們自動(dòng)為所有的寄存器做好地址譯碼和控制邏輯布局。這樣我們?cè)趯憉ser_logic的時(shí)候,就可以直接使用這些寄存器了。
第二幅圖是顯示我們可以使用的IPIC信號(hào)。選中每個(gè)信號(hào),右邊就會(huì)顯示它的功能,我們可以根據(jù)自己的需要做刪減,這里我們保持默認(rèn),點(diǎn)擊Next。
第三幅圖的選項(xiàng)是讓W(xué)izard幫我們生成一個(gè)測(cè)試用的Master,那么我們可以在IP核加入系統(tǒng)之前就對(duì)他進(jìn)行功能測(cè)試。這個(gè)測(cè)試用的Master叫仿真支持平臺(tái),具有一些AXI總線的控制能力??梢酝ㄟ^閱讀平臺(tái)的README文件得到關(guān)于指令的信息。這里我們不選。
點(diǎn)擊Next,繼續(xù)。
上面第一幅圖中有三個(gè)選項(xiàng),第一個(gè)選項(xiàng)表示生產(chǎn)的User Logic使用Verilog(默認(rèn)使用VHDL),這里根據(jù)自己對(duì)語言的掌握進(jìn)行選擇,我使用Verilog,所以勾選該選項(xiàng)。第二個(gè)選項(xiàng)表示同時(shí)生成ISE工程,便于調(diào)試和測(cè)試IPcore。第三個(gè)選項(xiàng)表示生產(chǎn)軟件驅(qū)動(dòng)庫文件,方便在SDK里使用IPcore。
點(diǎn)擊Next后,便進(jìn)入最后的總覽界面,確認(rèn)無誤后,點(diǎn)擊Finish。
這樣我們的IP核就建立好了。我們發(fā)現(xiàn)IP Catalog中多出來一個(gè)USER分類,我們的IP核就在里面,然后雙擊將該IP核添加到我們的系統(tǒng)之中。
接下來我們需要編輯三個(gè)文件:
第一個(gè)文件:mpd文件。在Bus Interface選項(xiàng)卡中找到該IP,右擊選擇View MPD,進(jìn)入MPD文件,我們?cè)贓ND之前添加pwm_out端口,方向是輸出,位數(shù)為1。保存關(guān)閉。這個(gè)文件里面的端口會(huì)在system assembly view中的ports界面中映射出添加的pwm_out接口。添加的代碼見下圖:
第二個(gè)文件:vhd文件。右鍵IP,選擇Browse HDL Sources,在hdl文件夾下的vhdl文件夾里面選擇vhd文件,添加代碼。這個(gè)步驟是聲明剛才在MPD中設(shè)置的接口名稱和位寬(這里叫pwm_out,位寬為1),并且將這個(gè)接口一直連接到用戶邏輯設(shè)備。添加的代碼見下圖后兩幅圖(這里的文件內(nèi)容格式比較像,注意別添加錯(cuò)位置了):
第三個(gè)文件:v文件。右鍵IP,選擇Browse HDL Sources,在文件夾下的verilog文件夾里面選擇.v文件,添加代碼,見下圖。第一幅圖聲明pwm_out接口。第二幅圖定義pwm_out為輸出,而且寬度為1。第三幅圖是用戶實(shí)現(xiàn)段,令slv_reg0為周期寄存器,slv_reg1為占空比寄存器。此外我們還需要一個(gè)計(jì)數(shù)器(pwm_counter)、下一個(gè)周期的開始信號(hào)(Over Period)和預(yù)輸出信號(hào)(pre_pwm_out)。
至此,我們?nèi)齻€(gè)文件就添加完畢了。我們用戶自定義的IP核主要就是修改這三個(gè)文件。
然后我們?cè)诓藛螜谥羞x擇Project——Rescan User Repositories,然后就可以在port選項(xiàng)卡中看到我們新添加的引腳pwm_out。選擇External Ports把引腳引出去。再打開Address選項(xiàng)卡,單擊右上角的Generated Addresses按鈕,就可以看到系統(tǒng)給每個(gè)模塊分配的地址。這里的地址在我們后面軟件中會(huì)用到。
然后單擊Project——Design Rule Check,如果Console中沒有提示錯(cuò)誤,那我們XPS中的工作就算完成了。關(guān)閉XPS,回到PlanAhead。
PS:如果DRC后沒有錯(cuò)誤,但是在后面的PlanAhead里面綜合時(shí)還是提示XPS中有錯(cuò)誤,那可以在XPS中選擇Generate Netlist定位一下問題所在。
PlanAhead中的工作——2
PlanAhead中的工作,和以前一樣,先是右擊system.xmp文件,選擇Create Top HDL。
然后單擊左邊的Add Source,創(chuàng)建約束文件(前面文章已經(jīng)介紹過),約束文件起名為system。
完成后點(diǎn)擊左邊的Run Synthesis,在綜合過程結(jié)束后彈出的對(duì)話框中選擇Open Synthesized Design。然后在打開的I/O便簽中添加約束,這里我們將pwm輸出引腳約束到開發(fā)板上的一個(gè)LED燈(DS19)上面,然后保存。然后可以查看system.ucf文件中已經(jīng)增加了我們的約束信息。
然后單擊左邊的Generate Bitstream。完成后和以前一樣導(dǎo)出我們的硬件平臺(tái)到SDK。
SDK中的工作
和以前一樣,我們?cè)赟DK中以導(dǎo)出的硬件為平臺(tái),使用Hello World模板創(chuàng)建應(yīng)用程序,前面的文章已經(jīng)講過,這里略過。我創(chuàng)建的應(yīng)用程序名為L(zhǎng)ED_IP。
創(chuàng)建好以后,選擇Xilinx Tools——Repositories。單擊New,加入我們剛才Wizard生成的edk目錄,里面有我們創(chuàng)建的IP核信息,如下圖:
然后在BSP文件(我的為L(zhǎng)ED_IP_bsp)上右擊,選擇Board Support Package Setting。找到drivers中的pwm_ip_0,修改Driver,選擇pwm_ip,
這樣我們便將我們的IP核的Driver添加了進(jìn)來。然后在helloworld.c中添加如下代碼:
/*
* helloworld.c: simple test application
*/
#include
#include "platform.h"
#include "pwm_ip.h"
#include "xparameters.h"
int main()
{
init_platform();
printf("This is a PWM IP Creation Demo.");
PWM_IP_mWriteReg(XPAR_PWM_IP_0_BASEADDR, 0, 10000);
PWM_IP_mWriteReg(XPAR_PWM_IP_0_BASEADDR, 4, 0x80000000+5000); // 占空比5000/10000=50%
cleanup_platform();
return 0;
}
然后連接開發(fā)板,用導(dǎo)出的bit文件配置FPGA,編譯運(yùn)行程序,我們會(huì)看到LED(DS19)的亮度只有其它的一半。更準(zhǔn)確的我們可以用萬用表測(cè)一下pmod1_0引腳的電壓(DS19和pmod1_0連在一起),只有Vcc(3.3V)的一半1.65V。證明產(chǎn)生了占空比50%的方波。
按照上述的步驟,在編譯程序時(shí)應(yīng)該會(huì)出錯(cuò),這是由一些已知的軟件本身Bug造成的(我的軟件版本是14.4),我們做以下幾個(gè)點(diǎn)的修改:
打開Wizard幫助我們生成的驅(qū)動(dòng)文件,我的目錄是E:\FPGA\workspace\xilinx\demo_ip\demo_ip.srcs\sources_1\edk\system\drivers\pwm_ip_v1_00_a\src,打開里面的pwm_ip_selftest.c文件,添加下圖中框起來的那行宏定義:
編譯時(shí)提醒找不到xio.h文件。解決方法是在上面所說的目錄里打開pwm_ip.h和pwm_ip_selftest.h文件,把里面的xio.h全部用xil_io.h替換。如果還編譯出錯(cuò),就在這兩個(gè)文件里面添加#include “xil_types.h”。具體可參見Xilinx官方: 。
一些知識(shí)點(diǎn):
我們一般在硬件中添加IP核以后,在軟件設(shè)計(jì)中就需要寫對(duì)應(yīng)的程序來配置和使用IP核。那么這個(gè)時(shí)候我們?cè)撛鯓尤戇@個(gè)程序呢??jī)煞矫娴耐緩健2徽撌荴ilinx官方的IP核,還是我們自己創(chuàng)建的IP核,都會(huì)附帶實(shí)例程序,比如這個(gè)我們創(chuàng)建的PWM_IP核,我們就可以在前面所說的目錄里面找到示例驅(qū)動(dòng)程序(即pwm_ip.h、pwm_ip.c、pwm_ip_selftest.c)文件。官方的IP核,我們可以軟件安裝目錄里面找到對(duì)應(yīng)的文檔和示例程序,比如我的目錄是C:\Xilinx\14.4\ISE_DS\EDK\hw\XilinxProcessorIPLib\pcores。當(dāng)然,我們也可以在SDK中的system.mss中直接打開文檔和例子程序。其實(shí),我們?cè)诮⒁粋€(gè)應(yīng)用程序的時(shí)候,它幫我們自動(dòng)生成的BSP,就是直接拷貝這些地方的示例代碼。比如我們按照上面所說的方法解決掉bug以后,我們可以去bsp文件里面找到我們這個(gè)IP核,查看他的src,就會(huì)發(fā)現(xiàn)它也已經(jīng)改變了。另一個(gè)途徑就是去Xilinx官方找對(duì)應(yīng)的IP核文檔,這個(gè)只能針對(duì)Xilinx提供的IP核。
關(guān)于xparameters.h文件。這個(gè)文件是系統(tǒng)自動(dòng)生成的,對(duì)于我們的開發(fā)至關(guān)重要,前面的程序中,我們有使用到一些宏,那些宏就是在這個(gè)文件里面定義的。打開這個(gè)文件,我們就會(huì)發(fā)現(xiàn)里面基本上全是宏定義,主要是定義一些設(shè)備的基地址、高地址、偏移量、中斷號(hào)等。我們進(jìn)行程序設(shè)計(jì)的時(shí)候,一般都需要去這個(gè)文件里面找對(duì)應(yīng)地址的宏定義。
至此,這篇文章也寫完了。IP核的創(chuàng)建對(duì)于我們?nèi)粘5拈_發(fā)還是非常重要的,我們需要很好的掌握。另一方面,這篇文章也介紹了一些驅(qū)動(dòng)級(jí)的應(yīng)用程序設(shè)計(jì),大家可以結(jié)合相關(guān)文件里面的代碼好好體會(huì)一下Zynq的軟硬件協(xié)同設(shè)計(jì)。
評(píng)論
查看更多