ZYNQ之简易流水灯(EMIO、AXI GPIO)

一般来说ZYNQ可以有三种方式实现流水灯:MIO,EMIO,AXI GPIO。但是由于赛灵思的ZYNQ开发板MIO资源没有LED,所以实现流水灯只能EMIO或者AXI GPIO。这里使用AXI GPIO实现流水灯,为了更多的使用板子资源,在流水灯的基础上增加了按键,中断,定时器,串口等功能可以实现流水灯的方向的切换,精准定时等功能。同时也会给出AXI GPIO和EMIO实现流水灯的代码。 

一、vivado

创建一个工程,添加ZYNQ IP核

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第1张图片

点击自动连线

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第2张图片

 完成后双击打开,配置EMIO

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第3张图片

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第4张图片

配置EMIO位宽为2

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第5张图片

然后添加AXI GPIO 

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第6张图片

 点击自动连线

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第7张图片

左边全勾上,接口选择led

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第8张图片

 然后点击ZYNQ核上的GPIO,刚刚才配置的,设置将引脚扩展处来,为后面PL分配引脚做准备。

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第9张图片

 然后删除USB端口,不然后面会报错ZYNQ之简易流水灯(EMIO、AXI GPIO)_第10张图片

 

然后验证当前设计,出现如下弹窗,说明设计结果正确。

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第11张图片

 在 Sources 窗口中,选中 Design Sources 下的 .bd文件生成HDL 模块
ZYNQ之简易流水灯(EMIO、AXI GPIO)_第12张图片

 ZYNQ之简易流水灯(EMIO、AXI GPIO)_第13张图片

然后进行分析与综合

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第14张图片

 分配引脚为刚刚我们设置的两个EMIO

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第15张图片

按键原理图

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第16张图片

 设置按键引脚和电源值

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第17张图片

保存引脚约束文件

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第18张图片

然后生成字节流,因为用到了PL部分

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第19张图片

 将硬件导出

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第20张图片

启动vitis进入软件编程部分

ZYNQ之简易流水灯(EMIO、AXI GPIO)_第21张图片

二、vitis

这里工程的建立就不说了,具体的可以参考前面的

1.LED

主要是初始化LED和设置LED的输入输出方向

int led_init(void)
{
	int Status;
	//初始化GPIO
	Status = XGpio_Initialize(&Axi_Gpio, GPIO_DEVICE_ID);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}
	//设置GPIO输入/输出模型  0:输出  1:输入
	XGpio_SetDataDirection(&Axi_Gpio, led_channel, 0x00);
	return XST_SUCCESS;
}

2.Key

主要是初始化Key和设置Key的输入输出方向


int key_init(void)
{
	int Status;
	//查找器件的ID,查找器件的配置信息
	ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	if (ConfigPtr == NULL)
	{
		return XST_FAILURE;
	}
	//初始化GPIO驱动
	Status = XGpioPs_CfgInitialize(&Key_Gpio, ConfigPtr,ConfigPtr->BaseAddr);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}

	//设置输出使能(最后一个参数:0表示关闭使能,1表示打开)
	XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY0, 1);
	XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY1, 1);


	//把GPIO的方向设置为输入(最后一个参数:0表示输入,1表示输出)
	XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY0, 0);
	XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY1, 0);
	return XST_SUCCESS;

}

3.定时器

初始化定时器并且设置定时器的周期和模式。定时器周期计算主要是要主要私有定时器的时钟频率为CPU工作频率的一半。

int timer_init(void)
{
	int Status;
	//私有定时器初始化
	XScuTimer_Config *timer_cfg_ptr;
	timer_cfg_ptr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
	if (timer_cfg_ptr == NULL)
	{
		return XST_FAILURE;
	}
	Status = XScuTimer_CfgInitialize(&Timer, timer_cfg_ptr,timer_cfg_ptr->BaseAddr);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}

	XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); // 加载计数周期
	XScuTimer_EnableAutoReload(&Timer); // 设置自动装载模式
	return XST_SUCCESS;
}

4.中断

中断处理固定模式:

①初始化中断控制器

②初始化CPU异常功能、向CPU注册异常处理回调函数、使能异常处理功能

③使能中断控制器、设置中断的类型、使能对应引脚的中断

④设置中断的回调函数(用户自己设置)

