Xilinx ZYNQ 7000+Vivado2015.2系列(四)之GPIO的三种方式:MIO、EMIO、AXI_GPIO
前言:
ZYNQ 7000有三种GPIO:MIO,EMIO,AXI_GPIO
MIO是固定管脚的,属于PS,使用时不消耗PL资源;
EMIO通过PL扩展,使用时需要分配管脚,使用时消耗PL管脚资源;
AXI_GPIO是封装好的IP核,PS通过M_AXI_GPIO接口控制PL部分实现IO,使用时消耗管脚资源和逻辑资源。
使用的板子是zc702。
1.MIO方式
Zynq7000 系列芯片有 54 个 MIO(multiuse I/O), 它们分配在 GPIO 的 Bank0 和Bank1 隶属于 PS 部分。
这些 IO 与 PS 直接相连。 不需要添加引脚约束。
MIO 信号对 PL部分是透明的, 不可见。 所以对 MIO 的操作可以看作是纯 PS 的操作。
新建Vivado工程,添加ZYNQ CPU核,双击,配置好时钟和内存类型,确认勾选MIO:
如系列(三)文章所述,生成bit stream,然后Launch SDK。
在SDK中新建工程,源文件如下:
#include "xgpiops.h"
#include "sleep.h"
int main(){
static XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int iPinNumber= 8;
u32 uPinDirection = 0x1;
int xStatus;
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");
XGpioPs_SetDirectionPin(&psGpioInstancePtr, iPinNumber,uPinDirection);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);
while(1){
XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 1);
usleep(500000);
XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 0);
usleep(500000);
}
return 0;
}
下载到板子上,DS12就开始闪烁了。
2.EMIO方式
EMIO 分配在 bank2 和 bank3 和 PL部分相连。EMIO 有 64 个引脚可供我们使用 。
当 MIO 不够用时, PS 可以通过驱动 EMIO 控制 PL 部分的引脚 。
Vivado工程里ZYNQ CPU核配置,确保EMIO勾选,这里我设置了位宽为4,后面为其分配了四个管脚:
在Diagram里面将GPIO_0的引脚引出来,生成顶层文件后查看这个引脚的名字,因为我修改了名字,这里叫emio_0_tri_io
管脚约束文件:
#GPIO PMOD1
set_property PACKAGE_PIN E15 [get_ports {emio_0_tri_io[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {emio_0_tri_io[0]}]
set_property PACKAGE_PIN D15 [get_ports {emio_0_tri_io[1]}]
set_property IOSTANDARD LVCMOS25 [get_ports {emio_0_tri_io[1]}]
set_property PACKAGE_PIN W17 [get_ports {emio_0_tri_io[2]}]
set_property IOSTANDARD LVCMOS25 [get_ports {emio_0_tri_io[2]}]
set_property PACKAGE_PIN W5 [get_ports {emio_0_tri_io[3]}]
set_property IOSTANDARD LVCMOS25 [get_ports {emio_0_tri_io[3]}]
SDK部分:MIO号是0~53,EMIO从54开始
#include "xgpiops.h"
#include "sleep.h"
int main()
{
static XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int xStatus;
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");
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 54,1);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 55,1);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 56,1);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 57,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 54,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 55,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 56,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 57,1);
while(1)
{
XGpioPs_WritePin(&psGpioInstancePtr, 54, 1);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 54, 0);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 55, 1);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 55, 0);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 56, 1);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 56, 0);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 57, 1);
usleep(200000);
XGpioPs_WritePin(&psGpioInstancePtr, 57, 0);
usleep(200000);
}
return 0;
}
下载到板子里,PMOD1的4个led灯交替闪烁。
3.AXI_GPIO方式
VIvado工程里,ZYNQ CPU核配置:
勾选M_AXI_GPIO 接口:
勾选复位信号:
给PL的时钟信号:
加入AXI_GPIO IP,这里设置位宽为4,后面将控制4个led灯:
自动连接后如下图:
管脚约束如下:
#GPIO PMOD1
set_property PACKAGE_PIN E15 [get_ports {gpio_sw_tri_o[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_sw_tri_o[0]}]
set_property PACKAGE_PIN D15 [get_ports {gpio_sw_tri_o[1]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_sw_tri_o[1]}]
set_property PACKAGE_PIN W17 [get_ports {gpio_sw_tri_o[2]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_sw_tri_o[2]}]
set_property PACKAGE_PIN W5 [get_ports {gpio_sw_tri_o[3]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_sw_tri_o[3]}]
SDk部分如下:
#include <stdio.h>
#include "platform.h"
#include "xparameters.h"
#include "xgpio.h"
int main() {
XGpio gpio_led;
int status;
int i,x,y;
init_platform();
status = XGpio_Initialize(&gpio_led, 0);
if(status == 0){
printf("success \r\n");
}
XGpio_SetDataDirection(&gpio_led,1,0);
while (1){
for (i = 0; i<=3; i++){
XGpio_DiscreteWrite(&gpio_led, 1, 0x01<<i);
for(x =1000; x > 0; x-- ){
for (y = 100000; y > 0; y--);
}
}
}
cleanup_platform();
return 0;
}
可以看到,与EMIO一样需要分配管脚,
但是AXI_GPIO使用的头文件是#include "xgpio.h"
,
而EMIO是#include "xgpiops.h"
。
下载完成后,PMOD1 的四个LED灯依次闪烁。
总结:
MIO和EMIO使用PS的GPIO,,MIO固定管脚,EMIO手动分配管脚;IP方式手动分配管脚,综合后需要消耗PL的逻辑资源。