1.GPIO(generate )
PS端
500和501:共54根引脚,连接PS MIO,外设通过MIO用软件进行多路复用。
502:用来和DDR连接的。
PL端:13、34、35。
1.GPIO是一个外设,用来对器件引脚做观测(input)以及控制(output)。
2.每个IO都可以独立的、动态的编程。作为输入/输出/中断模式每个IO对应一个寄存器地址。控制IO的本质是读写寄存器地址。
3.GPIO被分成了四个bank,bank0和bank1通过MIO连接到PS引脚,bank2和bank3通过EMIO连接到PL引脚。
4.软件通过一组存储映射(memery-mapped)的寄存器来控制GPIO.
#存储映射:是指一次读写操作过程中的地址
控制GPIO的寄存器组
1.DATA_RO:用来反映器件引脚的状态。
2.DATA:32位,当GPIO被配置成输出的时候,该寄存器可以控制输出的值。
3.MASK_DATA_LSW/MASK_DATA_MSW:16位掩膜。
4.DIRM:控制IO引脚是作为输入还是输出。本质是控制输出使能。
5.OEN:当配置成输出(DIRM=1)的时候,OEN才有用。该寄存器用来打开/关闭输出使能。决定输出时data还是高阻态。
1.1 GPIO功能配置
上电和复位在编程时不需要考虑。
1.1.1 GPIO Configuration
2.MIO和EMIO
ZYNQ GPIO 接口信号被分成四组,分别是从 BANK0 到 BANK3。
其中 BANK0 和 BANK1 中共计 54个信号通过 MIO 连接到 ZYNQ 器件的引脚上,这些引脚属于 PS 端;
而 BANK2 和 BANK3 中共计 64 个信号则通过 EMIO 连接到了 ZYNQ 器件的 PL 端。
上半部分为中断有关的寄存器,下半部分为数据有关的寄存器。
控制GPIO的寄存器组
1.DATA_RO:当GPIO被配置成输入时,使软件观察到GPIO上的值。
2.DATA:32位,当GPIO被配置成输出的时候,该寄存器可以控制输出的值。
3.MASK_DATA_LSW/MASK_DATA_MSW:16位掩膜。
4.DIRM:控制IO引脚是作为输入还是输出。本质是控制输出使能。
5.OEN:当配置成输出(DIRM=1)的时候,OEN才有用。该寄存器用来打开/关闭输出使能。决定输出时data还是高阻态。
2.1 MIO
MIO:将来自PS外设和静态存储器接口的访问多路复用到PS的引脚上。把PS的外设和PS的引脚连接起来。并不是一一对应,可通过编程改变(多路复用)。
2.2 EMIO
EMIO(extendable multiuse I/O):是PS和PL之间的接口,扩展PS的引脚,使用FPGA端的引脚。PL端的引脚给PS端使用。
PS可以通过EMIO访问PL端。
4.GPIO中断
控制中断的寄存器组
1.INT_TYPR:中断类型选择——边沿或者电平(1边沿0电平)。
2.INT_POLARITY:极性选择(1正极性或者0负极性)。根据中断类型是边沿还是电平来确定是升降边沿还是高低电平触发。
3.INT_ANY:只针对边沿触发,是否同时支持升降沿触发(0不支持1支持)。
以上三个值进入中断逻辑寄存器来确定最后的中断触发条件
4.INT_STAT:写1清除中断。读来获取当前中断状态。
5.INT_MASK:中断屏蔽,选择性的屏蔽某些端口的GPIO
6.INT_DIS/INT_EN:使能或者关闭中断使能。
7.IRQ #52 to GIC:可以接收到PS和PL的中断请求信号。每个中断源都有一个自己的ID,GPIO的中断号为52.
5.代码
5.1 MIO和EMIO控制GPIO
/*
用PL端口的GPIO操控PS端口的LED
按键按下为1,没按下为0;
灯1亮,0灭
*/
#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
//核心板上PS端LED
#define MIO_0_LED 0
//底板上PS端的LED
#define MIO_7_LED 7
#define MIO_8_LED 8
//底板上PS端的按键
#define MIO_11_KEY 11 //KEY1
#define MIO_12_KEY 12 //KEY0
//底板上PL端的按键
#define EMIO_KEY0 54 //bank35 L20 PL KEY0
XGpioPs_Config * ConfigPtr ;
XGpioPs Gpio ; /* The driver instance for GPIO Device. */
int main(){
u32 ps_key0_value;
u32 ps_key1_value;
u32 pl_key0_value;
printf("GPIO EMIO TEST!\n\r");
//根据器件ID,查找器件的配置信息,返回值是一个结构体指针(XGpioPs_Config *)
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化GPIO驱动
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
//把GPIO的方向设置为输出(0输入 1输出)
XGpioPs_SetDirectionPin(&Gpio, MIO_0_LED, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_7_LED, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_8_LED, 1);
//把GPIO的方向设置为输入(0输入 1输出)
XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY0, 0);
XGpioPs_SetDirectionPin(&Gpio, MIO_12_KEY, 0);
XGpioPs_SetDirectionPin(&Gpio, MIO_11_KEY, 0);
//设置输出使能(0关闭 1打开)
XGpioPs_SetOutputEnablePin(&Gpio, MIO_0_LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO_7_LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO_8_LED, 1);
//写数据到GPIO
while(1){
//读取按键状态
ps_key0_value = XGpioPs_ReadPin(&Gpio, MIO_12_KEY);
ps_key1_value = XGpioPs_ReadPin(&Gpio, MIO_11_KEY);
pl_key0_value = XGpioPs_ReadPin(&Gpio, EMIO_KEY0);
//将按键状态写入LED(按键按下灯亮,松开灯灭)
XGpioPs_WritePin(&Gpio,MIO_0_LED,~ps_key0_value);
XGpioPs_WritePin(&Gpio,MIO_7_LED,~ps_key1_value);
XGpioPs_WritePin(&Gpio,MIO_8_LED,~pl_key0_value);
}
return 0;
}
5.2 中断控制GPIO
/*
用PS端口的GPIO操控PS端口的LED
*/
#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "sleep.h"
#include "xscugic.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
//GPIO的中断号
#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR
//GIC器件ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
//核心板上PS端LED
#define MIO_0_LED 0
//PS端按键KEY
#define MIO_12_KEY 12
XGpioPs_Config * ConfigPtr ;
XScuGic_Config * IntcConfig ; /* Instance of the interrupt controller */
//驱动实例
XGpioPs Gpio ; /* The driver instance for GPIO Device. */
XScuGic Intc ; /* The Instance of the Interrupt Controller Driver */
void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,u16 GpioIntrId);
void IntrHandler();//中断服务函数
u32 key_press = 0;
int main(){
u32 led_value = 0;
printf("GPIO INTERUPT TEST!\n\r");
//根据器件ID,查找器件的配置信息,返回值是一个结构体指针(XGpioPs_Config *)
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化GPIO驱动
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
//把GPIO的方向设置为输出(0输入 1输出)
XGpioPs_SetDirectionPin(&Gpio, MIO_0_LED, 1);
//把GPIO的方向设置为输入(0输入 1输出)
XGpioPs_SetDirectionPin(&Gpio, MIO_12_KEY, 0);
//设置输出使能(0关闭 1打开)
XGpioPs_SetOutputEnablePin(&Gpio, MIO_0_LED, 1);
//
SetupInterruptSystem(&Intc, &Gpio, GPIO_INTERRUPT_ID);
//写数据到GPIO
while(1){
//改变LED的显示状态
if(key_press == 1){
led_value = ~led_value;
key_press = 0;
//清除之前的中断状态
XGpioPs_IntrClearPin(&Gpio,MIO_12_KEY);
//延时消抖
XGpioPs_WritePin(&Gpio,MIO_0_LED,led_value);
//再次使能中断
usleep(200000);
XGpioPs_IntrEnablePin(&Gpio,MIO_12_KEY);
}
}
return 0;
}
//设置中断
void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
u16 GpioIntrId)
{
//查找GIC器件配置信息,并进行初始化
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
//初始化RAM处理器异常句柄
Xil_ExceptionInit();
//给IRQ注册异常处理程序
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicInstancePtr);
//使能处理器的中断
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
//关联中断处理函数,当外部中断来临时
XScuGic_Connect(GicInstancePtr, GpioIntrId,(Xil_ExceptionHandler)IntrHandler,(void *)Gpio);
//为GPIO器件使能中断,对中断控制器进行配置
XScuGic_Enable(GicInstancePtr, GpioIntrId);
//设置MIO引脚中断类型为下降沿触发
XGpioPs_SetIntrTypePin(Gpio, MIO_12_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
//打开中断使能,对IO管脚配置
XGpioPs_IntrEnablePin(Gpio, MIO_12_KEY);
}
void IntrHandler(){
printf("interupt detected!\n\r ");
key_press = 1;
//屏蔽中断
XGpioPs_IntrDisablePin(&Gpio,MIO_12_KEY);
}