ZYNQ中断例程

GPIO 中断系统初始化流程:
第一步:初始化 cpu 的异常处理功能
第二步:初始化中断控制器
第三步:向 CPU 注册异常处理回调函数;
第四步:将中断控制器中的对应中断 ID 的中断与中断控制器相连接
第五步:设置 GPIO 的中断类型,比如高电平中断、低电平中断、上升沿中断、
下降沿中断等。
第六步:设置 GPIO 中断回调函数,这里设置的回调函数是用于用户使用的。
第七步:使能 GPIO 的对应 PIN 的中断
第八步:使能中断控制器
第九步:使能异常处理功能
注意:AMP模式下对来自PL端的中断要用XScuGic_InterruptMaptoCpu()函数将CPU和中断对应起来
GIC在ZYNQ中只有一个,当两个CPU都需要中断时,要编程确定中断初始化的顺序

1.PS端GPIO中断

/*
 	 使用中断:用PS端口的GPIO操控PS端口的LED
*/
#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "sleep.h"
#include "xscugic.h"
//器件ID
#define GPIO_DEVICE_ID  	XPAR_XGPIOPS_0_DEVICE_ID
#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
//GPIO的中断号   52
#define GPIO_INTERRUPT_ID	XPAR_XGPIOPS_0_INTR

//核心板上PS端LED
#define	MIO_0_LED			0
//核心板上PS端按键
#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(){
	printf("GPIO INTERRUPT TEST!\n\r");
	u32 led_value = 0;

	//根据器件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_12_KEY, 0);

	//设置输出使能(0关闭 1打开)
	XGpioPs_SetOutputEnablePin(&Gpio, MIO_0_LED, 1);

	//设置中断系统
	SetupInterruptSystem(&Intc, &Gpio, GPIO_INTERRUPT_ID);

	//写数据到GPIO
	while(1){
		if(key_press){
			XGpioPs_IntrClearPin(&Gpio, MIO_12_KEY);
			led_value = ~led_value;
			key_press = 0;
			//清除之前的中断状态寄存器(int_state)

			XGpioPs_WritePin(&Gpio,MIO_0_LED, led_value);
			//延时消抖
			usleep(10000);

			XGpioPs_IntrEnablePin(&Gpio, MIO_12_KEY);//打开MIO的中断使能信号
		}
	}
	return 0;
}

void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,u16 GpioIntrId)
{


	//查找器件配置信息并进行初始化
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);

	Xil_ExceptionInit();//初始化ARM处理器异常句柄
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				GicInstancePtr);//给IRQ注册异常处理程序
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);//使能处理器的中断

	XScuGic_Connect(GicInstancePtr, GpioIntrId,
				(Xil_ExceptionHandler)IntrHandler,
				(void *)Gpio);//关联中断处理函数,当中断发生时,程序执行第三个输出变量函数
	XScuGic_Enable(GicInstancePtr, GpioIntrId);//为GPIO器件使能中断

	XGpioPs_SetIntrTypePin(Gpio, MIO_12_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);//设置指定引脚的中断触发类型
	XGpioPs_IntrEnablePin(Gpio, MIO_12_KEY);//打开MIO的中断使能信号
}

void IntrHandler(){
	printf("interrupt detect!\n\r");
	key_press = 1;
	XGpioPs_IntrDisablePin(&Gpio, MIO_12_KEY);//关闭中断
}

PL端GPIO触发

/*
 * GPIO中断实验
 * */
#include 
#include "xil_printf.h"
#include "xgpiops.h"
#include "xparameters.h"
#include "sleep.h"
#include "xscugic.h"

#define GPIO_DEVICE_ID  	XPAR_XGPIOPS_0_DEVICE_ID 	//GPIO设备ID
#define INTC_DEVICE_ID		XPAR_PS7_SCUGIC_0_DEVICE_ID	//中断ID

#define GPIO_INTR_ID 		XPAR_XGPIOPS_0_INTR			//GPIO的中断序列号

#define SW_BANK_ID			XGPIOPS_BANK2

//EMIO的引脚号
#define SW0 	54						//EMIO的54引脚
#define LED0	55						//EMIO的55引脚
#define LED1	56						//EMIO的56引脚