int interrupt_init()
{
	int Status;
	//初始化中断控制器
	XScuGic_Config *gic_cfg; //中断控制器配置信息
	gic_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (gic_cfg == NULL)
	{
		return XST_FAILURE;
	}
	Status = XScuGic_CfgInitialize(&Intc,gic_cfg,gic_cfg->CpuBaseAddress);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}
	//初始化异常处理
	Xil_ExceptionInit();
	//CPU中断异常注册
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&Intc);
	//使能处理器中断
	Xil_ExceptionEnable();;

	//设置定时器中断:  timer_intr_handler 中断处理函数
	XScuGic_Connect(&Intc, TIMER_IRPT_INTR,(Xil_ExceptionHandler)timer_intr_handler, &Timer);


	XScuGic_Enable(&Intc,TIMER_IRPT_INTR);//使能 GIC 中的定时器中断
	XScuTimer_EnableInterrupt(&Timer); //使能定时器中断

	return XST_SUCCESS;
}

三、代码

EMIO代码:

#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "sleep.h"

#define GPIO_DEVICE_ID  	XPAR_XGPIOPS_0_DEVICE_ID

//EMIO引脚从54开始算起
#define EMIO_LED0      54
#define EMIO_LED1      55
#define EMIO_LED2      56
#define EMIO_LED3      57

#define EMIO_KEY0      58
#define EMIO_KEY1      59
int key_scan();
XGpioPs_Config * ConfigPtr;
XGpioPs Gpio;	/* The driver instance for GPIO Device. */

int main()
{
	int key_value;

	//查找器件的ID,查找器件的配置信息
	ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	//初始化GPIO驱动
	XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);

	//LED:
	//把GPIO的方向设置为输出(最后一个参数:0表示输入,1表示输出)
	XGpioPs_SetDirectionPin(&Gpio, EMIO_LED0, 1);
	XGpioPs_SetDirectionPin(&Gpio, EMIO_LED1, 1);
	XGpioPs_SetDirectionPin(&Gpio, EMIO_LED2, 1);
	XGpioPs_SetDirectionPin(&Gpio, EMIO_LED3, 1);

	//设置输出使能(最后一个参数:0表示关闭使能,1表示打开)
	XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED0, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED1, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED2, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED3, 1);


	//KEY:
	//把GPIO的方向设置为输入(最后一个参数:0表示输入,1表示输出)
	XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY0, 0);
	XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY1, 0);

	while(1)
	{
		key_value = key_scan();
		if(key_value ==1)
		{
			//将按键的状态写入LED
			XGpioPs_WritePin(&Gpio, EMIO_LED1,1);

		}
		else if(key_value ==2)
		{

			XGpioPs_WritePin(&Gpio, EMIO_LED1,0);

		}
	}
	return 0;
}


int key_scan()
{
	int val=0;
	if(XGpioPs_ReadPin(&Gpio, EMIO_KEY0) == 1)
		val = 1;
	if(XGpioPs_ReadPin(&Gpio, EMIO_KEY1) == 1)
		val = 2;

	return val;
}

AXI GPIO代码:

#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xplatform_info.h"
#include 
#include "xgpio.h"
#include "xscutimer.h"
#include "xil_exception.h"

#define GPIO_DEVICE_ID		XPAR_XGPIOPS_0_DEVICE_ID  //GPIO ID
#define TIMER_DEVICE_ID     XPAR_XSCUTIMER_0_DEVICE_ID //定时器 ID

#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID  //中断控制器 ID
#define TIMER_IRPT_INTR     XPAR_SCUTIMER_INTR //定时器中断 ID


static XScuGic   Intc;  //中断驱动程序实例
static XScuTimer Timer; //定时器驱动程序实例
#define TIMER_LOAD_VALUE  0x1EFE920 //定时器装载值 100ms中断   1EFE920

//EMIO KEY
static XGpioPs Key_Gpio; //gpio ps 驱动实例
static XGpioPs_Config * ConfigPtr;
#define EMIO_KEY0      54
#define EMIO_KEY1      55

//AXI GPIO
#define led_channel 1   //LED灯引脚
static XGpio Axi_Gpio;	//GPIO设备的驱动实例

static int key_val,key_down,key_up,key_old;   //按键处理
static int delay_cnt=0; //用于精准延时

int led_init(void)
{
	int Status;
	//初始化GPIO
	Status = XGpio_Initialize(&Axi_Gpio, GPIO_DEVICE_ID);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}
	//设置GPIO输入/输出模型  0:输出  1:输入
	XGpio_SetDataDirection(&Axi_Gpio, led_channel, 0x00);
	return XST_SUCCESS;
}

