軟體版本:Anlogic -TD5.9.1-DR1_ES1.1
作業系統:WIN10 64bit
硬體平臺:適用安路(Anlogic)FPGA
實驗平臺:米聯客-MLK-L1-CZ06-DR1M90G開發板
板卡獲取平臺:https://milianke.tmall.com/
登入"米聯客"FPGA社群 http://www.uisrc.com 影片課程、答疑解惑!
1 概述
本課對FPSoC晶片GPIO進行介紹,透過點亮PS LED和PL LED以及讀取PL按鍵輸入值,來控制LED燈閃爍,演示GPIO PS和GPIO PL的使用方法。
本文實驗目的:
1:熟悉FPSoC PS部分PSIO的內部結構、相關暫存器
2:掌握FPSoC IP核中如何分配GPIO
3:掌握FD中如何使用PSIO
2系統框圖
PSIO一般會分配到固定的外設,包括FLASH、EMMC、TFCARD、UART、USB2.0、ETH乙太網。GPIO也可以單獨配置成普通的PSIO,如果IO不夠用也可以透過PLIO擴充套件更多IO。
3 GPIO介紹
3.1功能描述
GPIO(General Purpose I/O Ports),通用輸入/輸出埠。
DR1 器件含有通用I/O(GPI0)外設透過PS IO 模組為軟體提供多達54個裝置引腳的觀察和控制。它還透過PL IO 介面提供對來自可程式設計邏輯(PL)的64 個輸入和PL 的128 個輸出的訪問。GPI0 被組織成四組暫存器,對相關介面訊號進行分組。每個GPI0 作為輸入、輸出或中斷感測是獨立和動態程式設計。軟體可以使用單個載入指令讀取bank 內的所有GPI0 值,或者使用單個儲存指令將資料寫入一個或多個GPIO(在GPIO 的範圍內)。
軟體將 GPIO配置為輸出或輸入。無論 GPIO設定為輸入(OE 訊號 false)還是輸出(OE 訊號true),資料暫存器始終返回GPIO引腳的狀態。為了生成輸出波形,軟體會重複寫入一個或多個 GPIO。
3.2 GPIO特性
1、裝置引腳的 54 GPI0 訊號(透過PS 10 多路複用器佈線)
-
輸出具有三態能力
2、PS 和PL 之間透過PL 10 介面的192 個GPIO 訊號(64 輸入+64輸出+64輸出使能)
-
64 個輸入,128 個輸出(64 個真實輸出和64 個輸出使能)
3、每個GPIO的功能可單獨或成組動態程式設計
4、支援位或列資料方式對 GP10 進行寫入、輸出使能和方向控制
5、基於單個 GPIO 的可程式設計中斷
-
支援初始和遮蔽中斷的狀態讀取
-
支援中斷可選靈敏度:電平敏感(高或低)或邊緣敏感(正或負)
6、配置為 GPIO 的時候,預設狀態是輸入上拉
3.3 關鍵暫存器
名稱 |
暫存器名 |
功能描述 |
配置控制暫存器 |
GPIO SWPORTA DR BLK0-3 GPIO SWPORTA DDR BLK0-3 GPIO SWPORTA DR CLR BLK0-3 GPIO SWPORTA DDR CLR BLK0-3 |
控制 GPIO 的輸入/輸出,清除輸入/輸出的資料。 |
中斷暫存器 |
GPIO INTEN CLR BLK0-3 GPIO INTMASK CLR BLK0-3 GPIO INTTYPE LEVEL CLR BLK0-3 GPIO INT POLARITY_CLR_BLK0-3 GPIO INT BOTHEDGE CLR BLKO-3 |
中斷使能、中斷 mask、中斷清除,中斷響應極性設定。 |
Debounce暫存器 |
GPIO DEBOUNCE CLR BLK0-3 GPIO DEBOUNCE BLK0-3 |
GPIO 濾毛刺暫存器 |
4硬體電路分析
硬體介面和子卡模組請閱讀"附錄1"
配套工程的FPGA PIN腳定義路徑為soc_prj/uisrc/04_pin/ fpga_pin.adc
5搭建SOC系統工程
詳細的搭建過程這裡不再重複,對於初學讀者如果還不清楚如何建立SOC工程的,請學習"01Vitis Soc開發入門"這篇文章。
本文中的PS設定內容是新增加的GPIO PS以及GPIO PL部分,關於DDR、PSIO、CPU時鐘等設定請參考"01Vitis Soc開發入門"這篇文章。
5.1GPIO配置
01Vitis Soc開發入門"這篇文章中已經對特定功能的PSIO做了設定,只有剩餘的PSIO可以用於其他的自定義功能。以下設定未分配功能的PSIO,以及需要擴充套件的GPIO PL IO的數量。
5.2GPIO PL定義
設定好後,右擊選擇Create Design Port
設定IO名稱、IO型別、IO位寬
最終GPIO PL需要定義到FPGA的IO中,所以我們需要引出GPIO PL訊號到system_top頂層檔案
1 module system_top ( 2 output PL_LED, 3 input PL_KEY 4 ); 5 wire [1:0] pl_gpio_in; 6 wire [1:0] pl_gpio_out; 7 assign PL_LED = pl_gpio_out[0]; 8 assign pl_gpio_in[1] = PL_KEY; 9 system I_system ( 10 .pl_gpio_in (pl_gpio_in), 11 .pl_gpio_out(pl_gpio_out) 12 ); 13 14 endmodule
5.3編譯並匯出平臺檔案
以下步驟簡寫,有不清楚的看第1篇《01 Soc開發入門》文章。
匯出完成後,對應工程路徑的soc_hw路徑下有硬體平臺檔案:fpga_prj.hpf的檔案。根據硬體平臺檔案fpga_prj.hpf來建立需要Platform平臺。
6 搭建SDK工程
建立soc_base sdk platform和APP工程的過程不再重複,如果不清楚請參考本章節第一個demo。
6.1建立Platform工程
建立soc_base sdk platform和APP工程的過程不再重複,如果不清楚請參考本章節第一個demo《01 Soc開發入門》文章。
6.2建立gpio_ctl_led APP工程
7程式分析
Gpio_ctl_led.c
1 #include "al_gpio_hal.h" 2 3 #define PS_LED 51 //PS GPIO 51 4 #define PL_LED 54 //PL GPIO 01 5 #define PS_KEY 50 //PS GPIO 50 6 #define PL_KEY 55 //PL GPIO 02 7 #define LED_IN_BANK0 0x80000 8 #define LED_IN_BANK2 0x1 9 #define AL_GPIO_DEVICE_ID 0 10 #define AL_GPIO_DELAY_20MS 20 11 #define AL_GPIO_DELAY_2000MS 2000 12 13 AL_S32 AlGpio_Hal_Ctl_LED_Example() 14 { 15 AL_GPIO_HalStruct *GPIO; 16 AL_S32 PS_LedValue = 0; 17 AL_S32 PL_LedValue = 0; 18 AL_S32 PS_KeyValue = 0; 19 AL_S32 PL_KeyValue = 0; 20 21 /* 1、Test AlGpio_Hal_Init */ 22 AL_S32 ret = AlGpio_Hal_Init(&GPIO, AL_GPIO_DEVICE_ID, AL_NULL); 23 24 if (ret == AL_OK) { 25 AL_LOG(AL_LOG_LEVEL_INFO, "[TEST] APU AlGpio_Hal_Init success"); 26 } 27 else { 28 AL_LOG(AL_LOG_LEVEL_INFO, "[TEST] APU AlGpio_Hal_Init failed"); 29 } 30 31 /* 2、Test Gpio function through Bank. */ 32 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK1, LED_IN_BANK0); 33 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK2, LED_IN_BANK2); 34 AlSys_MDelay(AL_GPIO_DELAY_2000MS); 35 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK1, 0x0); 36 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK2, 0x0); 37 AlSys_MDelay(AL_GPIO_DELAY_2000MS); 38 39 40 /* 3、Test Gpio polling */ 41 PS_LedValue = AlGpio_Hal_ReadPinOutput(GPIO, PS_LED); 42 AL_LOG(AL_LOG_LEVEL_INFO, "GPIO PS led value is 0x%x", PS_LedValue); 43 PL_LedValue = AlGpio_Hal_ReadPinOutput(GPIO, PL_LED); 44 AL_LOG(AL_LOG_LEVEL_INFO, "GPIO PL led value is 0x%x", PL_LedValue); 45 46 while(1) 47 { 48 PS_KeyValue = AlGpio_Hal_ReadPinInput(GPIO, PS_KEY); 49 PL_KeyValue = AlGpio_Hal_ReadPinInput(GPIO, PL_KEY); 50 if(PS_KeyValue == 0|PL_KeyValue == 0){ 51 AlSys_MDelay(AL_GPIO_DELAY_20MS); 52 if (PS_KeyValue == 0|PL_KeyValue == 0) { 53 AlGpio_Hal_WritePin(GPIO, PS_LED, ~PS_LedValue); 54 AlGpio_Hal_WritePin(GPIO, PL_LED, ~PL_LedValue); 55 AlSys_MDelay(AL_GPIO_DELAY_20MS); 56 AlGpio_Hal_WritePin(GPIO, PS_LED, PS_LedValue); 57 AlGpio_Hal_WritePin(GPIO, PL_LED, PL_LedValue); 58 AlSys_MDelay(AL_GPIO_DELAY_20MS); 59 } 60 } 61 } 62 63 return AL_OK; 64 } 65 66 67 AL_S32 main(void) { 68 AL_LOG(AL_LOG_LEVEL_INFO, "[TEST]AlGpio_Hal_CTL_LED_Test start"); 69 AlGpio_Hal_Ctl_LED_Example(); 70 71 return AL_OK; 72 }
接下來對程式進行分析。
7.1GPIO位號定義
1 #define PS_LED 51 //PS GPIO 51 2 #define PL_LED 54 //PL GPIO 01 3 #define PS_KEY 50 //PS GPIO 50 4 #define PL_KEY 55 //PL GPIO 02
PS GPIO比較好確認,主要是根據原理圖確認好PSIO編號即可。GPIO PL擴充套件的GPIO需要根據繫結的FPGA PIN來劃分,GPIO PL [0]位對應的位號為54,是Bank 2中的第1位。其他的以此類推。
7.2GPIO操控方法
程式中使用了2種方式演示操控GPIO,依次分析:
方法1:直接操控對應Bank暫存器,下列程式分別對Bank1以及Bank2直接進行寫資料。由原理圖可知PS LED為PSIO51,Bank0的最大位號為31,所以Bank1的第1個位號為32。以此類推,PSIO51對應的是在對應的地址為0x80000,正好對應第20位。PL IO由此推斷為Bank2的第1位,對應的地址為0x1。該程式完成了點亮PS_LED、PL_LED持續2000MS之後再熄滅功能。
反應到開發板上狀態為,PL_LED以及PS_LED先點亮200MS後熄滅。
1 /* 2、Test Gpio function through Bank. */ 2 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK1, LED_IN_BANK0); 3 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK2, LED_IN_BANK2); 4 AlSys_MDelay(AL_GPIO_DELAY_2000MS); 5 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK1, 0x0); 6 AlGpio_Hal_WriteBank(GPIO, AL_GPIO_BANK2, 0x0); 7 AlSys_MDelay(AL_GPIO_DELAY_2000MS);
方法2:透過位號控制,先透過AlGpio_Hal_ReadPinOutput函式透過位號讀取了PL_LED以及PS_LED的狀態。然後持續讀取PS_KEY、PL_KEY的狀態,當發現PS_KeyValue == 0|PL_KeyValue == 0時,也就是PL KEY或者PS KEY任意哪個按鍵按下時,將PL_LED以及PS_LED以20MS為週期持續取反。
反應到開發板上狀態為,當任意對應按鍵KEY按下時,PL_LED以及PS_LED持續閃爍。
1 /* 3、Test Gpio polling */ 2 PS_LedValue = AlGpio_Hal_ReadPinOutput(GPIO, PS_LED); 3 AL_LOG(AL_LOG_LEVEL_INFO, "GPIO PS led value is 0x%x", PS_LedValue); 4 PL_LedValue = AlGpio_Hal_ReadPinOutput(GPIO, PL_LED); 5 AL_LOG(AL_LOG_LEVEL_INFO, "GPIO PL led value is 0x%x", PL_LedValue); 6 7 while(1) 8 { 9 PS_KeyValue = AlGpio_Hal_ReadPinInput(GPIO, PS_KEY); 10 PL_KeyValue = AlGpio_Hal_ReadPinInput(GPIO, PL_KEY); 11 if(PS_KeyValue == 0|PL_KeyValue == 0){ 12 AlSys_MDelay(AL_GPIO_DELAY_20MS); 13 if (PS_KeyValue == 0|PL_KeyValue == 0) { 14 AlGpio_Hal_WritePin(GPIO, PS_LED, ~PS_LedValue); 15 AlGpio_Hal_WritePin(GPIO, PL_LED, ~PL_LedValue); 16 AlSys_MDelay(AL_GPIO_DELAY_20MS); 17 AlGpio_Hal_WritePin(GPIO, PS_LED, PS_LedValue); 18 AlGpio_Hal_WritePin(GPIO, PL_LED, PL_LedValue); 19 AlSys_MDelay(AL_GPIO_DELAY_20MS); 20 } 21 } 22 }
8方案演示
8.1硬體準備
本實驗需要用到JTAG下載器、USB轉串列埠外設,另外需要把SW1模式開關設定到JTAG模式
5.8.2實驗結果
由於新增了PL端按鍵資源,所以Debug時需要將TD生成的soc_prj/soc_prj_Runs/best_result/soc_prj.bit檔案同時新增進來,在debug前會先下載PL端資源後啟動SOC部分。
IO輸出功能,可看到底板上的PS LED以及PL LED先亮起,後熄滅。
IO輸入功能,可以透過按動KEY2或KEY4,觀察到PS LED以及PL LED以20MS週期閃爍。
串列埠觀察到讀取的PS LED以及PL LED的狀態。