static XGpioPs 			GpioPs;			//GPIO实例
static XGpioPs_Config*	GpioCfgPtr;		//GPIO初始化指针
static XScuGic 			GicPs; 			//中断控制器实例
static XScuGic_Config*  GicPsPtr;		//中断控制器指针

int initGpio();
int setup_Interrupt();
void intrHandler(void * CallBackRef,u32 Bank,u32 status);
void breath_led();

int main(){
	initGpio();
	print("GPIO 初始化成功!\n");
	setup_Interrupt();
	print("GPIO interrupt 初始化成功!\n");
	while(1){

	}
	return 0;
}

int initGpio(){
	int status;
	GpioCfgPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	status = XGpioPs_CfgInitialize(&GpioPs,GpioCfgPtr,GpioCfgPtr->BaseAddr);
	if(status != XST_SUCCESS){
		return status;
	}
	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
	XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);

	XGpioPs_SetDirectionPin(&GpioPs,SW0,0x00);
	XGpioPs_SetOutputEnablePin(&GpioPs,SW0,0x00);
	return XST_SUCCESS;
}

int setup_Interrupt(){
	int status;
//1.初始化异常处理函数
	Xil_ExceptionInit();
//2.初始化中断设备控制器
	GicPsPtr = XScuGic_LookupConfig(INTC_DEVICE_ID);
	status = XScuGic_CfgInitialize(&GicPs,GicPsPtr,GicPsPtr->CpuBaseAddress);
	if(status != XST_SUCCESS){
		return status;
	}
//3.注册异常处理函数(中断异常ID,异常处理函数,向异常处理函数里面传入的参数)
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs);
//4.连接中断处理函数(中断控制器的实例,GPIO的中断ID,中断处理函数,一般是被连接设备的指针)
	status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs);
	if(status != XST_SUCCESS){
			return status;
	}
/*5.设置中断类型(驱动实例,GPIO所在的bankID,32位的掩码对应bank的32个引脚(0电平敏感1边沿敏感),
 * 如果设置为电平有效则该次出设置高电平还是低电平有效),如果设置为边沿触发则此处设置是单边沿还是双边沿*/
	XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0x00,XGPIOPS_IRQ_TYPE_EDGE_RISING);
//6.设置GPIO回调函数,产生中断时进入此函数
	XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs,intrHandler);
//7.使能对应PIN的中断
	XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(SW0-54));
//8.使能中断控制器中GPIO的中断
	XScuGic_Enable(&GicPs,GPIO_INTR_ID);
//9.使能异常处理
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
	return	XST_SUCCESS;
}

void intrHandler(void * CallBackRef,u32 Bank,u32 status){
	XGpioPs * GpioPtr;
	GpioPtr = (XGpioPs *)CallBackRef;
	u32 intrstatus;
	//判断中断是否由指定引脚产生,是则继续中断处理函数
	intrstatus = XGpioPs_IntrGetStatusPin(GpioPtr,SW0);
	if(intrstatus == 1){
		//清除中断标志,关闭中断引脚防止二次进入中断
		XGpioPs_IntrClearPin(GpioPtr,SW0);
		XGpioPs_IntrDisablePin(GpioPtr,SW0);
		u32 readSW;
		//按键消抖
		int cnt;
		while(cnt <100){
			readSW = XGpioPs_ReadPin(GpioPtr,SW0);
			if(readSW == 1){
				cnt ++;
			}
			else{
				cnt = 0;
			}
			usleep(1000);
		}
		readSW = XGpioPs_ReadPin(GpioPtr,SW0);
		printf("readSW = %d\n",(int)readSW);
		if(readSW == 0){
			XGpioPs_WritePin(GpioPtr,LED1,0x01);
		}
	}
	//打开中断使能
	XGpioPs_IntrEnablePin(GpioPtr,SW0);
}

void breath_led(){
		initGpio();
		int i,j;
		int led = 1;
		while(1){
			for(i=0;i<1000;i++){
				for(i=0;i<1000;i++){
					usleep(1);
					if(j<i){
						XGpioPs_WritePin(&GpioPs,LED0,led);
					}
					else{
						XGpioPs_WritePin(&GpioPs,LED0,~led);
					}
				}
			}
		}
}