int key_init(void)
{
	int Status;
	//查找器件的ID,查找器件的配置信息
	ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	if (ConfigPtr == NULL)
	{
		return XST_FAILURE;
	}
	//初始化GPIO驱动
	Status = XGpioPs_CfgInitialize(&Key_Gpio, ConfigPtr,ConfigPtr->BaseAddr);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}

	//设置输出使能(最后一个参数:0表示关闭使能,1表示打开)
	XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY0, 1);
	XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY1, 1);


	//把GPIO的方向设置为输入(最后一个参数:0表示输入,1表示输出)
	XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY0, 0);
	XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY1, 0);
	return XST_SUCCESS;

}


int key_scan()
{
	int val=0;
	if(XGpioPs_ReadPin(&Key_Gpio, EMIO_KEY0) == 1)
		val = 1;
	if(XGpioPs_ReadPin(&Key_Gpio, EMIO_KEY1) == 1)
		val = 2;
	return val;
}


//中断处理函数 100ms
void timer_intr_handler(void *CallBackRef)
{
	XScuTimer *timer_ptr = (XScuTimer *) CallBackRef;

	delay_cnt += 1;

	//处理按键
	key_val = key_scan();
	key_down = key_val & (key_old^key_val);
	key_up = ~key_val & (key_old^key_val);
	key_old = key_val;

	//清除定时器中断标志
	XScuTimer_ClearInterruptStatus(timer_ptr);
}

int interrupt_init()
{
	int Status;
	//初始化中断控制器
	XScuGic_Config *gic_cfg; //中断控制器配置信息
	gic_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (gic_cfg == NULL)
	{
		return XST_FAILURE;
	}
	Status = XScuGic_CfgInitialize(&Intc,gic_cfg,gic_cfg->CpuBaseAddress);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}
	//初始化异常处理
	Xil_ExceptionInit();
	//CPU中断异常注册
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&Intc);
	//使能处理器中断
	Xil_ExceptionEnable();;

	//设置定时器中断:  timer_intr_handler 中断处理函数
	XScuGic_Connect(&Intc, TIMER_IRPT_INTR,(Xil_ExceptionHandler)timer_intr_handler, &Timer);


	XScuGic_Enable(&Intc,TIMER_IRPT_INTR);//使能 GIC 中的定时器中断
	XScuTimer_EnableInterrupt(&Timer); //使能定时器中断

	return XST_SUCCESS;
}

int timer_init(void)
{
	int Status;
	//私有定时器初始化
	XScuTimer_Config *timer_cfg_ptr;
	timer_cfg_ptr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
	if (timer_cfg_ptr == NULL)
	{
		return XST_FAILURE;
	}
	Status = XScuTimer_CfgInitialize(&Timer, timer_cfg_ptr,timer_cfg_ptr->BaseAddr);
	if (Status != XST_SUCCESS)  //判断是否初始化成功
	{
		return XST_FAILURE;
	}

	XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); // 加载计数周期
	XScuTimer_EnableAutoReload(&Timer); // 设置自动装载模式
	return XST_SUCCESS;
}

int main(void)
{
	xil_printf("My  test!\r\n");

	//led初始化
	int Status,key;
	int lval = 0x1,rval = 0x1;
	Status = led_init();
	if (Status != XST_SUCCESS)
	{
		xil_printf("LEDs init failed!\r\n");
	}

	//key初始化
	Status = key_init();
	if (Status != XST_SUCCESS)
	{
		xil_printf("Key init failed!\r\n");
	}

	//定时器初始化
	Status = timer_init();
	if (Status != XST_SUCCESS)
	{
		xil_printf("timer init failed!\r\n");
	}
	//中断初始化
	Status = interrupt_init(); //一定要先定时器初始化后再中断初始化
	if (Status != XST_SUCCESS)
	{
		xil_printf("interrupt init failed!\r\n");
	}

	XScuTimer_Start(&Timer); //启动定时器

	while(1)
	{
		if(key_down ==1) //右移
		{
			key = 1;
		}
		else if(key_down ==2)
		{
			key = 2;
		}

		if(key == 1)
		{
			if(delay_cnt >= 10) //1s
			{
				//将按键的状态写入LED
				XGpio_DiscreteWrite(&Axi_Gpio, led_channel, rval);
				rval = rval >>1;
				if(rval < 0x1)
				{
					rval = 0x8;
				}
				delay_cnt = 0;
			}
		}
		else if(key == 2)
		{
			if(delay_cnt >= 10)
			{
				//将按键的状态写入LED
				XGpio_DiscreteWrite(&Axi_Gpio, led_channel, lval);
				lval = lval <<1;
				if(lval > 0x8)
				{
					lval = 0x1;
				}
				delay_cnt = 0;
			}
		}
	}

	return 0;
}

你可能感兴趣的:(ZYNQ,fpga开发)