Zedboard学习(五):MIO与EMIO操作

MIO:
Zynq7000 系列芯片有 54 个 MIO(multiuse I/O), 它们分配在 GPIO 的 Bank0 和Bank1 隶属于 PS 部分, 这些 IO 与 PS 直接相连。 不需要添加引脚约束, MIO 信号对 PL部分是透明的。 所以对 MIO 的操作可以看作是纯PS 的操作。
EMIO:
同时Zynq可以配置多达63个EMIO引脚,这些引脚可以配置到PL部分,也可以配置为外设的引脚,不过需要添加约束文件指定封装引脚。EMIO分配在Bank2和Bank3上。
资料链接

Zedboard学习(五):MIO与EMIO操作_第1张图片
除了Bank1是22bit之外,其他三个Bank都是32bit,折算一下就是:

MIO——54bit;
EMIO——64bit。

使用上MIO和EMIO也较为近似,EMIO主要用于MIO不够,扩展GPIO的场合。

MIO

1、新建工程。
Zedboard学习(五):MIO与EMIO操作_第2张图片

2、跟前面的博文一样,对zynq进行底层配置,搭建soc最小系统。(点击打开链接)
Zedboard学习(五):MIO与EMIO操作_第3张图片

3、产生比特流文件。
Zedboard学习(五):MIO与EMIO操作_第4张图片

4、导出比特流文件。File–>Export–>Export Hardware。
Zedboard学习(五):MIO与EMIO操作_第5张图片

5、打开SDK,进行PS部分的开发:File–>Launch SDK 。
在SDK下新建工程:File–>Launch SDK 。
Zedboard学习(五):MIO与EMIO操作_第6张图片

6、工程模板选空工程就行。
Zedboard学习(五):MIO与EMIO操作_第7张图片

7、准备自己编写代码,在新建的工程下,src右键–>New–>Source FIle 填上文件名字。

8、程序:

/*
 * main.c
 *
 *  Created on: 2017年7月11日
 *      Author: XHB
 */

#include "xgpiops.h"
#include "sleep.h"
#include "xparameters.h"

int main()
{
    XGpioPs gpioStruct;
    XGpioPs_Config *gpioConfig;
    int pinNum = 7;
    u32 pinDirection = 1;   //1表示输出, 0表示输入
    s32 xStatus;

    //print("hello\n");

    //初始化MIO
    //通过gpio的device_ID获取GPIO寄存器的基地址
    gpioConfig = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
    if(gpioConfig == NULL)  //若指针为空,说明没有找到对应的设备或者FPGA底层未进行配置
    {
        print("Can not lookup gpioConfig!!!\n");
        return XST_FAILURE;
    }

    //初始化GPIO
    xStatus = XGpioPs_CfgInitialize(&gpioStruct, gpioConfig, gpioConfig->BaseAddr);
    if(xStatus != XST_SUCCESS)
    {
        print("PS MIO GPIO Initialize failed!!!\n");
    }
    else
    {
        print("PS MIO GPIO Initialize successed!!!\n");
    }

    //设置GPIO的引脚以及输入输出模式
    XGpioPs_SetDirectionPin(&gpioStruct, pinNum, pinDirection);

    //设置GPIO的输出使能
    XGpioPs_SetOutputEnablePin(&gpioStruct, pinNum, 1);

    while(1)
    {
        XGpioPs_WritePin(&gpioStruct, pinNum, 1);   //给高电平

        sleep(1);   //延时1s

        XGpioPs_WritePin(&gpioStruct, pinNum, 0);   //给低电平

        sleep(1);   //延时1s
    }

    return 0;
}

9、程序说明:
头文件:
xgpiops.h:定义了与GPIO初始化、操作等有关的函数和参数;
sleep.h:定义了延时函数,用来控制延时;
xparameters.h:与底层配置有关,定义了ps端的外设的Device ID、基地址等等信息。

结构体:
主要用到两个结构体:
XGpioPs_Config类型结构体:包含有GPIO初始化信息。

