一、EMIO简介
ZYNQ GPIO 接口信号被分成四组,分别是从 BANK0 到 BANK3。其中 BANK0 和 BANK1 中共计 54个信号通过 MIO 连接到 ZYNQ 器件的引脚上,这些引脚属于 PS 端; 而 BANK2 和 BANK3 中共计 64 个信号则通过 EMIO 连接到了 ZYNQ 器件的 PL 端, 如下图所示:
在大多数情况下, PS 端经由 EMIO 引出的接口会直接连接到 PL 端的器件引脚上, 通过 IO 管脚约束来指定所连接 PL 引脚的位置。 通过这种方式, EMIO 可以为 PS 端实现额外的 64 个输入引脚或 64 个带有输出使能的输出引脚。 EMIO 还有一种使用方式,就是用于连接 PL 内实现的功能模块( IP 核) , 此时 PL 端的 IP 作为 PS 端的一个外部设备, 如图 4.1.2 所示:
EMIO:扩展MIO,是PS与PL端的接口,当PS引脚不够用时,可以拓展EMIO使用PL端引脚
二、实验任务
本章的实验任务是使用 Z100 底板上的两个用户按键分别控制 PS 端两个 LED 的亮灭。其中一个按键PL_KEY0 连接到了 PL 端, 需要通过 EMIO 进行扩展,另外一个按键是底板上 PS 端的用户按键 PS_KEY0,这两个按键分别控制 PS_LED0 和 PS_LED1,底板上的 PS_KEY0 控制 PS_LED0、 PL_KEY0 控制 PS_LED1。两个 LED 灯在按键按下的时候点亮,释放后熄灭
三、程序设计
1、整体框图:
2、硬件设计
根据实际需要选择位宽
对EMIO进行管脚约束
Haskell
set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS18} [get_ports GPIO_0_0_tri_io[0]]
代码编写:
注意bank地址!!!
cs
#include <stdio.h>
#include "xparameters.h"
#include "xgpiops.h"
#include "sleep.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define MIO_LED1 7//MIO7
#define MIO_LED2 8//MIO8
#define MIO_LED0 0//MIO0
#define MIO_KEY0 12//MIO12
#define EMIO_KEY0 54//EMIO54
XGpioPs Gpio; /* The driver instance for GPIO Device. */
int main(){
XGpioPs_Config *ConfigPtr;
u32 ps_key;
u32 pl_key;
//初始化GPIO驱动配置
//根据器件ID来查找器件配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//对GPIO的驱动进行初始化
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
//设置引脚方向
XGpioPs_SetDirectionPin(&Gpio, MIO_LED1, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_LED2, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_LED0, 1);
//设置PS_KEY
XGpioPs_SetDirectionPin(&Gpio, MIO_KEY0, 0);
//设置PL_KEY
XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY0, 0);
//设置输出使能 0:输入 1:输出
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED1, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED2, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED0, 1);
printf("GPIO MIO TEXT!\n");
while(1){
ps_key = XGpioPs_ReadPin(&Gpio,MIO_KEY0);
pl_key = XGpioPs_ReadPin(&Gpio,EMIO_KEY0);
XGpioPs_WritePin(&Gpio, MIO_LED1, ps_key);
XGpioPs_WritePin(&Gpio, MIO_LED2, pl_key);
XGpioPs_WritePin(&Gpio, MIO_LED0, ps_key);
}
return 0 ;
}
四、下载验证
五、总结
六、拓展训练
约束管脚
Haskell
set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS18} [get_ports GPIO_0_0_tri_io[0]]
set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports GPIO_0_0_tri_io[1]]
重新生成硬件信息
代码编写:
Haskell
#include <stdio.h>
#include "xparameters.h"
#include "xgpiops.h"
#include "sleep.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define MIO_LED1 7//MIO7
#define MIO_LED2 8//MIO8
#define MIO_LED0 0//MIO0
#define MIO_KEY0 12//MIO12
#define EMIO_KEY0 54//EMIO54
#define EMIO_KEY1 55//EMIO54
XGpioPs Gpio; /* The driver instance for GPIO Device. */
int main(){
XGpioPs_Config *ConfigPtr;
u32 ps_key;
u32 pl_key1;
u32 pl_key2;
//初始化GPIO驱动配置
//根据器件ID来查找器件配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//对GPIO的驱动进行初始化
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
//设置引脚方向
XGpioPs_SetDirectionPin(&Gpio, MIO_LED1, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_LED2, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_LED0, 1);
//设置PS_KEY
XGpioPs_SetDirectionPin(&Gpio, MIO_KEY0, 0);
//设置PL_KEY
XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY0, 0);
XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY1, 0);
//设置输出使能 0:输入 1:输出
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED1, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED2, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED0, 1);
printf("GPIO MIO TEXT!\n");
while(1){
ps_key = XGpioPs_ReadPin(&Gpio,MIO_KEY0);
pl_key1 = XGpioPs_ReadPin(&Gpio,EMIO_KEY0);
pl_key2 = XGpioPs_ReadPin(&Gpio,EMIO_KEY1);
XGpioPs_WritePin(&Gpio, MIO_LED1, ps_key);
XGpioPs_WritePin(&Gpio, MIO_LED2, pl_key1);
XGpioPs_WritePin(&Gpio, MIO_LED0, pl_key2);
}
return 0 ;
}
编译执行: