日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

ZYNQ7000-GPIO详解

發(fā)布時(shí)間:2025/3/13 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ZYNQ7000-GPIO详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ZYNQ7000-GPIO詳解

參考:UG585 - Zynq-7000 SoC Technical Reference Manual (v1.12.2) 385~394頁(yè)–Ch14: General Purpose I/O(GPIO)

一. GPIO的基本概念

GPIO,General Purpose I/O,通用輸入/輸出,是ZYNQ的外設(shè)之一。ZYNQ的架構(gòu)圖如下圖所示。

與非SOC不同的是,ZYNQ的GPIO引腳由PS側(cè)的MIO引腳和PL側(cè)的EMIO引腳構(gòu)成(見(jiàn)上圖)。

關(guān)于MIO和EMIO的詳細(xì)介紹參見(jiàn)我的另一篇博客:傳送門(mén):ZYNQ7000-MIO與EMIO詳解

二. GPIO框圖與分組

ZYNQ的GPIO框圖如下圖所示。ZYNQ的GPIO引腳分為4個(gè)Bank即4組,其中,

118個(gè)GPIO = 32個(gè)MIO(Bank0) + 22個(gè)MIO(Bank1)+ 32個(gè)EMIO(Bank2)+ 32個(gè)EMIO(Bank3)

可見(jiàn)基本都是32個(gè)IO引腳一組,這是因?yàn)镚PIO的控制寄存器是32位的,每一位對(duì)應(yīng)一個(gè)IO引腳的話(huà),一組寄存器就對(duì)應(yīng)32個(gè)引腳,所以,4組基本相同的寄存器分別控制4組Bank,Bank1對(duì)應(yīng)的也是一組32位寄存器,只是因?yàn)镸IO引腳總共就54個(gè),54-32=22,所以這組寄存器只控制22個(gè)引腳。

三. GPIO的功能與控制寄存器

GPIO的功能有三種:輸入,輸出,中斷使用MIO和EMIO在功能上幾乎相同,唯一的區(qū)別是EMIO因?yàn)槭荘L側(cè)引腳,可以與PL部分進(jìn)行通訊,而MIO對(duì)PL側(cè)是透明的。

特別的,MIO7,MIO8只能做輸出,這在ZYNQ7000-MIO與EMIO詳解中有說(shuō)明。

GPIO的功能在芯片內(nèi)部通過(guò)一組寄存器來(lái)控制,如下圖所示。注意,一組寄存器同時(shí)控制一個(gè)GPIO Bank的所有引腳

了解GPIO的控制器寄存器能幫助我們更深入的理解軟件中的相關(guān)庫(kù)函數(shù),對(duì)編程有些幫助,當(dāng)然,不了解也行,只要熟悉庫(kù)函數(shù)即可。

輸入/輸出控制寄存器:

寄存器名稱(chēng)說(shuō)明
DATA_ROdata read only(RO大概是這兩個(gè)單詞的縮寫(xiě)吧),
GPIO引腳的值存儲(chǔ)在此寄存器中,無(wú)論GPIO被配置為輸入或輸出,都可以通過(guò)讀此寄存器得到GPIO引腳的值。
因?yàn)槭侵蛔x寄存器(對(duì)軟件來(lái)說(shuō)),軟件向此寄存器的寫(xiě)入操作將被忽略。
DATA輸出數(shù)據(jù)寄存器,當(dāng)GPIO被配置為輸出才起作用,此寄存器中的值就是輸出到引腳的值。
向此寄存器寫(xiě)入就是在設(shè)置GPIO的輸出值,
讀此寄存器將返回GPIO前一時(shí)刻的輸出值,而不是現(xiàn)在的值。
MASK_DATA_LSWMask Data Least Significant Words,輸出數(shù)據(jù)低16位掩碼寄存器,此寄存器只有低16位有效,
對(duì)應(yīng)位為1表示DATA寄存器低16位中對(duì)應(yīng)位的值可以更改,
若不為1,則表示DATA寄存器低16位中對(duì)應(yīng)位保持原值
MASK_DATA_MSWMask Data Most Significant Words,輸出數(shù)據(jù)高16位掩碼寄存器,
功能同MASK_DATA_LSW,只是它對(duì)應(yīng)DATA寄存器高16位
DIRMDirection Memory,方向寄存器,默認(rèn)為0表示輸入,設(shè)為1表示輸出
注意,即使DIRM為1,軟件也可以像輸入一樣去讀此引腳的電平。
OENOutput Enable,輸出使能寄存器,
僅當(dāng)DIRM為0時(shí)有效,為1表示輸出使能,
為0表示輸出不使能,此時(shí)對(duì)應(yīng)引腳上的值為三態(tài)值

