【转】

自作多情 提交于 2019-11-28 22:34:37

zynq中三种实现GPIO的方式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/husipeng86/article/details/52123465

本文介绍在zynq中三种实现GPIO的方式,分别为MIO、EMIO和IP方式。

MIO和EMIO方式是使用PS部分的GPIO模块来实现GPIO功能的,支持54个MIO(可输出三态)、64个输入和128个输出(64个输出和64个输出使能)EMIO

而IP方式是在PL部分实现 GPIO功能,PS部分通过M_AXI_GP接口来控制该GPIO IP模块;另外EMIO模块虽然使用PS部分GPIO但也使用了PL部分的管脚资源。

MIO方式实现GPIO

vivado中zynq设置如下图

mio_vivado中配置

由图中可见要选中打开GPIO,其下自动显示可用于GPIO的MIO(当MIO作为其他功能时就不能作为GPIO使用了),其中MIO 7、MIO 8只能作为输出使用,因为它们用于VMODE管脚(参考UG585第14章:14.2.3)

软件部分如下

#include <stdio.h> #include "platform.h" #include "xgpiops.h"  #define LED1    0 #define LED2    9  static void delay(int dly) {     int i, j;     for (i = 0; i < dly; i++) {         for (j = 0; j < 0xffff; j++) {             ;         }     } }  int main() {     int Status;     XGpioPs_Config *ConfigPtr;     XGpioPs Gpio;      init_platform();      ConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);     Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,                     ConfigPtr->BaseAddr);     if (Status != XST_SUCCESS){         return XST_FAILURE;     }      XGpioPs_SetDirectionPin(&Gpio, LED1, 1);     XGpioPs_SetDirectionPin(&Gpio, LED2, 1);     XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1);     XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1);      while (1) {         XGpioPs_WritePin(&Gpio, LED1, 0);         XGpioPs_WritePin(&Gpio, LED2, 1);         delay(1000);         XGpioPs_WritePin(&Gpio, LED1, 1);         XGpioPs_WritePin(&Gpio, LED2, 0);         delay(1000);     }     cleanup_platform(); }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

EMIO方式实现GPIO

vivado中zynq设置如下图

emio_vivado中配置

图中可知GPIO中选择使用EMIO,并选择位宽(这里例子中选择3);其vivado中连接如下图

emio_vivado中连接

上图可知除了FIXED IO和DDR接口外,还多了3个3对(一个输入,一个输出和一个输出使能)GPIO管脚。

不同于MIO,这里三个IO管脚(一个输入,一个输出和一个输出使能在自动生成的顶层模块中合并为一个IO)要绑定到芯片对应管脚上

软件部分如下

#include <stdio.h> #include "platform.h" #include "xgpiops.h"  #define LED_R   54 #define LED_G   55 #define LED_B   56 #define LED_ON  0 #define LED_OFF 1  static void delay(int dly) {     int i, j;     for (i = 0; i < dly; i++) {         for (j = 0; j < 0xffff; j++) {             ;         }     } }  int main() {     int Status;     XGpioPs_Config *ConfigPtr;     XGpioPs Gpio;      init_platform();      ConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);     Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,                     ConfigPtr->BaseAddr);     if (Status != XST_SUCCESS) {         print("cfg init err\n");         return XST_FAILURE;     }     XGpioPs_SetDirectionPin(&Gpio, LED_R, 1);     XGpioPs_SetOutputEnablePin(&Gpio, LED_R, 1);     XGpioPs_SetDirectionPin(&Gpio, LED_G, 1);     XGpioPs_SetOutputEnablePin(&Gpio, LED_G, 1);     XGpioPs_SetDirectionPin(&Gpio, LED_B, 1);     XGpioPs_SetOutputEnablePin(&Gpio, LED_B, 1);      while (1) {         XGpioPs_WritePin(&Gpio, LED_R, LED_ON);         delay(1000);         XGpioPs_WritePin(&Gpio, LED_G, LED_ON);         delay(1000);         XGpioPs_WritePin(&Gpio, LED_B, LED_ON);         delay(1000);         XGpioPs_WritePin(&Gpio, LED_R, LED_OFF);         delay(1000);         XGpioPs_WritePin(&Gpio, LED_G, LED_OFF);         delay(1000);         XGpioPs_WritePin(&Gpio, LED_B, LED_OFF);         delay(1000);     }     cleanup_platform(); }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758

类似MIO方式(都为PS部分GPIO操作),设置为输出并设置输出使能,但要注意这里的GPIO号是从54开始的3个。

IP方式实现GPIO

vivado中zynq设置如下图

axi_gpio_vivado中配置

图中可知GPIO中MIO和EMIO都不选择,但要打开M_AXI_GP接口(这里选择M_AXI_GP0)和复位管脚,如下图

axi_gpio_vivado中配置_GP和复位

当然用到了PL部分逻辑则至少需要一个时钟输出到PL部分,这里选择FCLK_CLK0输出50MHz,如下图

axi_gpio_vivado中配置_时钟

推荐加入zynq后,不要自动连接,再加入gpio并位宽设置为3,具体设置如下图

axi_gpio_ip设置

GPIO设置好后,再点击上面的蓝色字体的自动连接,即可得到上面的连接,这样可以减少手动连接量。

最后vivado中连接如下图

axi_gpio_vivado中连接

与EMIO类似需要将顶层三个GPIO管脚要绑定到芯片对应管脚上。

软件部分如下

#include <stdio.h> #include "platform.h" #include "xgpio.h"  #define AXI_GPIO_DEVICE_ID  XPAR_GPIO_0_DEVICE_ID #define XGPIO_BANK1         1 #define XGPIO_BANK2         2  #define LED34_R_PIN         0x01 #define LED34_G_PIN         0x02 #define LED34_B_PIN         0x04  static void delay(int dly) {     int i, j;     for (i = 0; i < dly; i++) {         for (j = 0; j < 0xffff; j++) {             ;         }     } }  int main() {     XGpio_Config *XGpioCfg;     XGpio XGpio;     int Status;      init_platform();      XGpioCfg = XGpio_LookupConfig(AXI_GPIO_DEVICE_ID);     Status = XGpio_CfgInitialize(&XGpio, XGpioCfg, XGpioCfg->BaseAddress);     if (Status != XST_SUCCESS) {         return XST_FAILURE;     }      XGpio_SetDataDirection(&XGpio, XGPIO_BANK1, ~(LED34_R_PIN | LED34_G_PIN | LED34_B_PIN));     XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, LED34_R_PIN | LED34_G_PIN | LED34_B_PIN);     while (1) {         XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, ~LED34_R_PIN);         delay(1000);         XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, ~(LED34_R_PIN | LED34_G_PIN));         delay(1000);         XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, ~(LED34_R_PIN | LED34_G_PIN | LED34_B_PIN));         delay(1000);         XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, ~(LED34_G_PIN | LED34_B_PIN));         delay(1000);         XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, ~(LED34_B_PIN));         delay(1000);         XGpio_DiscreteWrite(&XGpio, XGPIO_BANK1, LED34_R_PIN | LED34_G_PIN | LED34_B_PIN);         delay(1000);     }     cleanup_platform();     return 0; }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

这里实现的功能与EMIO方式中功能相同,当时IP方式中为PL部分实现的GPIO,所以调用的函数与前面两种GPIO实现函数不同,注意包含的GPIO头文件,前两种是#include "xgpiops.h"而这最后一种为#include "xgpio.h"

总结

MIO和EMIO方式使用PS部分的GPIO模块,其中MIO方式不占用PL部分资源,其输出管脚只能为固定的54个(而且要在未被其它外设使用的情况下),EMIO方式会占用PL的管脚资源,其管脚可在PL部分任意选择(除特殊功能管脚),IP方式除了占用PL部分管脚资源外还会占用PL部分逻辑资源,所以其GPIO功能在PL部分实现其调用函数也和前两种不同,最后EMIO和IP方式在vivado都需要绑定管脚。

落花人独立微雨燕双飞关注
落花人独立微雨燕双飞

58篇文章

排名:千里之外

七水_SevenFormer关注
七水_SevenFormer

119篇文章

排名:6000+

FPGA难得一P关注
FPGA难得一P

31篇文章

排名:千里之外

没有更多推荐了,返回首页

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!