PL端EMIO中断以及串口中断


#include 
#include "platform.h"
#include "xil_printf.h"
#include "AXI_reglist.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xuartps.h"
#include "sleep.h"

#define GPIO_DEV_ID 		XPAR_PS7_GPIO_0_DEVICE_ID
#define GPIO_INTERRUPT_ID	XPS_GPIO_INT_ID 		//来自FPGA的EMIO中断
#define GIC_ID  			XPAR_PS7_SCUGIC_0_DEVICE_ID
#define UART1_DEV_ID 		XPAR_PS7_UART_1_DEVICE_ID
#define UART1INTR  			XPAR_PS7_UART_1_INTR

#define 	EMIO_CYCLE_CNT_VALID 	54 	//接收FPGA端的周期计数有效信号引脚  高电平有效
#define 	EMIO_DELAY_CTRL 		55 	//发送FPGA端的延时控制字有效信号
#define 	EMIO_DIV_CNT_VALID 		56 	//发送给FPGA的分频有效信号  		高电平有效
#define 	EMIO_BANK_ID 			2 	//EMIO的bank id
#define 	UART_SEND_DELAY 		4 	//串口发送间隔
#define 	DELAY_CTRL 				0 	//延时控制字

static XGpioPs GpioPs;
static XGpioPs_Config * GpioCnfPtr;
static XScuGic ScuGic;
static XScuGic_Config * ScuGicCfgPtr;
static XUartPs Uart1;
static XUartPs_Config * Uart1CfgPtr;

void initGpio(); 	//初始化并设置管脚的输入输出
void uart1Iint(); 	//初始化uart1
void initSwIntr(); 	//设置中断并关联中断函数

void uart1Handler(void *CallBackRef); 	//串口接收中断
void f2pIntr0Handler(void * CallBackRef); 	//FPGA端的EMIO中断
u32 uart_send_cnt = 0	;
u32 delay_ctrl 	= 0 ;
int main()
{
	//配置延时控制字的初始值
	uart_send_cnt = 0;
	WriteDivCnt(10000);
	//GPIO初始化
	initGpio();
    WriteDelayCtrl(DELAY_CTRL);
    XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,0);
    XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,1);
    XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,0);
	//串口外设初始化
	uart1Iint();
    XGpioPs_WritePin(&GpioPs,EMIO_DIV_CNT_VALID,0);
    XGpioPs_WritePin(&GpioPs,EMIO_DIV_CNT_VALID,1);
    XGpioPs_WritePin(&GpioPs,EMIO_DIV_CNT_VALID,0);
    sleep(1);
	//中断初始化
	initSwIntr();
	while(1){

	}
    return 0;
}

//initial gpio func
void initGpio(){
	GpioCnfPtr = XGpioPs_LookupConfig(GPIO_DEV_ID);
	XGpioPs_CfgInitialize(&GpioPs,GpioCnfPtr,GpioCnfPtr->BaseAddr);
	//设置两个管脚的输入输出模式 0输入  1输出
	XGpioPs_SetDirectionPin(&GpioPs,EMIO_CYCLE_CNT_VALID,0x00);
	XGpioPs_SetDirectionPin(&GpioPs,EMIO_DELAY_CTRL,0x01);
	XGpioPs_SetDirectionPin(&GpioPs,EMIO_DIV_CNT_VALID,0x01);
	//设置管脚的输入输出使能
	XGpioPs_SetOutputEnablePin(&GpioPs,EMIO_DIV_CNT_VALID,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,EMIO_DELAY_CTRL,0x01);
}

void uart1Iint(){
	u32 intrMask=0;
	Uart1CfgPtr = XUartPs_LookupConfig(UART1_DEV_ID);
	XUartPs_CfgInitialize(&Uart1,Uart1CfgPtr,Uart1CfgPtr->BaseAddress);

	//设置uart工作模式
	XUartPs_SetBaudRate(&Uart1,115200);
	//设置接收FIFO的触发阈值
    XUartPs_SetFifoThreshold(&Uart1, 2);
	XUartPs_SetOperMode(&Uart1,XUARTPS_OPER_MODE_NORMAL);
	intrMask =XUARTPS_IXR_RXOVR;
	XUartPs_SetInterruptMask(&Uart1,intrMask);
}

