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上。
资料链接
除了Bank1是22bit之外,其他三个Bank都是32bit,折算一下就是:
MIO——54bit;
EMIO——64bit。
使用上MIO和EMIO也较为近似,EMIO主要用于MIO不够,扩展GPIO的场合。
MIO
1、新建工程。
2、跟前面的博文一样,对zynq进行底层配置,搭建soc最小系统。(点击打开链接)
3、产生比特流文件。
4、导出比特流文件。File–>Export–>Export Hardware。
5、打开SDK,进行PS部分的开发:File–>Launch SDK 。
在SDK下新建工程:File–>Launch SDK 。
6、工程模板选空工程就行。
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下载,会弹出警告说没有配置底层,忽视直接下载即可。
EMIO:
1、vivado下新建工程。
2、跟前面的博文一样,对zynq进行底层配置,搭建soc最小系统。(点击打开链接)
3、双击zynq,手动更改zynq7处理器的配置。
在emio那里打钩,添加EMIO外设。
只添加8个EMIO,所以位数选8。
4、完成更改,回到block design中看看,发现多出了GPIO_0。选中他,按CTRL+T将引脚引出。这里的GPIO_0对应EMIO。
5、保存当前的block design,回到工程视图,产生仿真文件。
6、创建顶层文件。
打开新建的Verilog文件,可以看到新加的接口:gpio_tri_io_0。
7、由于EMIO是PL部分新添加的外设,还需要进行引脚约束。
添加引脚约束文件。
8、创建一个xdc文件。
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闪烁。
这里选用的GPIO的引脚号是54,对应第一个EMIO,也就是之前引脚约束时分配的第一个LED对应的引脚;总共分配了8个EMIO,更改这个引脚号,也同样可以控制其他几个LED。