ZYNQ:MIO、EMIO、IO的区别和灵活使用

ZYNQ:MIO、EMIO、IO的区别和灵活使用

ZYNQ:MIO、EMIO、IO的区别和灵活使用

在使用ZYNQ上ARM cortex-A9平台时首先面临的就是对IO进行操作,总的来说对IO操作无怪乎两种方式,一种是直接对GPIO寄存器进行操作,这样程序效率高,但编写代码困难;另一种是调用SDK工具提供的API接口函数。

在实际使用时ZYNQ又把GPIO分成MIO、EMIO和PL端的IO这三种类型,在刚刚接触时会因为这三种IO的不同配置和使用方式而影响后续的学习,这里针对三种IO进行详细的说明使用方法。

首先要明白这三种IO的物理属性,简单的说1、MIO只属于PS端,PL端无法进行操作。

2、EMIO从物理属性来说属于PL端IO,但PS端可以通过软件映射连线来对EMIO进行操作,且使用效果与MIO一致。3、PL端所有IO都属于常规的FPGA的IO口,可进行输入输出操作,但是如果PS端不对EMIO控制时,LP端可以随意的使用EMIO。

1、PS配置MIO进行输出

ZYNQ7000系列芯片由54个MIO,隶属于PS部分,使用时不需要添加引脚约束,对PL部分是不可见的。在使用PS端MIO时需要对GPIO进行配置,这个配置过程与普通的ARM芯片过程一致。首先需要对MIO的基本特性进行配置,在对GPIO配置时需要调用API函数,这里需要了解下面几个函数

1、XGpioPs_Config *XGpioPs_LookupConfig(u16 DeviceId);

这个函数是根据唯一的设备ID号来查找设备配置。这个函数返回一个配置表入口。实际上就是根据设备ID返回结构体XGpioPs_Config的配置。

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

这个函数用于初始化GPIO,主要完成对XGpioPs结构体的配置。函数总是返回配置成功。

3、 void XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction);

这个函数为指定的引脚配置输入输出方向。实际上是对方向寄存器(DirModeReg寄存器)进行使能。设置为0时禁止输出驱动使能,也就是输入有效,设置为1时使能输出驱动。

4、void XGpioPs_SetOutputEnablePin(XGpioPs *InstancePtr, u32 Pin, u32 OpEnable);

这个函数设置指定引脚输出使能。这个是对OpEnableReg寄存器进行配置。OpEnableReg与DirModeReg属于逻辑与的关系,只有两个都配置成功才能实现MIO的输入或者输出的配置。

5、u32 XGpioPs_ReadPin(XGpioPs *InstancePtr, u32 Pin);

这个函数是从指定引脚读出数据。返回值是从DATA_RO寄存去内取出读到的数据。

6、void XGpioPs_WritePin(XGpioPs *InstancePtr, u32 Pin, u32 Data);

这个函数是对指定引脚写入数据。这个函数是对DATA寄存器、DATA_MSW寄存器、DATA_LSW寄存器进行配置,共同完成输出数据的写入。

在了解了上述函数后,对PS端的GPIO操作就相对简单了。配置流程就是

1、根据设备ID找到基地址和设备编号,也就是完成XGpioPs_Config的配置。

2、对找到的设备进行配置,这个可直接调用函数进行完成。

3、设置IO的输入输出方向。

4、使能对应IO的输入输出。

5、对IO进行读或者写操作。

根据上面是配置流程代码如下:

#include “xgpiops.h”

#include “sleep.h”

int main()

{

static XGpioPs psGpioInstancePtr;

XGpioPs_Config* GpioConfigPtr;

int iPinNumber= 7; //LD9连接的是MIO7

u32 uPinDirection = 0x1; //1表示输出,0表示输入

int xStatus;

//--MIO的初始化

GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);

if(GpioConfigPtr == NULL)

return XST_FAILURE;

xStatus =XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr);

if(XST_SUCCESS != xStatus)

print(" PS GPIO INIT FAILED \n\r");

//--MIO的输入输出操作

XGpioPs_SetDirectionPin(&psGpioInstancePtr, iPinNumber,uPinDirection);//配置MIO输出方向

XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);//配置MIO的第7位输出

while(1)

{

XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 1);//点亮MIO的第7位输出1

sleep(1); //延时

XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 0);//熄灭MIO的第7位输出0

sleep(1); //延时

}

return 0;

}

2、 PS配置EMIO进行输出

在使用EMIO时需要在Z7的IP核配置时选择EMIO。如下图,这里选择了2个EMIO端口。

其次又要EMIO硬件上属于PL端,需要在PL端对GPIO进行约束,通俗的讲就是把这个GPIO硬件端口链接到PS上。管脚约束文件如下图

在完成了上述配置后,在SDK上对这些EMIO进行配置时就和MIO一样。

3、PS配置PL端普通IO进行输出

这个方式对PL端普通IO进行操作是比较麻烦的,并且也消耗AXI总线资源。

AXI接口如下表描述:

在使用PS对PL端IO操作时,AXI_GPIO相当于GPIO的IP核,是通过AXI总线挂在PS上的GPIO上。因此系统整体连线图如下图所示:(这个图包含了MIO、EMIO和AXI_GPIO)

这部分由于使用了AXI总线,设备的ID和地址都是确定的,因此不需要对GPIO的设备ID和基地址进行配置,只需要对PL端GPIO进行初始化即可。

xstatus = XGpio_Initialize(&pl_gpio_instance_ptr, XPAR_AXI_GPIO_0_DEVICE_ID);

if (NULL!=xstatus)

print (“pl_axi_gpio config ok \n\r”) ;

XGpio_SetDataDirection(&pl_gpio_instance_ptr,1,1);

XGpio_SetDataDirection(&pl_gpio_instance_ptr,2,0);

然后对这个IO进行读写操作,这里需要主要的是输入数据为32位,需要把输入的数据和GPIO数量要进行对应。

XGpio_DiscreteWrite(&pl_gpio_instance_ptr,2,0xffffffff);

XGpio_DiscreteWrite(&pl_gpio_instance_ptr,2,0x00000000);

总结

这三种GPIO的配置有相同的地方和不同的地方,不同的地方主要是由GPIO所归属的物理位置不同导致,由于物理位置不同进行额外配置在PL端。而在PS端其实需要修改的很少。因此在SDK上进行IO操作是相对灵活且简单的。

相关推荐

《尔雅》尔雅•五、释宫
365登录次数限制

《尔雅》尔雅•五、释宫

📅 07-15 👁️ 4450
红米note外屏破了,换个得多少钱
bet3365.com

红米note外屏破了,换个得多少钱

📅 09-20 👁️ 4486