概 述
ZYNQ 的工程設計大體上可以分為 對硬體邏輯系統的設計 和 對 CPU 軟體程式的設計
- 硬體邏輯系統設計:搭建一個滿足使用者需求的硬體環境,通過 Vivado 實作
- CPU 程式設計:通過使用者程式控制 CPU 工作,使整個系統達到預定的效果,該部分通過 Vitis 實作
兩者間的關系及具體設計步驟如下圖所示
xsa 檔案為硬體資源描述檔案,可以通過生成比特流或生成子產品設計産生
- 涉及到 PL 端的設計:導出 xsa 檔案時需要包含比特流,是以通常使用 生成比特流(bit stream) 的方式産生 xsa 檔案
- 純 PS 端的設計:導出時不需要比特流,是以兩種方式皆可
接下來以按鍵控制 led 工程為例介紹 ZYNQ 開發的基本流程,本設計實作的功能如下
- 按下 PS 端按鍵 SW3,PL 端小燈 LED1 亮起,松開則小燈熄滅
- 按下 PL 端按鍵 SW1,PS 端小燈 LED5 亮起,松開則小燈熄滅
硬體邏輯系統設計
建立 Vivado 工程
輕按兩下打開 Vivado,點選 Create Project
填寫工程名稱并選擇儲存路徑,勾選 Create project subdirectory 則項目儲存在 {Project location}/{Project name} 檔案夾下,點選 Next
選擇 RTL Project,點選 Next
根據實際情況選擇晶片,筆者所用開發闆型号為 MZ7035FD,晶片型号為 xc7z035ffg676-2,點選 Next
點選 Finish,項目建立完成
建立子產品設計
點選 Create Block Design 建立子產品設計
在彈出的視窗中修改設計命名(注意不能包含中文及空格),點選 OK 完成建立
可以看到 Design 欄出現了我們剛建立好的 system 子產品設計
建構硬體系統
此時我們的設計内沒有任何内容,需要點選 + 為設計添加 IP 核
在彈出的搜尋欄中輸入 zynq,可以看到下方出現了 ZYNQ7 Processing System,輕按兩下該 IP 核添加
ZYNQ IP 核的配置通常有兩個必需配置的部分:使能外設和配置 DDR 型号。輕按兩下 ZYNQ IP 核即可打開配置界面,如下圖所示
右側欄為 ZYNQ 的圖形化向導界面,綠色部分為可配置界面,單擊即可快速跳轉到對應項設定。左側欄為 ZYNQ IP 核配置的導航視窗,共分為 8 個部分,對應功能如下
- ZYNQ Block Design:圖形化向導界面
- PS-PL Configuration:PS-PL 接口配置界面,可以對 AXI、HP、DMA 等總線接口進行配置
- Peripheral I/O Pins:I/O 外設引腳配置界面,可對 I/O 外設引腳進行 MIO 以及 EMIO 的配置,配置時需要注意 Bank 電平
- MIO Configuration:MIO 配置界面,相較于 I/O 外設引腳配置界面功能更為複雜
- Clock Configuration:時鐘配置界面,用于配置 PS 輸入時鐘、外設時鐘、DDR 時鐘和 CPU 時鐘等
- DDR Configuration:DDR 配置界面,控制 DDR 型号以及細節參數等
- SMC Timing Calculation:SMC 時序計算界面,可進行 SMC 時序計算
- Interrupts:中斷控制界面,可對 PS 與 PL 間的中斷進行配置
ZYNQ 中的外設接口由對應控制器控制,使用時需要先進行使能。點選圖形化向導界面的 I/O Peripherals 中對應的外設接口便可以跳轉到相應的配置界面,點選 GPIO 即可進入相應配置界面
本設計通過 PS 與 PL 側的按鍵控制另一側的 LED 燈,每個按鍵和 LED 燈都需要一個 GPIO 信号。GPIO 連接配接到 PS 部分使用的是 MIO 接口,連接配接到 PL 部分使用的則是 EMIO 接口,是以我們需要使能這兩個外設接口。PS 端的引腳是固定的,我們不需要配置設定;PL 端的按鍵和 LED 燈都需要一個 EMIO 信号,是以我們将 EMIO 的位寬設定為 2
設定完成後檢查電平狀态,将 Bank1 的電平設定為 1.8V
使能完成後傳回圖形化向導界面,可以看到此時在 GPIO 外設後面已經打上 √ 了,代表我們已經使能該接口
接下來開始配置 DDR,DDR 全名為雙速率同步動态随機存儲器(Double Data Rate Synchronous Dynamic Random Access Memory),也就是我們常說的 記憶體。基于 PS 端的應用,大部分都需要基于片外存儲外設 DDR 上允許。點選圖像化界面的 DDR 控制器即可跳轉到配置界面
使能 DDR 并選擇 DDR 型号,筆者使用的是 MT41K256M16 RE-125
點選 OK,可以看到此時 ZYNQ 的 IP 核如圖所示
點選上方的藍色小字 Run Block Automation 系統就會自動幫我們導出引腳,勾選 All Automation 後點選 OK 即可
導出完成後可以看到軟體幫我們導出了 ZYNQ 的兩個引腳,但 GPIO_0 還未導出,是以我們需要手動将其導出
點選 GPIO_0 引腳,然後右鍵點選 Make External 導出引腳
該設計中 ZYNQ IP 核在配置時,有幾個端口信号是沒有被使用到的
- FCLK_RESET0_N:全局複位信号,低電平有效
- M_AXI_GP0:通用 AXI 接口信号,M 代表其作為主機信号
- M_AXI_GP0_ACLK:M_AXI_GP0 的輸入時鐘信号
- FCLK_CLK0:PS 輸出時鐘信号
其中,M_AXI_GP0_ACLK 雖然本設計中并未使用到,但如果不給其一個輸入信号,軟體便會報錯
為了防止出現該現象,我們隻需要将 FCLK_CLK0 和 M_AXI_GP0_ACLK 連接配接即可。連接配接時隻需選中其中一個引腳按住滑鼠左鍵拖動到對應的引腳即可
端口連接配接完成後使用快捷鍵 Ctrl+S 儲存設計,随後點選上方的 √ 來對設計進行驗證
當出現以下彈窗時證明設計無誤
生成封裝
點選 sources 資源欄我們建立的 system 子產品設計,右鍵選擇 Generate Output Products 生成輸出
選擇 Out Of context per IP,點選 Generate
點選 sources 資源欄我們建立的 system 子產品設計,右鍵選擇 Create HDL Wrapper 以建立 HDL 封裝
在彈出的視窗中選擇讓 Vivado 管理封裝和自動更新,随後點選 OK 開始建立封裝
如果工程資源欄的右上角出現 Updating 的字樣表明封裝正在建立和更新中,當字樣消失且 Sources 欄出現藍色名為 system_wrapper 的設計檔案時,則代表封裝已經建立和更新完成
管腳限制
對于涉及 PL 端的設計,在完成封裝後我們需要對涉及到的管腳進行配置設定和限制。點選左側導航欄的 Open Elaborated Design 進行限制和配置設定
點選 OK
根據實際情況綁定引腳并設定電平限制,筆者使用的 MZ7035FD 闆載接口如下
闆載裝置 | ZYNQ 接口 |
SW1 | H12 |
SW3 | MIO50 |
LED1 | F13 |
LED5 | MIO51 |
使用快捷鍵 Ctrl+S 儲存限制檔案,在彈窗中輸入限制檔案名,點選 OK 即可
生成比特流
完成了管腳限制後即可開始比特流的生成,比特流中包含着對 PL 端的配置資訊,其中就包括對 引腳的配置設定 以及 電平的限制,是以生成比特流需要在進行管腳配置設定和限制之後。當然如果設計并未使用到 PL 部分資源,可以直接跳過該環節。點選左側工具欄 Generate Bitstream 開始生成比特流
此時軟體會提示 ”沒有可用的實作結果,是否先進行綜合實作再自動生成比特流“,我們直接點選 Yes 即可
導出硬體
File > Export > Export Hardware
點選 Next
對于純 PS 端的設計,選擇哪一項都可以,而涉及到 PL 端的設計必須選擇 Include bitstream,點選 Next
設定 xsa 檔案名稱及儲存路徑,點選 Next
點選 Finish 即可
啟動 Vitis
硬體導出完成後 Vivado 部分的設計已經完成,接下來打開 Vitis 開始 CPU 軟體程式設計。點選 Tools > Launch Vitis IDE
CPU 軟體程式設計
建立工程
Vitis 将晶片視為一個平台,平台的相關資訊通過此前導出的 xsa 檔案描述,工程間的關系如下
File > New > Application Project,點選 Next
選擇 Create a new platform from hardware (XSA),點選 Browse 選擇此前導出的 xsa 檔案,或者從清單中選擇與開發闆相比對的
等待 xsa 檔案加載完成,點選 Next
設定工程名稱,點選 Next
點選 Next
選擇工程模闆,點選 Finish 即完成建立
點選 Finish 即可完成建立
添加應用庫
對于某些開發闆,廠商可能提供已經編寫完善的應用庫,若要使用這些應用庫就需要将相關檔案添加到項目中。以應用庫 MZ7035FD_Lib 為例,首先将檔案夾複制到項目中
選中項目,右鍵 Properties
選擇 Paths and Symbols,點選右側 Add 将應用庫添加至頭檔案路徑,否則編譯時會提示找不到相關檔案
點選 Workspace
選擇應用庫檔案夾,點選 OK
點選 OK
點選 Apply and Close
添加使用者代碼
在項目 src 檔案夾下建立檔案 main.c
本設計示例代碼如下
/* main.c
*********************************************
* @Vivado 2022.1
* @Vitis 2022.1
* @Board MZ7035FD
* @Chip xc7z035ffg676-2
* @DDR MT41K256M16 RE-125
*********************************************
*/
#include "PS_GPIO/PS_GPIO.h"
#define PS_LED 51 // LED5
#define PS_KEY 50 // SW3
#define PL_LED 54 + 0 // LED1
#define PL_KEY 54 + 1 // SW1
int main()
{
// 初始化 PS 端 MIO 和 EMIO
PS_GPIO_Init();
// 設定 GPIO 模式
PS_GPIO_SetPinMode(PS_LED, GPIO_DIR_OUTPUT, GPIO_STATE_LOW);
PS_GPIO_SetPinMode(PS_KEY, GPIO_DIR_INPUT, GPIO_STATE_LOW);
PS_GPIO_SetPinMode(PL_LED, GPIO_DIR_OUTPUT, GPIO_STATE_LOW);
PS_GPIO_SetPinMode(PL_KEY, GPIO_DIR_INPUT, GPIO_STATE_LOW);
// 循環讀取按鍵狀态
while(1)
{
PS_GPIO_WritePin(PS_LED, PS_GPIO_ReadPin(PL_KEY) == GPIO_STATE_HIGH ? GPIO_STATE_LOW : GPIO_STATE_HIGH);
PS_GPIO_WritePin(PL_LED, PS_GPIO_ReadPin(PS_KEY) == GPIO_STATE_HIGH ? GPIO_STATE_LOW : GPIO_STATE_HIGH);
}
return 0;
}
/* PS_GPIO.h
*********************************************
* @Vivado 2022.1
* @Vitis 2022.1
* @Board MZ7035FD
* @Chip xc7z035ffg676-2
* @DDR MT41K256M16 RE-125
*********************************************
*/
#ifndef __PS_GPIO_H__
#define __PS_GPIO_H__
#include "xgpiops.h"
#define GPIO_DIR_INPUT 0 // 設定 GPIO 為輸入
#define GPIO_DIR_OUTPUT 1 // 設定 GPIO 為輸出
#define GPIO_OUTPUT_ENABLE 1 // 使能 GPIO 輸出
#define GPIO_OUTPUT_DISABLE 0 // 禁用 GPIO 輸出
#define GPIO_STATE_LOW 0 // GPIO 為低電平
#define GPIO_STATE_HIGH 1 // GPIO 為高電平
void PS_GPIO_Init();
void PS_GPIO_SetPinMode(uint8_t GPIO_Num, uint8_t GPIO_Dir, uint8_t GPIO_Default_State);
void PS_GPIO_WritePin(uint8_t GPIO_Num, uint8_t GPIO_State);
uint8_t PS_GPIO_ReadPin(uint8_t GPIO_Num);
#endif
/* PS_GPIO.c
*********************************************
* @Vivado 2022.1
* @Vitis 2022.1
* @Board MZ7035FD
* @Chip xc7z035ffg676-2
* @DDR MT41K256M16 RE-125
*********************************************
*/
#include "PS_GPIO.h"
// GPIO 執行個體對象
XGpioPs GpioPs;
/*
* @brief 初始化 PS 端 MIO 和 EMIO
*/
void PS_GPIO_Init()
{
// 擷取 PS 端 GPIO 配置
XGpioPs_Config *ConfigPtr = XGpioPs_LookupConfig(XPAR_XGPIOPS_0_DEVICE_ID);
// 初始化 PS 端 GPIO 執行個體
XGpioPs_CfgInitialize(&GpioPs, ConfigPtr, ConfigPtr->BaseAddr);
}
/*
* @brief 設定單個 GPIO 引腳模式
* @param GPIO_Num GPIO 編号(MIO:0~53,EMIO:54~)
* @param GPIO_Dir GPIO 方向(輸入/輸出)
* @param GPIO_Default_Output GPIO 預設輸出(GPIO設定為輸出時有效)
*/
void PS_GPIO_SetPinMode(uint8_t GPIO_Num, uint8_t GPIO_Dir, uint8_t GPIO_Default_State)
{
// 設定 GPIO 輸入/輸出方向
XGpioPs_SetDirectionPin(&GpioPs, GPIO_Num, GPIO_Dir);
// 輸出模式需要使能并設定預設輸出電平
if(GPIO_Dir == GPIO_DIR_OUTPUT)
{
// 使能 GPIO 輸出
XGpioPs_SetOutputEnablePin(&GpioPs, GPIO_Num, GPIO_OUTPUT_ENABLE);
// 設定預設輸出
XGpioPs_WritePin(&GpioPs, GPIO_Num, GPIO_Default_State);
}
}
/*
* @brief 寫入 GPIO 電平
* @param GPIO_Num GPIO 編号(MIO:0~53,EMIO:54~)
* @param GPIO_State 待寫入的 GPIO 電平狀态
*/
void PS_GPIO_WritePin(uint8_t GPIO_Num, uint8_t GPIO_State)
{
XGpioPs_WritePin(&GpioPs, GPIO_Num, GPIO_State);
}
/*
* @brief 讀取 GPIO 電平
* @param GPIO_Num GPIO 編号(MIO:0~53,EMIO:54~)
* @return 高電平輸出 1,低電平輸出 0
*/
uint8_t PS_GPIO_ReadPin(uint8_t GPIO_Num)
{
return XGpioPs_ReadPin(&GpioPs, GPIO_Num);
}
闆級驗證與調試
選擇工具欄運作按鈕,點選 Run Configurations...
輕按兩下 Single Application Debug (GDB) 建立配置
選擇 Target Setup,取消勾選 Reset entire system,否則燒錄後會報錯
點選運作按鈕即可自動下闆運作
點選調試按鈕即可下闆調試
調試相關按鈕(全速運作、暫停、停止、進入函數、跳過語句)
Vitis 聯合 VSC 程式設計
Vitis 在編寫代碼時需要通過快捷鍵 Alt+? 啟用代碼提示,使用體驗非常差。為此下面介紹如何使用 VS Code 編寫代碼,效果如下
首先在 VS Code 中打開 Vitis 項目檔案夾
點選報錯部分 > 快捷鍵 Alt + Enter > 編輯 "includePath" 設定
此時 VS Code 會在項目根路徑下生成 .vscode 配置檔案夾,我們需要在 c_cpp_properties.json 檔案中添加頭檔案路徑。其中${default} 代表 C/C++ 插件全局配置中設定的 Include,我們還需要添加該項目需要的頭檔案
Vitis 項目依賴的頭檔案均在平台工程 (Platform Project) system_wrapper 中,由上圖可知 system_wrapper 和 應用工程 (Application Project) gpio_axi_system 檔案夾平級,是以添加頭檔案路徑如下 (xxx/** 會自動周遊 xxx 檔案夾下的所有子檔案和子檔案夾)
此時按住 Ctrl 并用滑鼠點選變量、函數名等已可以檢視其定義,但仍然會有紅色波浪線報錯
在 .vscode 檔案夾下建立 settings.json 配置檔案,并添加如下内容
{
"C_Cpp.intelliSenseEngineFallback": "disabled",
"C_Cpp.intelliSenseEngine": "Tag Parser"
}
紅色波浪線報錯消失,開始用 VS Code 愉快地程式設計吧!
Vivado 聯合 Modelsim 仿真
Modelsim 在仿真速度和使用體驗上均要優于 Vivado 自帶的 Vsim,是以接下來将介紹如何在 Vivado 中調用 Modelsim 進行仿真
編譯 Vivado 仿真庫
Modelsim 安裝完成後并不包含 Xilinx 相關的器件庫,是以需要先編譯後才能使用。打開 Vivado,Tools > Compile Simulation Libraries
設定 Simulator 為 Modelsim Simulator,選擇編譯庫存放路徑和 modelsim.exe 所在檔案夾,勾選 Compile Xilinx IP,點選 Compile
等待編譯完成
設定仿真工具和庫路徑
Vivado 建立工程的預設仿真工具是 Vsim,是以要使用 Modelsim 仿真,每個新工程都要設定一次。點選 Tools > Settings
側邊欄選中 Simulation,設定 Target Simulator 為 Modelsim Simulator,點選 Yes
設定 Xilinx 編譯庫路徑,點選 OK
點選側邊欄 Run Simulation > Run Behavioral Simulation
等待 Modelsim 仿真結果,大功告成!
參考文獻
[1] 小梅哥. 基于C程式設計的Zynq裸機程式設計與應用教程
[2] 皮皮祥. Vivado 關聯 Modelsim 進行仿真