//uart recv interrupt
void uart1Handler(void *CallBackRef){
    XUartPs *uart_instance_ptr = (XUartPs *) CallBackRef;
    u32 rec_data_L = 0 ;
    u32 rec_data_H = 0 ;
    u32 rec_data = 0;
    u32 isr_status ;                           //中断状态标志

    //读取中断ID寄存器,判断触发的是哪种中断
    isr_status = XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress,
                   XUARTPS_IMR_OFFSET);
    isr_status &= XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress,
                   XUARTPS_ISR_OFFSET);

    //判断中断标志位RxFIFO是否触发
    if (isr_status & (u32)XUARTPS_IXR_RXOVR){
        rec_data_L = XUartPs_RecvByte(XPAR_PS7_UART_1_BASEADDR);
        rec_data_H = XUartPs_RecvByte(XPAR_PS7_UART_1_BASEADDR);
        rec_data = rec_data_L | (rec_data_H<<8);
        WriteDelayCtrl(rec_data);
        XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,0);
        XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,1);
        XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,0);
        //清除中断标志
        XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress,
                XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR) ;
    }
}

//initial software interrept
void initSwIntr(){
	Xil_ExceptionInit();
	ScuGicCfgPtr = XScuGic_LookupConfig(GIC_ID);
	XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);

	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
	//connect uart1 interrupt
	XScuGic_Connect(&ScuGic,UART1INTR,(Xil_ExceptionHandler)uart1Handler,&Uart1);
	XScuGic_SetPriorityTriggerType(&ScuGic , UART1INTR , 0xA0 ,0x01);
	XScuGic_Enable(&ScuGic,UART1INTR);

	//connect fpga interrupt
	XScuGic_Connect(&ScuGic,GPIO_INTERRUPT_ID,(Xil_ExceptionHandler)f2pIntr0Handler,&GpioPs);
	XGpioPs_SetIntrType(&GpioPs,XGPIOPS_BANK2,1<<(EMIO_CYCLE_CNT_VALID-54),1<<(EMIO_CYCLE_CNT_VALID-54),0);
	//打开中断使能,对IO管脚配置
	XGpioPs_IntrEnablePin(&GpioPs, EMIO_CYCLE_CNT_VALID);
	XScuGic_Enable(&ScuGic,GPIO_INTERRUPT_ID);
	XScuGic_SetPriorityTriggerType(&ScuGic , GPIO_INTERRUPT_ID , 0xB0 ,0x01);
	Xil_ExceptionEnable();
}

void f2pIntr0Handler(void * CallBackRef){
	XGpioPs *GpioPtr;
	GpioPtr = (XGpioPs *)CallBackRef;
	u32 intrstatus;
	u32 cyclecnt = 0;
	intrstatus = XGpioPs_IntrGetStatusPin(GpioPtr,EMIO_CYCLE_CNT_VALID);
	if(intrstatus == 1){
		if(delay_ctrl < 1024){
			if(uart_send_cnt == UART_SEND_DELAY){
				uart_send_cnt = 0;
			}
			if(uart_send_cnt == 0){
			cyclecnt = ReadCycleCnt();
			//高位在前,低位在后
				XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR,(cyclecnt  >>24)& 0xff);
				XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR,(cyclecnt  >>16)& 0xff);
				XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR,(cyclecnt  >> 8)& 0xff);
				XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR,(cyclecnt  >> 0)& 0xff);

				WriteDelayCtrl(delay_ctrl);
				XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,0);
				XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,1);
				XGpioPs_WritePin(&GpioPs,EMIO_DELAY_CTRL,0);
			}
			if(uart_send_cnt == 1){
				delay_ctrl = delay_ctrl + 1;
			}
			uart_send_cnt 	= 	uart_send_cnt + 1;
		}
		XGpioPs_IntrEnablePin(GpioPtr,EMIO_CYCLE_CNT_VALID);
	}
}

你可能感兴趣的:(嵌入式硬件,fpga开发,1024程序员节)