/**
 * This typedef contains configuration information for a device.
 */
typedef struct {
    u16 DeviceId;       /**< Unique ID of device */
    u32 BaseAddr;       /**< Register base address */
} XGpioPs_Config;

XGpioPs类型结构体:用于对GPIO进行相关配置,调用库函数对其成员变量赋值,实质上是映射到寄存器上,对寄存器进行操作。跟当初学习stm32的库函数时的原理一样。

/**
 * The XGpioPs driver instance data. The user is required to allocate a
 * variable of this type for the GPIO device in the system. A pointer
 * to a variable of this type is then passed to the driver API functions.
 */
typedef struct {
    XGpioPs_Config GpioConfig;  /**< Device configuration */
    u32 IsReady;            /**< Device is initialized and ready */
    XGpioPs_Handler Handler;    /**< Status handlers for all banks */
    void *CallBackRef;      /**< Callback ref for bank handlers */
    u32 Platform;           /**< Platform data */
    u32 MaxPinNum;          /**< Max pins in the GPIO device */
    u8 MaxBanks;            /**< Max banks in a GPIO device */
} XGpioPs;

几个库函数:
可以跟踪到定义看他们详细的代码,这里简单介绍一下。使用时都是些套路。
a、通过gpio的device_ID获取GPIO寄存器的基地址,返回值是一个XGpioPs_Config指针类型结构体,deviceID可以到xparameters.h找到我们底层的GPIO的ID。

XGpioPs_Config *XGpioPs_LookupConfig(u16 DeviceId)

b、初始化GPIO。填入两个结构体的指针,以及GPIO对应的基地址。

s32 XGpioPs_CfgInitialize(XGpioPs *InstancePtr, XGpioPs_Config *ConfigPtr,u32 EffectiveAddr)

c、设置GPIO输入\输出模式。InstancePtr是前面初始化时设置了的结构体,Pin是MIO的引脚号,Direction若是1表示输出,若是0表示输入。

void XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction)

d、GPIO输出使能。InstancePtr是前面初始化过的结构体,pin是引脚号,OpEnable若是1使能引脚,允许输出;若是0,禁止输出。

void XGpioPs_SetOutputEnablePin(XGpioPs *InstancePtr, u32 Pin, u32 OpEnable)

e、向MIO的某个引脚写入数据,输出1或0。InstancePtr和Pin跟前面一样,Data为1或0,对应高电平和低电平。

void XGpioPs_WritePin(XGpioPs *InstancePtr, u32 Pin, u32 Data)

f、GPIO相关的函数都可以在xgpiops.h找到。

10、SDK下运行程序,就可以看到MIO7对应的LED等闪烁了。
其实这里可以不用配置FPGA的比特流文件,因为MIO是不依托FPGA的PL部分的,是直接挂在PS部分的,所以直接下载进去也可以运行的。
如果直接在sdk下载,会弹出警告说没有配置底层,忽视直接下载即可。
Zedboard学习(五):MIO与EMIO操作_第8张图片

EMIO:

1、vivado下新建工程。
Zedboard学习(五):MIO与EMIO操作_第9张图片
Zedboard学习(五):MIO与EMIO操作_第10张图片

2、跟前面的博文一样,对zynq进行底层配置,搭建soc最小系统。(点击打开链接)
Zedboard学习(五):MIO与EMIO操作_第11张图片

3、双击zynq,手动更改zynq7处理器的配置。
在emio那里打钩,添加EMIO外设。
Zedboard学习(五):MIO与EMIO操作_第12张图片
只添加8个EMIO,所以位数选8。
这里写图片描述

4、完成更改,回到block design中看看,发现多出了GPIO_0。选中他,按CTRL+T将引脚引出。这里的GPIO_0对应EMIO。
Zedboard学习(五):MIO与EMIO操作_第13张图片

5、保存当前的block design,回到工程视图,产生仿真文件。
Zedboard学习(五):MIO与EMIO操作_第14张图片

