在 UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-A53 中我們題到了如何透過 Vivado 去建立我們的專案,讓 UltraZed-EG PCIe Carrier Card 上的處理器系統 (Processing Syste, PS) 裡面的 Cortex-A53 可以透過 AXI_GPIO 去對可程式邏輯區 (Programmable Logic, PL) 端的 LEDs D12 ~ D19 進行輸出的控制。
在這篇文章,我們要講的則是如何透過 AXI_GPIO 來處理 輸入 的控制,並讓 Cortex-R5 根據不同的輸入,在 ps_uart1 輸出不同的訊息,以及控制不同的 LED 亮暗。
(本文以 Vivado 2018.2 進行開發)
開發目標
和 UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-A53 一文很像,只是這次我們把目標轉向 Cortex-R5 ,以及將 GPIO 輸出的功能,改成 GPIO 輸入。
這次我們將透過 ps_uart1 輸出 Cortex-R5 上的訊息,並透過 AXI_GPIO 搭配 interrupt 的使用,去偵測使用者按下可程式邏輯(Programmable Logic, PL) 端的 SW2 ~ SW4 這三個無段按鈕。
建立專案
首先讓我們打開 Vivado 吧~ 不過在進行這一步之前,請先確定你有依照 讓 Vivado 有 UltraZed-EG PCIe Carrier Card 的設定檔 一文的說明,讓我們在建立專案的時候可以找到 UltraZed-EG PCIe Carrier Card 這塊板子。
啟動了 Vivado 後,點選 Create New Project
接下來指定好專案路徑和名稱
選擇 RTL Project ,並將 Do not specify sources at this time 打勾,我們暫時不會匯入已經有的 verilog 程式碼
點選 Boards ,選擇 UltraZed-EG PCIe Carrier Card
完成專案的建立
建立 Block Design
和之前的文章一樣,我們的專案需要用到 Xilinx 一些預先定義好的 IP, 因此使用 Block Design 來建立我們的設計。
首先點選 IP Integrator -> Create Block Design
接著點選 OK 建立我們的 Block Design
點選 Add IP 按鈕去增加我們需要的 IP 核
我們首先尋找 Zynq UltraScale+ MPSoC 並將它加入到我們的 Block Design,並點選 Run BLock Automation 對該 IP 做一些設定
由於預設的 Zynq UltraScale+ MPSoC 並不會打開可程式邏輯 (Programmable Logic, PL) 對應到處理器系統 (Processing System, PS) 的中斷控制 (PL-PS interrupt),因此我們要自己打開。
點擊 Zynq UltraScale+ MPSoC 兩下來對其進行設定,你會看到這樣的頁面,選擇 PS-PL Configuration
接下來,點選 General -> Interrupts -> PL to PS -> IRQ0[0-7] 將其變成 1 ,完成後點選 OK
你會看到我們的 Zynq UltraScale+ MPSoC 增加了 pl_ps_irq0[0:0] 這個輸入界面,如果有需要的話則再 Run Block Automation 一次。
接下來,將 Board 裡面的 Push buttons 拉到我們的 Diagram 去
目前電路變成這樣
接下來,再把 Board 上的 LED 拉到 axi_gpio_0 上面,讓整個電路變成這樣
對 axi_gpio_0 點擊兩下,進入到以下設定頁面
在這邊,我們將 Enable Interrupt 打開,點選 OK 完成設定
我們拉條線將 ip2intc_irpt 接到 pl_ps_irq0[0:0] 上,讓 interrupt 可以運作
完成後,點選 Run Connection Automation 進行線路連接,現在電路會變成這樣
(注意到 ip2intc_irpt 一定要連接到 pl_ps_irq0[0:0] 上呦,也就是橘色線的這一條)
完成後可以點選 Validate Design 按鈕來確認設計沒問題
好了,讓我們來產生 HDL Wrapper 吧 ~
產生 HDL Wrapper
接下來我們要將剛剛用 Block Design 建立的電路變成 verilog 程式碼,因此會需要進行產生 HDL Wrapper 這個步驟。
對你的 Block Design 檔案點選右鍵,選擇 Create HDL Wrapper ,它會根據你專案設定的語言 (VHDL 或是 Verilog) 來產生相對的 HDL 程式碼。
由於這次我們不需要對產出來的東西進行修改,因此選 Let Vivado manage wrapper and auto-update 即可
好了後,假設你的 Block Design 檔案叫做 design_1.bd ,那就會產生 design_1_wrapper.v 或是 design_1_wrapper.vhdl 這樣的檔案。
產生位元流 (bitstream)
前面的處理都好了後,接下來點選 Program and Debug -> Generate Bitstream 去讓 Viavado 將這個專案產生出
位元流 (bitstream) ,Zynq UltraScale+ 會在開機的時候根據 bitstream 的資訊對 FPGA 進行設定。
這個產生的過程視你的電腦強度如何而決定花多少時間,總之先來泡杯茶吧~
當 bitstream 完成後,我們準備執行 Xilinx SDK 來透過寫 C 語言專案來讓 Cortex-R 可以透過 AXI_GPIO 偵測 SW2 ~ SW4 的中斷(interrupt) ,並根據不同按鈕的觸發來對 LED 進行控制。
點選 File -> Export -> Export Hardware 將剛剛產生的硬體資訊輸出給 Xilinx SDK 去。
確定你有勾選 Include bitstream 後,點選 OK
完成後,執行 Xilinx SDK
建立 Xilinx SDK 專案
啟動 Xilinx SDK 後,點選 File -> New -> Application Project 去建立新的專案
這邊我命名此一專案為 helloR5 ,並指定為 standalone 的程式,注意到 Processor 要選擇 psu_cortex45_0
接下來,我們一樣選擇 Hello World 來作為我們的專案樣板,點選 Finish 完成專案建立。
打開 helloworld.c
點選左邊欄位的 helloR5 -> src -> helloworld.c 來編輯我們的主程式,你會看到以下的內容
/* * helloworld.c: simple test application * * This application configures UART 16550 to baud rate 9600. * PS7 UART (Zynq) is not initialized by this application, since * bootrom/bsp configures it to baud rate 115200 * * ------------------------------------------------ * | UART TYPE BAUD RATE | * ------------------------------------------------ * uartns550 9600 * uartlite Configurable only in HW design * ps7_uart 115200 (configured by bootrom/bsp) */ #include <stdio.h> #include "platform.h" #include "xil_printf.h" int main() { init_platform(); print("Hello World\n\r"); cleanup_platform(); return 0; }
這個程式預設會直接透過 Xilinx 定義好的 print() 函式透過當前開發板的 ps7_uart 進行輸出,以這塊板子而言,就是透過 ps_uart0 也就是 Linux 端的 /dev/ttyUSB1 會得到訊息,讓我們修改一下預設的輸出吧。
設定輸出的 UART
在本文一開始,我們題到了我們這次希望透過 ps_uart1 輸出,也就是希望 Linux 端的 /dev/ttyUSB0 可以收到訊息,那這樣要怎樣做呢?
首先點選 Xilinx -> Board Support Packages Settings
選擇 helloR5_bsp
點選 Overview -> standalone 設定 stdin 和 stdout 成 ps_uart1 ,變成如下圖這樣
點選 OK ,完成設定,這樣這個專案透過 print() 或是 xil_printf() 輸出的訊息就都是從 ps_uart1 也就是 Linux 端的 /dev/ttyUSB0 進行輸出囉~