总结一下zynq的GPIO应用
zynq的GPIO分为PS部分的MIO和PS-PL配合使用的EMIO(用PL端的IO扩展GPIO),由PS调度。这里描述一下这个EMIO的应用。
IP的方式扩展IO
在vivado下配置AXI接口的GPIO
这里例化了两组GPIO,一组作为 LED的输出IO,一组作为按键的输入IO,采用中断方式检测电平变化
#include <stdio.h>
#include <xgpio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xscugic.h"
#include "xscutimer.h"
#include "./inc/gpio.h"
static XGpio led_out_4b;
static XGpio BTNInst;
static XScuGic INTCInst;
int XGpio_InterruptInitialize(void)
{
int status;
printf("LED 4bit Init.............\r\n");
status = XGpio_Initialize(&led_out_4b,XPAR_AXI_GPIO_0_DEVICE_ID); //Init LED GPIO
if(status != XST_SUCCESS)
return XST_FAILURE;
XGpio_SetDataDirection(&led_out_4b,1,0x00); //Set GPIO as output
status = XGpio_Initialize(&BTNInst, BTNS_DEVICE_ID);
if(status != XST_SUCCESS)
return XST_FAILURE;
XGpio_SetDataDirection(&BTNInst, 1, 0xFF);
printf("EXIT InterruptInitialize......\r\n");
status = IntcInitFunction(EXIT_INTC_DEVICE_ID, &BTNInst);
if(status != XST_SUCCESS)
return XST_FAILURE;
return XST_SUCCESS;
}
//----------------------------------------------------
// INTERRUPT SETUP FUNCTIONS
//----------------------------------------------------
int IntcInitFunction(u16 DeviceId, XGpio *GpioInstancePtr)
{
XScuGic_Config *IntcConfig;
int status;
// Interrupt controller initialization
IntcConfig = XScuGic_LookupConfig(DeviceId);
status = XScuGic_CfgInitialize(&INTCInst, IntcConfig,
IntcConfig->CpuBaseAddress);
if(status != XST_SUCCESS)
return XST_FAILURE;
// Register GIC interrupt handler
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&INTCInst);
Xil_ExceptionEnable();
// Register GPIO interrupt handler
status = XScuGic_Connect(&INTCInst,
INTC_GPIO_INTERRUPT_ID,
(Xil_ExceptionHandler)BTN_Intr_Handler,
(void *)GpioInstancePtr);
if(status != XST_SUCCESS)
return XST_FAILURE;
// Enable GPIO interrupts
XGpio_InterruptEnable(GpioInstancePtr, 1);
XGpio_InterruptGlobalEnable(GpioInstancePtr);
// Enable GPIO interrupts in the controller
XScuGic_Enable(&INTCInst, INTC_GPIO_INTERRUPT_ID);
return XST_SUCCESS;
}
void BTN_Intr_Handler(void *InstancePtr)
{
u8 btn_value = 0;
unsigned char led_val = 0;
// Ignore additional button presses
if ((XGpio_InterruptGetStatus(&BTNInst) & BTN_INT) != BTN_INT)
{
printf("Other interrupt......\r\n");
return;
// Disable GPIO interrupts
XGpio_InterruptDisable(&BTNInst, BTN_INT);
}
btn_value = ~ XGpio_DiscreteRead(&BTNInst, 1)&0x0f;
printf("key value 0x%x......\r\n",btn_value);
switch (btn_value){
case 0x01: led_val = 0x01; break;
case 0x02: led_val = 0x02; break;
case 0x04: led_val = 0x04; break;
case 0x08: led_val = 0x08; break;
default:break;
}
XGpio_DiscreteWrite(&led_out_4b,1,~led_val);
// Acknowledge GPIO interrupts
(void)XGpio_InterruptClear(&BTNInst, BTN_INT);
// Enable GPIO interrupts
XGpio_InterruptEnable(&BTNInst, BTN_INT);
}
上面代码初始化EMIO和按键中断的初始化和中断处理函数
直接扩展EMIO,由ZYNQ处理器引出到PL端配置IO
硬件连接
CPU GPIO定制配置
由硬件导入到SDK中会生成相应的驱动API,
使用刚才例化的GPIO做了一个IIC(源码借鉴某位大神,尊重原著,略有修改)
初始化IO和调用API接口如下代码:
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
#include "xgpiops.h"
#include "./inc/i2c.h"
static XGpioPs psGpioInstancePtr;
int EMIO_I2C_init(void)
{
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("EMIO INIT FAILED \n\r");
XGpioPs_SetDirectionPin(&psGpioInstancePtr, SCL_PIN,DIRECTION_OUTPUT);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, SDA_PIN,DIRECTION_OUTPUT);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, SCL_PIN,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, SDA_PIN,1);
return xStatus;
}
void CLOCK_HIGH(void)
{
XGpioPs_WritePin(&psGpioInstancePtr,SCL_PIN, 1);
}
void CLOCK_LOW(void)
{
XGpioPs_WritePin(&psGpioInstancePtr,SCL_PIN, 0);
}
int GET_DATA(void)
{
return XGpioPs_ReadPin(&psGpioInstancePtr,SDA_PIN);
}
void DATA_INPUT(void)
{
XGpioPs_SetDirectionPin(&psGpioInstancePtr, SDA_PIN,DIRECTION_INPUT);//
}
void DATA_OUTPUT(void)
{
XGpioPs_SetDirectionPin(&psGpioInstancePtr, SDA_PIN,DIRECTION_OUTPUT);//
}
void DATA_HIGH(void)
{
XGpioPs_WritePin(&psGpioInstancePtr,SDA_PIN, 1);
}
void DATA_LOW(void)
{
XGpioPs_WritePin(&psGpioInstancePtr,SDA_PIN,0);
}
void I2C_start(void)
{
CLOCK_HIGH();
DATA_HIGH();
I2C_DELAY;
DATA_LOW();
I2C_DELAY;
CLOCK_LOW();
I2C_DELAY;
}
void I2C_end(void)
{
DATA_LOW();
I2C_DELAY;
CLOCK_HIGH();
I2C_DELAY;
DATA_HIGH();
I2C_DELAY;
}
int I2C_sendbyte( unsigned char value )
{
unsigned char tmp = value;
unsigned char i=0,ack;
for(i=0; i<8; i++)
{
if(tmp & 0x80 )
DATA_HIGH();
else
DATA_LOW();
I2C_DELAY;
CLOCK_HIGH();
I2C_DELAY;
CLOCK_LOW();
I2C_DELAY;
tmp<<=1;
}
DATA_HIGH();
DATA_INPUT();
I2C_DELAY;
CLOCK_HIGH();
ack = GET_DATA();
I2C_DELAY;
CLOCK_LOW();
I2C_DELAY;
DATA_OUTPUT();
if(ack==1)
{
return -1;
}
return 0;
}
unsigned char I2C_readbyte( unsigned char addr)
{
unsigned char i=0,data=0;
DATA_HIGH();
DATA_INPUT();
for(i=0; i<8; i++)
{
CLOCK_HIGH();
I2C_DELAY;
data <<= 1;
if(GET_DATA())
data |= 1;
I2C_DELAY;
CLOCK_LOW();
I2C_DELAY;
}
DATA_OUTPUT();
DATA_HIGH();
I2C_DELAY;
CLOCK_HIGH();
I2C_DELAY;
CLOCK_LOW();
I2C_DELAY;
DATA_HIGH();
return data;
}
int I2C_readdata(unsigned char id, unsigned char addr, unsigned char *value)
{
// 两相写
I2C_start();
if(I2C_sendbyte(id<<1) != 0)
{
goto error;
}
if(I2C_sendbyte(addr) != 0)
{
goto error;
}
// 两相读
I2C_start();
if(I2C_sendbyte((id<<1)|0x1) != 0)
{
goto error;
}
*value = I2C_readbyte(addr);
I2C_end();
return 0;
error:
I2C_end();
return -1;
}
int I2C_writedata(unsigned char id, unsigned char addr,unsigned char value)
{
I2C_start();
if(I2C_sendbyte(id<<1) != 0)
{
goto error;
}
if(I2C_sendbyte(addr) != 0)
{
goto error;
}
if(I2C_sendbyte(value)!= 0)
{
goto error;
}
I2C_end();
return 0;
error:
I2C_end();
return -1;
}
void i2c_test(void)
{
u8 data = 0xAA;
EMIO_I2C_init();
usleep(500*1000);
if (I2C_writedata(I2C_DEVICE_ADDR,0x00,data) != 0)
printf("IIC write error!!!!!!!!!!!!!\r\n");
else
printf("IIC write addr 0x00 data is 0x%X \r\n",data);
usleep(50000); //写到读之间延时一段时间
data = 0;
if(I2C_readdata(I2C_DEVICE_ADDR,0x00,&data) != 0)
printf("IIC read error!!!!!!!!!!!!!\r\n");
else
printf("IIC read addr 0x00 data is 0x%X \r\n",data);
}
这里可以测试GPIO的应用,包括按键触发中断,根据按键的状态点灯;EMIO模拟IIC接口读写EEPROM测试。