zynq中三種實現GPIO的方式

https://blog.csdn.net/husipeng86/article/details/52123465

 

zynq中三種實現GPIO的方式

本文介紹在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();
}

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();
}

類似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;
}

這裏實現的功能與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都需要綁定管腳。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章