Xilinx ZYNQ 7000+Vivado2015.2系列(十五)AXI Timer 用户定时器中断控制LED
前面的中断学习中我们学了按键,GPIO,Timer,是时候把它们整合到一起了。
今天我们混合使用PS/PL部分的资源,建立一个比较大的系统。
板子:zc702。
实现功能如下:
1.通过串口打印信息询问你要按SW5还是SW7;
2.当正确的按键被按下,定时器启动,关闭led DS23;
3.当定时器溢出后触发中断,开启DS23,系统回到1。
我们用一个AXI GPIO连接到SW5,EMIO连接SW7,MIO连接DS23(固定连接),定时器也使用PL的AXI Timer。
AXI Timer的主要特性:
硬件系统
1.添加zynq核,AXI GPIO,AXI Timer
2.打开zynq核的配置,使能UART 1,使能GPIO MIO,添加1 bit的EMIO GPIO,使能PL-PS中断IRQ_F2P
3.AXI GPIO宽度设为1
4.点击自动连接,所有都可以自动连接
5.将zynq的IRQ_F2P[0:0] 连接到AXI Timer的interrupt
,点击zynq的GPIO\_0
右键Make External
,点击输出的引脚可以修改信号名称
生成顶层文件:
添加约束
连接到两个按键,AXI GPIO连接到SW5,EMIO 连接到SW7
set_property PACKAGE_PIN G19 [get_ports {gpio_sw_tri_i[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_sw_tri_i[0]}]
set_property PACKAGE_PIN F19 [get_ports {gpio_0_tri_io[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_0_tri_io[0]}]
另外,LED DS 23连接在MIO 10:
生成比特文件,打开SDK。
软件部分
代码来自于Xilinx官方。
#include <stdio.h>
#include "platform.h"
#include "xil_types.h"
#include "xgpio.h"
#include "xtmrctr.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "xil_io.h"
#include "xil_exception.h"
#include "xscugic.h"
static XGpioPs psGpioInstancePtr;
extern XGpioPs_Config XGpioPs_ConfigTable[XPAR_XGPIOPS_NUM_INSTANCES];
static int iPinNumber = 10;
XScuGic InterruptController; /* Instance of the Interrupt Controller */
static XScuGic_Config *GicConfig;/* The configuration parameters of the
controller */
static int InterruptFlag;
//void print(char *str);
extern char inbyte(void);
void Timer_InterruptHandler(void *data, u8 TmrCtrNumber)
{
print(" Inside Timer ISR \n \r ");
XTmrCtr_Stop(data,TmrCtrNumber);
// PS GPIO Writting
print("LED 'DS23' Turned ON \r\n");
XGpioPs_WritePin(&psGpioInstancePtr,iPinNumber,1);
XTmrCtr_Reset(data,TmrCtrNumber);
print(" Timer ISR Exit\n \n \r");
InterruptFlag = 1;
}
int SetUpInterruptSystem(XScuGic *XScuGicInstancePtr)
{
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the ARM processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler,
XScuGicInstancePtr);
/*
* Enable interrupts in the ARM
*/
Xil_ExceptionEnable();
return XST_SUCCESS;
}
int ScuGicInterrupt_Init(u16 DeviceId,XTmrCtr *TimerInstancePtr)
{
int Status;
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
* */
GicConfig = XScuGic_LookupConfig(DeviceId);
if (NULL == GicConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(&InterruptController, GicConfig,
GicConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Setup the Interrupt System
* */
Status = SetUpInterruptSystem(&InterruptController);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Connect a device driver handler that will be called when an
* interrupt for the device occurs, the device driver handler performs
* the specific interrupt processing for the device
*/
Status = XScuGic_Connect(&InterruptController,
XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR,
(Xil_ExceptionHandler)XTmrCtr_InterruptHandler,
(void *)TimerInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Enable the interrupt for the device and then cause (simulate) an
* interrupt so the handlers will be called
*/
XScuGic_Enable(&InterruptController, XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR);
return XST_SUCCESS;
}
int main()
{
static XGpio GPIOInstance_Ptr;
XGpioPs_Config*GpioConfigPtr;
XTmrCtr TimerInstancePtr;
int xStatus;
u32 Readstatus=0,OldReadStatus=0;
int iPinNumberEMIO = 54;
u32 uPinDirectionEMIO = 0x0;
u32 uPinDirection = 0x1;
int exit_flag,choice,internal_choice;
init_platform();
xStatus = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID);
if(XST_SUCCESS != xStatus)
print("GPIO INIT FAILED\n\r");
XGpio_SetDataDirection(&GPIOInstance_Ptr, 1,1);//AXI GPIO 1表示输入
xStatus = XTmrCtr_Initialize(&TimerInstancePtr,XPAR_AXI_TIMER_0_DEVICE_ID);
if(XST_SUCCESS != xStatus)
print("TIMER INIT FAILED \n\r");
XTmrCtr_SetHandler(&TimerInstancePtr,
Timer_InterruptHandler,
&TimerInstancePtr);
XTmrCtr_SetResetValue(&TimerInstancePtr,
0, //Change with generic value
0xff000000);
XTmrCtr_SetOptions(&TimerInstancePtr,
XPAR_AXI_TIMER_0_DEVICE_ID,
(XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION ));//Setting timer Option (Interrupt Mode And Auto Reload )
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);//MIO上的DS23 1代表输出
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);//1 for Enabling Output Enable
XGpioPs_SetDirectionPin(&psGpioInstancePtr,
iPinNumberEMIO,uPinDirectionEMIO); //EMIO上的SW7 0代表输入
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumberEMIO,0); //0 for Disabling Output Enable
xStatus=ScuGicInterrupt_Init(XPAR_PS7_SCUGIC_0_DEVICE_ID,&TimerInstancePtr);
if(XST_SUCCESS != xStatus)
//User selection procedure to select and execute tests
exit_flag = 0;
while(exit_flag != 1)
{
print("------- Menu Starts -------\r\n");
print("Press '1' to use NORMAL GPIO as an input (SW5 switch)\r\n");
print("Press '2' to use EMIO as an input (SW7 switch)\r\n");
print("Press any other key to Exit\r\n");
choice = inbyte();//等待串口输入
printf("Selection : %c \r\n",choice);
internal_choice = '1';
switch(choice)
{
// Use case for AXI GPIO
case '1':
exit_flag = 0;
print("Press Switch 'SW5' push button on board \r\n");
print(" \r\n");
while(internal_choice != '0')
{
Readstatus = XGpio_DiscreteRead(&GPIOInstance_Ptr, 1);
if(1== Readstatus && 0 == OldReadStatus )
{
print("SW5 PUSH Button pressed \n\r");
print("LED 'DS23' Turned OFF \r\n");
XGpioPs_WritePin(&psGpioInstancePtr,iPinNumber,0);
//Start Timer
XTmrCtr_Start(&TimerInstancePtr,0);
print("timer start \n\r");
//Wait For interrupt;
print("Wait for the Timer interrupt to tigger \r\n");
print(" \r\n");
while(InterruptFlag != 1);
InterruptFlag = 0;
print("Press '0' to go to Main Menu \n\r ");
print("Press any other key to remain in AXI GPIO Test \n\r ");
internal_choice = inbyte();
printf("Select = %c \r\n",internal_choice);
if(internal_choice != '0')
{
print("Press Switch 'SW5' push button on board \r\n");
}
}
OldReadStatus = Readstatus;
}
print(" \r\n");
print(" \r\n");
break;
case '2' :
//Use case for PS GPIO
exit_flag = 0;
print("Press Switch 'SW7' push button on board \r\n");
print(" \r\n");
while(internal_choice != '0')
{
Readstatus = XGpioPs_ReadPin(&psGpioInstancePtr,
iPinNumberEMIO);
if(1== Readstatus && 0 == OldReadStatus )
{
print("SW7 PUSH Button pressed \n\r");
print("LED 'DS23' Turned OFF \r\n");
XGpioPs_WritePin(&psGpioInstancePtr,iPinNumber,0);
//Start Timer
XTmrCtr_Start(&TimerInstancePtr,0);
print("timer start \n\r");
//Wait For interrupt;
print("Wait for the Timer interrupt to tigger \r\n");
print(" \r\n");
while(InterruptFlag != 1);
InterruptFlag = 0;
print("Press '0' to go to Main Menu \n\r ");
print("Press any other key to remain in EMIO Test \n\r ");
internal_choice = inbyte();
printf("Select = %c \r\n",internal_choice);
if(internal_choice != '0')
{
print("Press Switch 'SW7' push button on board \r\n");
}
}
OldReadStatus = Readstatus;
}
print(" \r\n");
print(" \r\n");
break;
default :
exit_flag = 1;
break;
}
}
print("BYE \r\n");
cleanup_platform();
return 0;
}
从main函数开始:
定义三个实例:
AXI GPIO实例:
XGpio
AXI Timer实例:
XTmrCtr
前面还定义了EMIO GPIO实例:
XGpioPs
(EMIO Pin脚是54,DS 23 Pin脚是10)
AXI GPIO初始化:
XGpio\_Initialize
AXI GPIO设置数据方向:
XGpio\_SetDataDirection
1表示输入,这个IO是接SW5的
AXI Timer初始化:
XTmrCtr\_Initialize
设置AXI Timer中断处理器:
XTmrCtr\_SetHandler
这个处理器就是我们自定义的功能Timer_InterruptHandler(),
中断发生之后去干嘛,这里我们实现的是点亮DS 23
设置AXI Timer初始值:
XTmrCtr\_SetResetValue
定时器功能设置:
XTmrCtr\_SetOptions
XTC\_INT\_MODE\_OPTIONEnables the timer counter interrupt output.
XTC\_AUTO\_RELOAD\_OPTIONconfigures the timer counter to reload from the compare value
PS的GPIO初始化:XGpioPs_LookupConfig XGpioPs_CfgInitialize
设置IO的数据方向:XGpioPs_SetDirectionPin //MIO上的DS23 1代表输出 | EMIO上的SW7 0代表输入
XGpioPs_SetOutputEnablePin 1 for Enabling Output Enable 0 for Disabling Output Enable
GIC初始化:封装在ScuGicInterrupt_Init()函数
XScuGic\_LookupConfig\-->XScuGic\_CfgInitialize
while循环:
向控制台输入一个值,利用inbyte()接收,
利用case选择是使用SW5还SW7触发定时器,
触发后开启定时器,中断发生点亮DS 23。
当标志位exit_flag不等于1持续这个操作,
没有进入任何case分支,进入default,
默认里面设置exit_flag=1,退出while,程序就结束了。
注:我在测试的时候,inbyte()会时不时抽风,需要重启应用程序,有待考究。