中斷控制寄存器:

寄存器名稱(chēng)說(shuō)明
INT_TYPEInterrupt Type 中斷類(lèi)型寄存器,
控制GPIO中斷是電平觸發(fā)還是邊緣觸發(fā)
INT_POLARITYInterrupt Polarity 中斷極性寄存器
控制GPIO中斷是低電平/下降沿有效,還是高電平/上升沿有效
INT_ANYInterrupt Any,雙邊沿寄存器,
僅當(dāng)INT_TYPE為邊沿觸發(fā)時(shí),此寄存器才有效,控制是否雙沿均可觸發(fā)中斷
INT_STATInterrupt State,中斷狀態(tài)寄存器,
此寄存器的值會(huì)被與之相連的INT State D觸發(fā)器讀取
D觸發(fā)器存儲(chǔ)中斷狀態(tài),軟件通過(guò)讀此D觸發(fā)器輸出來(lái)判斷中斷是否發(fā)生,
清除此D觸發(fā)器來(lái)清除中斷狀態(tài)
INT_MASKInterrupt Mask,中斷掩碼寄存器,
顯示當(dāng)前哪些位被屏蔽,哪些位啟用
INT_DISInterrupt Disable,中斷失效寄存器,
向該寄存器的任何位寫(xiě)入 1 都會(huì)屏蔽該中斷信號(hào)。
從該寄存器讀取會(huì)返回不可預(yù)測(cè)的值
INT_ENInterrupt Enable,中斷使能寄存器
向該寄存器的任何位寫(xiě)入 1,可以啟用/解除中斷信號(hào)的掩碼。
從該寄存器讀取將返回一個(gè)不不可預(yù)測(cè)的值

四. GPIO中斷設(shè)置與說(shuō)明

GPIO中斷號(hào)為52。此中斷的優(yōu)先級(jí)芯片內(nèi)部已經(jīng)固定好了,所以在軟件中配置GPIO中斷時(shí),不需要指定GPIO中斷的優(yōu)先級(jí)。

GPIO所有引腳都是共享一個(gè)中斷的,這意味著如果兩個(gè)引腳的中斷都使能了,如果不去讀取具體引腳的電平,軟件無(wú)法判斷中斷具體來(lái)自哪個(gè)引腳。

中斷觸發(fā)類(lèi)型設(shè)置:

五. 在Vitis中配置GPIO

我自建了GPIO相關(guān)庫(kù)函數(shù),將相關(guān)GPIO功能寫(xiě)在一起。Xxk_PsGpio.c 與 Xxk_PsGpio.h。這里并沒(méi)有使用處理整個(gè)Bank的函數(shù),因?yàn)閷?shí)際應(yīng)用時(shí)很好需要處理整個(gè)Bank,都是單獨(dú)處理某個(gè)Pin。

Xxk_PsGpio.h如下:

#ifndef XXK_PSGPIO_H #define XXK_PSGPIO_H// 包含xilinx庫(kù)中頭文件 #include "xil_printf.h" #include "xgpiops.h" #include "xscugic.h" #include "xil_exception.h"// 宏定義 #define __weak __attribute__((weak))// 與PS GPIO相關(guān)的宏定義 // 引腳宏定義 #define MIO12 12U#define EMIO0 54U #define EMIO1 55U #define EMIO2 56U #define EMIO3 57U #define EMIO4 58U// GPIO指的就是PS側(cè)的GPIO硬核,對(duì)于ZYNQ7,只有一個(gè)GPIO硬核 #define PSGPIO_INPUT 0U #define PSGPIO_OUTPUT 1U #define PSGPIO_OUTPUT_ENABLE 1U #define PSGPIO_OUTPUT_DISABLE 0U/* 中斷類(lèi)型,已在xgpiops.h中定義,放在這里方便找到 #define XGPIOPS_IRQ_TYPE_EDGE_RISING 0x00U #define XGPIOPS_IRQ_TYPE_EDGE_FALLING 0x01U #define XGPIOPS_IRQ_TYPE_EDGE_BOTH 0x02U #define XGPIOPS_IRQ_TYPE_LEVEL_HIGH 0x03U #define XGPIOPS_IRQ_TYPE_LEVEL_LOW 0x04U */// PS GPIO相關(guān)函數(shù) // 初始化psGpio int psGpioInti(XGpioPs *psGpioPtr, u16 psGpio_deviceId); //psGpioInti(&psGpio, XPAR_XGPIOPS_0_DEVICE_ID);// 設(shè)置psGpio某引腳為輸出并使能 void psGpio_SetPinOutputAndEnbale(const XGpioPs *psGpioPtr, u32 Pin); //psGpio_SetPinOutputAndEnbale(&psGpio, EMIO0);// 設(shè)置psGpio某引腳為輸入,輸入無(wú)需使能 void psGpio_SetPinInput(const XGpioPs *psGpioPtr, u32 Pin); //psGpio_SetPinInput(&psGpio, EMIO0);// 向psGpio某引腳寫(xiě)入0或1 extern void XGpioPs_WritePin(const XGpioPs *psGpioPtr, u32 Pin, u32 Data); //XGpioPs_WritePin(&psGpio, EMIO0, 1);// 讀取psGpio某引腳的電平,得到0或1 extern u32 XGpioPs_ReadPin(const XGpioPs *psGpioPtr, u32 Pin); // EMIO0_pinData = XGpioPs_ReadPin(&psGpio, EMIO0);// 中斷相關(guān)函數(shù) int scuGic_Inti(XScuGic *scuGicPtr, u16 scuGicID); //初始化中斷控制器 //scuGic_Inti(&scuGic, XPAR_XSCUTIMER_0_DEVICE_ID);void psGpio_PinIntr_SetAndEnable(XScuGic *scuGicPtr, XGpioPs *psGpioPtr, u32 psGpio_intrId,Xil_ExceptionHandler psGpio_Handler, u32 Pin, u8 IrqType); //psGpio_PinIntr_SetAndEnable(&scuGic, &psGpio, XPAR_XGPIOPS_0_INTR, // psGpio_Handler, EMIO0, XGPIOPS_IRQ_TYPE_EDGE_RISING);void psGpio_Handler(void *CallBackRef); // 需在main中重寫(xiě)此弱函數(shù)#endif

Xxk_PsGpio.c 如下:

#include "Xxk_PsGpio.h"// 初始化PS側(cè)GPIO,包括MIO和EMIO int psGpioInti(XGpioPs *psGpioPtr, u16 psGpio_deviceId) {XGpioPs_Config *psGpio_configPtr;psGpio_configPtr = XGpioPs_LookupConfig(psGpio_deviceId); // 根據(jù)器件ID查找配置// 配置初始化配置int status;status = XGpioPs_CfgInitialize(psGpioPtr, psGpio_configPtr, psGpio_configPtr->BaseAddr);if (status != XST_SUCCESS){xil_printf("PsGpio %d Initialization Failed\r\n", psGpio_deviceId);return status;}status = XGpioPs_SelfTest(psGpioPtr);if (status != XST_SUCCESS){xil_printf("PsGpio %d SelfTest Failed\r\n", psGpio_deviceId);return status;}xil_printf("PsGpio %d Initialization Succeed\r\n", psGpio_deviceId);return status; }// 設(shè)置psGpio某引腳為輸入,輸入無(wú)需使能 void psGpio_SetPinInput(const XGpioPs *psGpioPtr, u32 Pin) {XGpioPs_SetDirectionPin(psGpioPtr, Pin, PSGPIO_INPUT); }// 設(shè)置psGpio某引腳為輸出并使能 void psGpio_SetPinOutputAndEnbale(const XGpioPs *psGpioPtr, u32 Pin) {XGpioPs_SetDirectionPin(psGpioPtr, Pin, PSGPIO_OUTPUT);XGpioPs_SetOutputEnablePin(psGpioPtr, Pin, PSGPIO_OUTPUT_ENABLE); }// 設(shè)置psGpio某引腳輸出不使能 void psGpio_SetPinOutputDisbale(const XGpioPs *psGpioPtr, u32 Pin) {XGpioPs_SetOutputEnablePin(psGpioPtr, Pin, PSGPIO_OUTPUT_DISABLE); }// PS GPIO PIN中斷使能 void psGpio_PinIntr_SetAndEnable(XScuGic *scuGicPtr, XGpioPs *psGpioPtr, u32 psGpio_intrId,Xil_ExceptionHandler psGpio_Handler, u32 Pin, u8 IrqType) {// 連接中斷ID與固定服務(wù)函數(shù)XScuGic_Connect(scuGicPtr, psGpio_intrId, (Xil_ExceptionHandler)psGpio_Handler, (void *)psGpioPtr);// 啟用對(duì)應(yīng)中斷ID的中斷源XScuGic_Enable(scuGicPtr, psGpio_intrId);// 注意psGPIO中斷不需要設(shè)置中斷優(yōu)先級(jí)// 設(shè)置psGPIO中斷類(lèi)型XGpioPs_SetIntrTypePin(psGpioPtr, Pin, IrqType);// 在使能前先清除一次中斷,否則之前的中斷狀態(tài)可能殘留,導(dǎo)致燒寫(xiě)后馬上進(jìn)一次中斷XGpioPs_IntrClearPin(psGpioPtr, Pin);// 使能psGPIO中斷XGpioPs_IntrEnablePin(psGpioPtr, Pin); }// psGpio中斷處理弱函數(shù) __weak void psGpio_Handler(void *CallBackRef) {XGpioPs *psGpioPtr = (XGpioPs *)CallBackRef;// psGpio_intrFlag = 1;if (XGpioPs_IntrGetStatusPin(psGpioPtr, MIO12) == TRUE){XGpioPs_IntrDisablePin(psGpioPtr, MIO12);XGpioPs_IntrClearPin(psGpioPtr, MIO12);xil_printf("This is psGpio_Handler - MIO12\r\n");}else if (XGpioPs_IntrGetStatusPin(psGpioPtr, EMIO4) == TRUE){XGpioPs_IntrDisablePin(psGpioPtr, EMIO4);XGpioPs_IntrClearPin(psGpioPtr, EMIO4);xil_printf("This is psGpio_Handler - EMIO4\r\n");} }// 初始化中斷控制器ScuGic int scuGic_Inti(XScuGic *scuGicPtr, u16 scuGicID) {// 打開(kāi)系統(tǒng)的中斷處理功能Xil_ExceptionInit(); // 初始化異常句柄,只在很早版本的bsp中需要,此處為了兼容性保留Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler,scuGicPtr); // 為IRQ注冊(cè)中斷處理程序Xil_ExceptionEnable(); // 使能系統(tǒng)中斷功能XScuGic_Config *scuGicConfig;scuGicConfig = XScuGic_LookupConfig(scuGicID); // 根據(jù)器件ID查找配置int status;status = XScuGic_CfgInitialize(scuGicPtr, scuGicConfig, scuGicConfig->CpuBaseAddress);if (status != XST_SUCCESS){xil_printf("ScuGic Initialization Failed\r\n");return XST_FAILURE;}xil_printf("ScuGic Initialization Succeed\r\n");return status; }

使用自建庫(kù),GPIO輸入,輸出及中斷均有使用的main.c如下:

/*功能:控制EMIO0~2為輸出,EMIO4為輸入,EMIO3為中斷 */#include "Xxk_PsGpio.h" #include "sleep.h"// 全局變量 XGpioPs psGpio; XScuGic scuGic;int psGpio_EMIO_intrFlag = 0; int psGpio_MIO_intrFlag = 0;int main(int argc, char const *argv[]) {xil_printf("begin\r\n");// 初始化psGpiopsGpioInti(&psGpio, XPAR_XGPIOPS_0_DEVICE_ID);// 設(shè)置psGpio引腳方向psGpio_SetPinOutputAndEnbale(&psGpio, EMIO0);psGpio_SetPinOutputAndEnbale(&psGpio, EMIO1);psGpio_SetPinOutputAndEnbale(&psGpio, EMIO2);psGpio_SetPinInput(&psGpio, EMIO3);// 初始化中斷控制器scuGic_Inti(&scuGic, XPAR_XSCUTIMER_0_DEVICE_ID);// 設(shè)置并使能psGpio某引腳中斷psGpio_PinIntr_SetAndEnable(&scuGic, &psGpio, XPAR_XGPIOPS_0_INTR,psGpio_Handler, EMIO4, XGPIOPS_IRQ_TYPE_EDGE_FALLING);psGpio_PinIntr_SetAndEnable(&scuGic, &psGpio, XPAR_XGPIOPS_0_INTR,psGpio_Handler, MIO12, XGPIOPS_IRQ_TYPE_EDGE_FALLING);while (1){sleep(1);xil_printf("EMIO3 value: %d\r\n", XGpioPs_ReadPin(&psGpio, EMIO3));XGpioPs_WritePin(&psGpio, EMIO0, 1);XGpioPs_WritePin(&psGpio, EMIO1, 1);XGpioPs_WritePin(&psGpio, EMIO2, 0);if (psGpio_EMIO_intrFlag){xil_printf("This is psGpio_Handler - EMIO4\r\n");psGpio_EMIO_intrFlag = 0;XGpioPs_IntrEnablePin(&psGpio, EMIO4);}if (psGpio_MIO_intrFlag){xil_printf("This is psGpio_Handler - MIO12\r\n");psGpio_MIO_intrFlag = 0;XGpioPs_IntrEnablePin(&psGpio, MIO12);}sleep(1);XGpioPs_WritePin(&psGpio, EMIO0, 0);XGpioPs_WritePin(&psGpio, EMIO2, 1);}return 0; }void psGpio_Handler(void *CallBackRef) // 重寫(xiě)弱函數(shù) {XGpioPs *psGpioPtr = (XGpioPs *)CallBackRef;if (XGpioPs_IntrGetStatusPin(psGpioPtr, MIO12) == TRUE){psGpio_MIO_intrFlag = 1;XGpioPs_IntrDisablePin(psGpioPtr, MIO12);XGpioPs_IntrClearPin(psGpioPtr, MIO12);}if (XGpioPs_IntrGetStatusPin(psGpioPtr, EMIO4) == TRUE){psGpio_EMIO_intrFlag = 1;XGpioPs_IntrDisablePin(psGpioPtr, EMIO4);XGpioPs_IntrClearPin(psGpioPtr, EMIO4);} }

六. GPIO的另一種實(shí)現(xiàn)方式 - AXI GPIO

本文介紹了如何使用MIO和EMIO實(shí)現(xiàn)GPIO,而對(duì)于ZYNQ來(lái)說(shuō),在PL中使用AXI GPIO IP核也可以實(shí)現(xiàn)GPIO功能,具體介紹參見(jiàn)我的另一篇博文。

傳送門(mén):ZYNQ7000-AXI GPIO詳解

七. 總結(jié)

本文介紹了ZYNQ7000中GPIO的基本概念,GPIO是ZYNQ PS側(cè)最簡(jiǎn)單的一種外設(shè),它可以由MIO或EMIO實(shí)現(xiàn)。以32為界,118個(gè)GPIO被分為了4個(gè)Bank,每個(gè)Bank對(duì)應(yīng)一組控制寄存器,然后簡(jiǎn)單介紹了每個(gè)寄存器的名稱(chēng)含義和功能,最后附上了通過(guò)自建GPIO函數(shù)庫(kù),便捷操作GPIO的軟件代碼。

對(duì)GPIO理解還不深,如有疏漏,歡迎評(píng)論指出!

總結(jié)

以上是生活随笔為你收集整理的ZYNQ7000-GPIO详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。