ZYNQ的自定義IP
1、實驗原理
在vivado中可以將自己寫的verilog模塊封裝成IP核,並入bd設計,有效地提高了PS到PL的設計內聯能力。同時,這部分的學習可以將verilog的基礎知識轉移到嵌入式設計中。所以,這是一個基本的能力。
2、實驗操作
一、創建工程
這一步根據自己的開發板選型即可。沒有特殊的設置。
二、新建文件
在source的hierarchy(層次)中添加文件user_gpio.v,就是通過自定義的模塊實現GPIO的傳輸。模塊的功能很簡單,就是將輸入連到輸出。
module user_gpio( input wire gpio_in, input wire [3:0] ps_gpio_in, output wire gpio_out, output wire [3:0] ps_gpio_out ); assign gpio_out = gpio_in; assign ps_gpio_out[3:0] = ps_gpio_in[3:0]; endmodule
代碼參考小熊貓課堂。
三、基於AXI總線的IP打包
基於AXI總線的IP打包可以將IP快速地部署到總線上,可以與總線上的其他設備充分交互,自然也可以通過總線的引腳接出芯片。
tool》【單擊】create and package new IP》next》【選擇】Create AXI4 Peripheral》next》 寄存器數量選擇4》【選擇】edit》finish
在新彈出的窗口中,就是IP核的編輯界面,其與工程界面分立,說明不依賴於特定工程存在。
在這個窗口可以編輯AXI總線IP核。
和verilog的模塊間的調用一樣,在IP核的頂端和子模塊中加入端口聲明也是端口輸入輸出,例化用點連接。值得注意的是,這里只例化兩個端口gpio_in和gpio_out,而對於ZYNQ內核端的輸入輸出信號在這里並不連接,作為空置引腳。在后面會連接到寄存器。
為了使AXI寄存器控制起效和簡潔,需要更改某些寄存器的設置。
在如圖所示的位置更改112~114三行代碼。從reg變成wire應該好理解,我們做的模塊功能單一,不需要使用reg變量實現控制的目的。其他兩個變量則是多余的變量。從前面寄存器數量最小為4可以得到,該IP設計默認至少使用4個寄存器,而我們這里太簡單,只需兩個,所以需要手動刪除。
改完之后將下面所有的報錯點屏蔽掉,即可完成配置。
這里也從一個側面說明幾個寄存器之間不存在直接關聯。
在子模塊的尾部插入如下代碼:
// User logic ends wire ps_gpio_in; wire [3:0] ps_gpio_out; assign ps_gpio_out[3:0] = slv_reg0; assign slv_reg1 = ps_gpio_in; user_gpio test( .gpio_in(gpio_in), .gpio_out(gpio_out), .ps_gpio_in(ps_gpio_in), .ps_gpio_out(ps_gpio_out) );
這里也解釋了前面為什么要使用wire型的slv_reg1,主要是節約賦值時間。
如果以后有時間可以學習AXI總線協議的話,或許就可以看懂現在的模塊,現在不做討論,主要了解如何在AXI的IP上搭建verilog的自定義IP。
四、打包整合后的工程
tools》Create and package new IP》next》package your current project》next》overwrite》finish
這一步的操作就可以將整合后的工程打包在一個IP。這里也有將這個工程IP添加到全局的設置,如果有需要的可以嘗試一下。
五、bd設計,調用自定義IP
首先創建bd文件,然后調用zynq內核,這部分是基礎操作,不做過多的說明。
配置內核也是按照開發板的習慣配置。需要添加UART和DDR,其他的基本默認。(在前面的基礎實驗中的操作都適用)(例如bank0和bank1的電壓,我的是3.3和1.8)
調用自定義的IP加入設計
直接搜索輸入user好像會自動顯示自定義IP,沒有試過其他的,我的可以。
加入之后就先自連,再引線,有強迫症的可以用一下整理。
這時候需要引出輸入輸出引腳到芯片外部,直接在引腳上右擊,然后make external,就可以直接連上外部引腳(當然,你得配置管腳以到具體的引腳)。
這時候的bd設計就已經完成了。
這里要注意系統分配的寄存器地址。在多個自定義設計中可能會用到。這個地址也會直接影響后面的軟件操作。
六、構建硬件平台
bd文件只不過是一個IP集合,沒有例化,自然不能直接往里面寫軟件。
在所屬bd文件上右擊》generate product 》create HDL wizard
這兩步理解一下。generate productor是用於例化IP核的。bd文件將所有IP核的關系描述清楚后,需要將設計轉化為具體的verilog模塊來實現這種關系。至於create HDL wizard,就是自動例化頂層,相當於系統自動將bd的頭部用verilog包裝(你默認語言是verilog的話)。
分配引腳:在 open elboarded design中分配好管腳。
就可以綜合映射得到bit流文件。操作上可以直接生成bitstream。
然后生成硬件平台,這就意味着硬件設計的結束。作為硬件開發者來說,就可以收工了。但是,了解軟件部分的設計可以有效提高硬件的設計視野,這也是比較重要的部分。
此外,一定要在Tcl Console中查看一下hardware是否成功。vovado不會自動跳轉到tcl,所以要注意一下。反正我的licence在這里總是失效。好像重啟軟件有用,也沒啥好的解決方案。
這里還需要勾選包含bitstream,這個不要忘了。
七、軟件設計
進入vitis,出現初始界面。這個過程比較長,不用太過驚訝。
一般來說,vitis默認的進入界面是上次的界面,所以需要整理一下。
加載硬件的方法在前面的GPIO實驗中已經說明過了,這里就簡述。
new》新建app》輸入工程名》創建硬件平台(第二面,加號選擇工程的xsa文件)》默認到底。
打開helloworld.c文件:
替換為
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "sleep.h" #include "string.h" #define IIC_BASEADDRESS 0x43C00000 #define REG0_OFFSET 0 #define REG1_OFFSET 4 u32 gpio_input_value=0; char buf_print[64]={0}; int main() { int i=0; init_platform(); print("Hello World\n\r"); while(1) { for(i=0;i<64;i++)buf_print[i]=0; gpio_input_value=Xil_In32(IIC_BASEADDRESS+REG1_OFFSET); sprintf(buf_print,"input gpio_value=%d\r\n",gpio_input_value); print(buf_print); Xil_Out32(IIC_BASEADDRESS+REG0_OFFSET,0); sleep(1); Xil_Out32(IIC_BASEADDRESS+REG0_OFFSET,0xffffffff); sleep(1); } cleanup_platform(); return 0; }
代碼源自小熊貓課堂
這里同樣不分析代碼的內容,這是另外一個系列的學習內容,這里只是作為長見識。
保存---編譯---調試---運行
就可以快速地將代碼運行在開發板上。
3、實驗結果
由於前面例化IP核時一個端口聲明出現錯誤,而且當時沒有做綜合。導致又重來了一遍。教訓呀。
這里總結一下更改的經驗:
1、不要該IP的頂端,因為后面的輸入輸出信號與這里直接相關,牽一發而動全身。
2、不要省略每一個檢查步驟,因為那都是用時間堆出來的教訓。
3、更改的話以內部修改為主,不得已才去動外部設計。
4、總結
不知道是不是由於從SDK移植的代碼不適用於vitis,還是代碼設置出現錯誤,最后只是燈閃爍,IO和UART均不工作。果然還是要自己寫代碼。以后有機會再修正吧,目前暫時這樣做。
5、追加
通過一次重頭再來的排查,發現只有一個燈閃爍是因為輸入輸出在位數上發生錯位導致數據丟失。串口沒有反應是由於手賤多點了一個UART0,(實際上我那時修改過一次但是沒有保存)所以在這里提醒操作要細心,不然費時費力、
下面附上實驗結果:
實拍視頻: