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