6、创建顶层文件。
Zedboard学习(五):MIO与EMIO操作_第15张图片
打开新建的Verilog文件,可以看到新加的接口:gpio_tri_io_0。
Zedboard学习(五):MIO与EMIO操作_第16张图片

7、由于EMIO是PL部分新添加的外设,还需要进行引脚约束。
添加引脚约束文件。
Zedboard学习(五):MIO与EMIO操作_第17张图片

8、创建一个xdc文件。
Zedboard学习(五):MIO与EMIO操作_第18张图片

9、创建完成后,对新建的xdc文件编辑。
这里写图片描述
输入代码:

set_property PACKAGE_PIN T22 [get_ports {gpio_0_tri_io[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[0]}]

set_property PACKAGE_PIN T21 [get_ports {gpio_0_tri_io[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[1]}]

set_property PACKAGE_PIN U22 [get_ports {gpio_0_tri_io[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[2]}]

set_property PACKAGE_PIN U21 [get_ports {gpio_0_tri_io[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[3]}]

set_property PACKAGE_PIN V22 [get_ports {gpio_0_tri_io[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[4]}]

set_property PACKAGE_PIN W22 [get_ports {gpio_0_tri_io[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[5]}]

set_property PACKAGE_PIN U19 [get_ports {gpio_0_tri_io[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[6]}]

set_property PACKAGE_PIN U14 [get_ports {gpio_0_tri_io[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[7]}]

10、产生比特流文件,之后导出并启动sdk。同前面MIO的步骤一样,新建一个空工程输入代码:

/*
 * main.c
 *
 *  Created on: 2017年7月12日
 *      Author: XHB
 */

#include "xgpiops.h"
#include "sleep.h"
#include "xparameters.h"

int main()
{
    XGpioPs gpioStruct;
    XGpioPs_Config *gpioConfig;
    int pinNum = 54;
    u32 pinDirection = 1;   //1表示输出, 0表示输入
    s32 xStatus;

    print("hello\n");

    //初始化MIO
    //通过gpio的device_ID获取GPIO寄存器的基地址
    gpioConfig = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
    if(gpioConfig == NULL)  //若指针为空,说明没有找到对应的设备或者FPGA底层未进行配置
    {
        print("Can not lookup gpioConfig!!!\n");
        return XST_FAILURE;
    }

    //初始化GPIO
    xStatus = XGpioPs_CfgInitialize(&gpioStruct, gpioConfig, gpioConfig->BaseAddr);
    if(xStatus != XST_SUCCESS)
    {
        print("PS MIO GPIO Initialize failed!!!\n");
    }
    else
    {
        print("PS MIO GPIO Initialize successed!!!\n");
    }

    //设置GPIO的引脚以及输入输出模式
    XGpioPs_SetDirectionPin(&gpioStruct, pinNum, pinDirection);

    //设置GPIO的输出使能
    XGpioPs_SetOutputEnablePin(&gpioStruct, pinNum, 1);

    while(1)
    {
        XGpioPs_WritePin(&gpioStruct, pinNum, 1);   //给高电平

        sleep(1);   //延时1s

        XGpioPs_WritePin(&gpioStruct, pinNum, 0);   //给低电平

        sleep(1);   //延时1s
    }

    return 0;
}

好的,你应该看出来了,跟MIO部分的其实基本都一样了,只是引脚号变成了54,而MIO部分的是7。
最开始算了一下,MIO总共有54个,0~53;EMIO有64个。所以54就是第一个EMIO了。

11、下载程序前,一定要先把工程的比特流文件下载一下。因为EMIO是依托于PL的,需要FPGA底层配置后,才可在PS端使用。下载后会看到LED闪烁。
Zedboard学习(五):MIO与EMIO操作_第19张图片
这里选用的GPIO的引脚号是54,对应第一个EMIO,也就是之前引脚约束时分配的第一个LED对应的引脚;总共分配了8个EMIO,更改这个引脚号,也同样可以控制其他几个LED。

你可能感兴趣的:(zedboard)