在 zybo board 開發記錄: 透過可程式邏輯控制 LED 閃爍 一文中我們說到了怎樣純粹使用 可程式邏輯 (Programmable Logic, PL) 去控制 Zybo board 上面的四個 LED 燈 (LD0 ~ LD3),接下來就讓我們透過 Zynq 上的 ARM 處理器來作到同樣的一件事情吧。
(本文以 Vivado 2016.2 進行開發)
本文主要參考自 Digilentinc 的 Getting Start Guide 並加入我自己試玩的一些心得。
開發目標
我們要透過 Zynq 上的 ARM 處理器,也就是 處理系統 (Processing System, PS)去控制 LED,具體目標與電路資訊如下:
根據 ZYBO FPGA Board Reference Manual 上面的資料,我們想要控制的這四個在板子上的 LED 都是位於可程式邏輯區(Programmable Logic, PL)可以碰觸到的地方,如果你想要透過 Zynq 去對這些 LED 進行控制,你就會需要透過 AXI GPIO 的幫助,就像這樣:
認識 AXI 匯流排
AXI 匯流排是作什麼用的?我們就從 Zynq 的架構來看 (參照 The Zynq Book p.28)
由上圖可以看到 AXI 匯流排橫跨了處理器系統 (Processing System, PS) 與可程式邏輯 (Programmable Logc, PL) 兩區,並連接到週邊。
實際上,AXI 協議為 ARM 的協議規範,來自於 AMBA 匯流排架構,若你對整個協議的內容有興趣,可以到 ARM 的 網站 去下載規格書。
建立我們的專案
我們首先當然是建立我們的專案了,在進行這一步前,請先確定你有按照 讓 Vivado 有 Zybo Board 的設定檔 一文所說,將 Zybo board 的設計導入。
啟動了 Vivado 後,點選 Create New Project 。
接下來指定好你的專案名稱與路徑
選擇 RTL Project
在開發板選項中,選擇 Zybo Board
完成專案建立
建立 Block Design
當我們的設計需要用到 Zynq 的處理器系統(Processing System, PS)時候,就需要透過 Block Design 來建立我們的電路設計,首先點選 IP Integrator -> Create Block Design 。
接著點選 OK 建立我們的 block design
點選 Add IP 按鈕去增加我們需要的 IP 核
我們首先尋找 Zynq 並將 ZYNQ7 Processing System 加入到我們的 Block Design,並點選 Run Block Automation 對 Zynq 處理器進行一些設定
進入到 Run Block Automation 的設定頁面後,確認 processing_system7_0 有被勾選到,並且 Cross Trigger In 以及 Cross Trigger Out 都是 Disable 的狀態,點選 Ok 結束設定。
上面的設定好了後,就會看到 ZYNQ7 Processing System 的 DDR 以及 FIXED_IO 都有接線出來
點選 Add IP 按鈕去增加我們需要的 IP 核,這次我們要增加 AXI_GPIO ,用來對可程式邏輯(Programmable Logic, PL)區域的 LED 進行控制,完成後點選上方的 Run Connection Automation 按鈕
在 Run Conenction Automation 視窗內,我們選擇 Custom (其實也可以在這邊直接選擇 leds 4bits)
接下來勾選 S_AXI ,並點選 Ok 進行確認。
好了後會像這樣,我們接下來對 axi_gpio_0 這個區塊點兩下,進行手動設定
在 IP Configuration 頁面,設定 GPIO 為輸出腳,並設寬度為 4 ,這邊我將輸出預設值設定為 0xF, 也就是預設這四個 LED 用的輸出腳都是 High 的電壓。完成後點選 OK, 結束 AXI_GPIO 的設定。
接下來點選 Validate Design 按鈕,我們要確認我們的 Block Design 沒問題才能夠繼續往下走。
正常來講不會有啥問題才對,我們結束 Block Design 的工作
加入 Constraints
在 zybo board 開發記錄: 透過可程式邏輯控制 LED 閃爍 一文有提到如何取得 Constraints 檔案,不過為了讓這篇文章完整,我們再講一次。
我們先連結到 Zybo Resource Center 去下載 Master XDC 檔案。
你也可以直接透過 wget 命令下載並解壓出 ZYBO_Master.xdc 這個檔案,它就是本節要加入的 Constraints 檔
coldnew@gentoo /tmp $ wget https://reference.digilentinc.com/_media/zybo/zybo_master_xdc.zip coldnew@gentoo /tmp $ unzip zybo_master_xdc.zip Archive: zybo_master_xdc.zip inflating: ZYBO_Master.xdc
接下來一樣選擇 Project Manager -> Add sources 來增加檔案
這次我們要增加的是 Constraints 檔,因此選擇 Add or create constraints
透過 Add Files 添加剛剛下載的 ZYBO_Master.xdc 檔案
ZYBO_Master.xdc
在 ZYBO_Master.xdc 裡面,預設所有對應接腳都是被註解掉的,這邊我們反註解我們需要的 led 接腳,要記得一下這邊的 I/O 名稱,我們等等要和產生出來的 HDL Wrapper 進行對應的工作。
##LEDs ##IO_L23P_T3_35 set_property PACKAGE_PIN M14 [get_ports {led[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}] ##IO_L23N_T3_35 set_property PACKAGE_PIN M15 [get_ports {led[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}] ##IO_0_35 set_property PACKAGE_PIN G14 [get_ports {led[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}] ##IO_L3N_T0_DQS_AD1N_35 set_property PACKAGE_PIN D18 [get_ports {led[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
這樣我們就可以準備將 Block Design 和硬體接腳對應在一起了。
產生 HDL Wrapper
接下來我們要透過 Block Design 產生我們的 HDL wrapper,對你的 Block Design 檔案點選右鍵,選擇 Create HDL Wrapper 。它會根據你專案設定的語言 (VHDL 或是 Verilog) 來產生相對的 HDL 程式碼。
產生出來的東西我們可能需要改些東西,為了避免麻煩這邊我選第一個選項。
好了後,假設你的 Block Design 檔案叫做 design_1.bd,那就會產生 design_1_wrapper.v 或是 design_1_wrapper.vhdl 這樣的檔案
我們接著要修改這個 HDL Wrapper,這是為什麼呢? 回去看一下前面做好的 Block Design 以及 Constraints 的資訊,我們可以看到 Block Design 設定好的 AXI_GPIO 其輸出腳叫做 gpio_rtl ,而在 Constraints 中,我們目標的 LED 輸出腳名稱是 led ,因此我們要調整一下這個 HDL Wrapper 讓 gpio_rtl 和 led 可以對應在一起。
由於在本範例中,design_1_wrapper.v 也就是 toplevel 的模組,因此在這邊將對外的 gpio_rtl_tri_o 接腳改為 led 讓它接出即可。
diff --git a/led_flash_zynq.srcs/sources_1/imports/hdl/design_1_wrapper.v b/led_flash_zynq.srcs/sources_1/imports/hdl/design_1_wrapper.v index 7b1b0bd..c57caa0 100644 --- a/led_flash_zynq.srcs/sources_1/imports/hdl/design_1_wrapper.v +++ b/led_flash_zynq.srcs/sources_1/imports/hdl/design_1_wrapper.v @@ -31,7 +31,7 @@ module design_1_wrapper FIXED_IO_ps_clk, FIXED_IO_ps_porb, FIXED_IO_ps_srstb, - gpio_rtl_tri_o); + led); inout [14:0]DDR_addr; inout [2:0]DDR_ba; inout DDR_cas_n; @@ -53,7 +53,7 @@ module design_1_wrapper inout FIXED_IO_ps_clk; inout FIXED_IO_ps_porb; inout FIXED_IO_ps_srstb; - output [3:0]gpio_rtl_tri_o; + output [3:0]led; wire [14:0]DDR_addr; wire [2:0]DDR_ba; @@ -76,7 +76,7 @@ module design_1_wrapper wire FIXED_IO_ps_clk; wire FIXED_IO_ps_porb; wire FIXED_IO_ps_srstb; - wire [3:0]gpio_rtl_tri_o; + wire [3:0]led; design_1 design_1_i (.DDR_addr(DDR_addr), @@ -100,5 +100,5 @@ module design_1_wrapper .FIXED_IO_ps_clk(FIXED_IO_ps_clk), .FIXED_IO_ps_porb(FIXED_IO_ps_porb), .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb), - .gpio_rtl_tri_o(gpio_rtl_tri_o)); + .gpio_rtl_tri_o(led)); endmodule
改好後,點選上方的 Run Implementation 來確認我們這樣的修改是否能編譯/驗證成功。