一、GPIO原理
1.GPIO介紹
程序員通過軟件代碼可以獨立和動態地對每個 GPIO 進行控制,使其作為輸入、輸出或中斷。
(1)通過一個加載指令,軟件可以讀取一個 GPIO 組內所有 GPIO 的值。
(2)通過一個保存指令,將數據寫到一個 GPIO 組內的一個或多個 GPIO 。
(3)在 ZYNQ-7000 SOC 內,GPIO 模塊的控制寄存器和狀態寄存器采用存儲器映射方式,它的基地址為 0xE000_A000。
(4)每個GPIO都提供了可編程的中斷。通過軟件程序代碼可以實現:①讀原始和屏蔽中斷的狀態;②可選的敏感性,包括電平敏感或邊沿敏感。
2.MIO與EMIO的異同
MIO(multiuse I/O):多功能IO接口,屬於Zynq的PS部分,Zynq7000 系列芯片有 54 個 MIO。它們分配在 GPIO 的 Bank0 和 Bank1 上,這些引腳可以用在GPIO、SPI、UART、TIMER、Ethernet、USB等功能上,每個引腳都同時具有多種功能,故叫多功能IO接口。這些 IO 與 PS 直接相連。不需要添加引腳約束,MIO 信號對 PL部分是透明的,不可見。所以對 MIO 的操作可以看作是純 PS 的操作。GPIO 的控制和狀態寄存器基地址為:0xE000_A000,我們 SDK 下軟件操作底層都是對於內存地址空間的操作。
EMIO(extendable multiuse I/O):擴展MIO,依然屬於Zynq的PS部分,只是連接到了PL上,再從PL的引腳連到芯片外面實現數據輸入輸出。Zynq7000 系列芯片有 64 個 EMIO,它們分配在 GPIO 的 Bank2 和 Bank3 上,當 MIO 不夠用時,PS 可以通過驅動 EMIO 控制 PL 部分的引腳,EMIO 的使用相當於,是一個 PS + PL 的結合使用的例子。所以,EMIO 需要分配引腳以及編譯綜合生成 bit文件。
PS:
(1)由於總計有54個 MIO ,因此第1組 MIO 引腳限制為22位。
(2)盡管 MIO 和 EMIO 組之間存在功能差異,但是對每組 GPIO 的控制是相同的。
3.GPIO接口及功能
DATA_RO: 此寄存器使能軟件觀察 PIN 腳,當 GPIO 被配置成輸出的時候,這個寄存器的值會反應輸出的 PIN 腳情況。 DATA: 此寄存器控制輸出到 GPIO 的值,讀這個寄存器的值可以讀到最后一次寫入該寄存器的值。 MASK_DATA_LSW: 位操作寄存器,寫入 GPIO 低 16bit 其他沒有改變的位置保存原先的狀態 MASK_DATA_MSW: 位操作寄存器,寫入 GPIO 高 16bit 其他沒有改變的位置保存原先的狀態 DIRM: 此寄存器控制輸出的開關,當 DIRM[x]==0 時候,禁止輸出 OEN: 輸出使能,當 OEN[x]==0 的時候輸出關閉,PIN 腳處於三態因此,如果要讀 IO 狀態就得讀 DATA_RO 的值,如果是對某一位進行操作就是寫MASK_DATA_LSW/MASK_DATA_MSW
二、注意事項
相對於MIO,EMIO有幾點要注意的地方:
1.EMIO 在 PL 部分,輸入與 OEN 寄存器無關,當 DIRM 設置為 0 的時候設置為輸入可以讀 DATA_RO 寄存器獲取數據。
2.輸出不能設置成三態,當 DIRM 設置為 1 的時候為輸出,寫入 DATA 寄存器或者MASK_DATA_LSW/MASK_DATA_MSW 寄存器。
3.EMIOGPIOTN[x]=DIRM[x] & OEN[x],實現輸出的控制。
三、配置上的區別
如果只是簡單的使用,那MIO和EMIO在編程上沒有太大區別,在配置上則有一些需要注意的地方。
1.MIO
ZYNQ配置時,在 MIO Configuration 選項卡對需要使用的MIO進行勾選即可。具體操作在前篇博客《ZYNQ筆記(2):PS端——Hello World !》 中已經詳細說明。
2.EMIO
①ZYNQ配置時,在 MIO Configuration 選項卡,再看到 I/O Peripherals 中的 GPIO 一欄,勾選上其中的 EMIO 一欄,並選擇 n 位引腳輸出(最多可以選擇 64 位)。
②ZYNQ配置完成后,ZYNQ系統多出一組引腳名為GPIO_0,這就是我們配置的EMIO,右擊該引腳,選擇 make external 把其引出。也可以對其更改名字。
③ZYNQ配置完成后,還需要對使用的EMIO引腳進行約束,即如PL端操作一樣用XDC文件編寫約束語句。
④配置完成后,必須生成bit流文件,並以此來加載SDK開發環境。
四、代碼精講
在 Xilinx 的 SDK 工具中,提供了對 GPIO 控制器進行操作的函數,這些 API 函數在 xgpiops.h 頭文件中。
(1) XGpioPs_Config * XGpioPs_LookConfig(u16 DeviceID) 根據唯一的設備ID號DeviceID,該函數查找設備配置。根據該號,該函數返回一個配置表路口。
(2) u32 XGpioPs_CfgInitialize(XGpioPs * InstancePtr, XGpioPs_Config * ConfigPtr, u32 EffectiveAddr) 該函數用於初始化一個GPiO實例,包括初始化該實例的所有成員。
(3) void XGpioPs_SetDirectionPin(XGpioP * InstancePtr, u32 Pin, u32 Direction) 該函數為指定的引腳設置方向。
(4) void XGpioPs_SetOutputEnablePin(XGpioPs * InstancePtr, u32 Pin, u32 OpEnable) 該函數設置指定引腳的輸出使能
(5) u32 XGpioPs_ReadPin(XGpioPs * InstancePtr, u32 Pin) 該函數從指定的引腳讀取數據
(6) void XGpioPs_WritePin(XGpioPs * InstancePtr, u32 Pin, u32 Data) 該函數向指定的引腳寫數據
參考資料:
[1]V3學院FPGA教程
[2]何賓, 張艷輝. Xilinx Zynq-7000嵌入式系統設計與實現[M]. 電子工業出版社, 2016.