【ZYNQ入门】第二篇、ZYNQ的中断系统及常用中断初始化程序

目录

第一部分、Zynq的中断系统及架构

1、中断系统结构

第二部分、各类中断对应的ID

1、软中断SGI的ID

2、私有中断PPI的ID

3、共享SPI的ID(最常用)

第三部分、常用中断初始化程序

1、UART0中断配置代码(SPI)

1.1、串口的工作模式

1.1.1、Normal Mode模式

1.1.2、Automatic Echo Mode模式

1.1.4、Remote Loopback Mode模式

1.2、串口初始化

1.3、中断初始化代码        

2、PL中断PS的配置代码(SPI)

2.1、硬中断的基础知识

2.2、硬中断实验内容

2.3、中断初始化代码如下

3、GPIO中断配置代码

4、AMP模式下软中断配置代码

4.1、SGI中断配置要点

4.2、AMP中断配置完整代码


第一部分、Zynq的中断系统及架构

        刚入手ZYNQ,对SDK的编程风格真的是不太习惯,不过适应一段时间后,会发现SDK还是挺好用的。这篇文章,主要是将最近学的中断系统进行一次整理,让自己的遗忘速度稍微变慢一点。

 1、中断系统结构

        想要完全认识ZYNQ的中断,下面这张图真的要非常熟悉。主干是通用中断控制器GIC)。GIC的左边包含三部分,分别是软中断SGI私有中断PPI以及共享中断SPI。最常用的就是共享中断,只要把其中一种中断的初始化步骤弄清楚,那么其它理解起来就会变很简单。

第二部分、各类中断对应的ID

        每个中断都对应有自己的ID,这里ID的作用主要是在初始化中断的时候,为某些中断初始化的入口参数。目的是告诉中断系统我用的哪一个中断,名字告诉你了,你别搞错了。

1、软中断SGI的ID

2、私有中断PPI的ID

3、共享SPI的ID(最常用)

第三部分、常用中断初始化程序

        中断的程序流程如下图所示,其中前四步为固定流程,因为这四步主要是用来初始化通用中断控制器,也就是第一张图的主干部分的初始化。因为无论是SGI、PPI还是SPI,这三个中断类型都连接着GIC,因此前四步初始化的便可以固定下来。

        前四步的配置代码如下:

    /*step1、初始化异常处理*/
    Xil_ExceptionInit();
    /*step2、初始化中断控制器*/
    ScuGicCfgPtr = XScuGic_LookupConfig(GIC_DEV_ID);
    status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
    if(status != XST_SUCCESS)
    {
        printf("Initial Gic Failed!");
        return status;
    }
    /*step3、注册异常处理回调函数*/
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
    /*step4、异常处理使能*/
    Xil_ExceptionEnable();

1、UART0中断配置代码(SPI)

1.1、串口的工作模式

        Zynq内的串口一共有四种工作模式,分别是普通模式自动回声模式本地回环模式远程回环模式

1.1.1、Normal Mode模式

        用于标准的UART操作模式。正常情况下都是用的这个模式。

1.1.2、Automatic Echo Mode模式

        这个模式下RXD引脚接收的数据,会自动路由到TXD引脚上。一边接收数据一边发送数据。

1.1.3、Local Loopback Mode模式

        本地回环模式,相当于自发自收,数据不经过TXD和RXD这两个管脚。

1.1.4、Remote Loopback Mode模式

        这个模式下,CPU在TXD上不能发送任何内容,在RXD上不能接收任何内容。

1.2、串口初始化

        配置串口中断之前,必须要对串口进行初始化,然后再去配置串口中断。初始化步骤包括:连接串口的ID、设置波特率、设置串口工作模式、设置中断间隔时间、启动中断监听。代码如下:

//串口初始化函数
void Uart0_Init()
{
    int state = 0;
    //寻找ID,初始化设备
    UartPsCfgPtr = XUartPs_LookupConfig(XPAR_PS7_UART_0_DEVICE_ID);//Device id
    state = XUartPs_CfgInitialize(&Uart0,UartPsCfgPtr,UartPsCfgPtr->BaseAddress);
    if(state != XST_SUCCESS)
    {
        printf("Uart initial failed");
        return state;
    }
    //设置波特率(应该与硬件相关,在设置硬件的时候就设置串口为115200)
    XUartPs_SetBaudRate(&Uart0,115200);
    //设置串口的工作模式
    XUartPs_SetOperMode(&Uart0,XUARTPS_OPER_MODE_NORMAL);//设置为普通模式
    //设置中断间隔时间(由于初始化中断时,设置为时间间隔中断)
    XUartPs_SetRecvTimeout(&Uart0,8);//8*4*1/115200 间隔这么久没有数据,就算中断
    //启动监听
    XUartPs_Recv(&Uart0,uart_rx_data,32);// 启动监听,设置接收buf的预计的字节数
}

        需要注意的就是串口中断触发方式,串口的触发方式有多种,本次实验选用的是接收时间间隔中断,当超过一段时间RXD没有接收到数据,便产生中断。具体参照xuartps_hw.h头文件。

#define XUARTPS_IXR_RBRK	0x00002000U /**< Rx FIFO break detect interrupt */
#define XUARTPS_IXR_TOVR	0x00001000U /**< Tx FIFO Overflow interrupt */
#define XUARTPS_IXR_TNFUL	0x00000800U /**< Tx FIFO Nearly Full interrupt */
#define XUARTPS_IXR_TTRIG	0x00000400U /**< Tx Trig interrupt */
#define XUARTPS_IXR_DMS		0x00000200U /**< Modem status change interrupt */
#define XUARTPS_IXR_TOUT	0x00000100U /**< Timeout error interrupt */
#define XUARTPS_IXR_PARITY 	0x00000080U /**< Parity error interrupt */
#define XUARTPS_IXR_FRAMING	0x00000040U /**< Framing error interrupt */
#define XUARTPS_IXR_OVER	0x00000020U /**< Overrun error interrupt */
#define XUARTPS_IXR_TXFULL 	0x00000010U /**< TX FIFO full interrupt. */
#define XUARTPS_IXR_TXEMPTY	0x00000008U /**< TX FIFO empty interrupt. */
#define XUARTPS_IXR_RXFULL 	0x00000004U /**< RX FIFO full interrupt. */
#define XUARTPS_IXR_RXEMPTY	0x00000002U /**< RX FIFO empty interrupt. */
#define XUARTPS_IXR_RXOVR  	0x00000001U /**< RX FIFO trigger interrupt. */
#define XUARTPS_IXR_MASK	0x00003FFFU /**< Valid bit mask */

1.3、中断初始化代码        

        串口中断初始化剩下的步骤如下

        main.c代码如下,需要注意的是串口初始化要放在中断初始化之前,不然程序会卡死,原因:串口的初始化中,包含了寻找串口的设备ID,和初始化变量赋值的过程。

#include <stdio.h>      //printf函数
#include "xparameters.h"
#include "xil_printf.h" //printf打印函数文件
#include "sleep.h"      //延迟头文件
#include "xscugic.h"    //通用中断控制器头文件
#include "xuartps.h"    //串口中断的处理函数
#include "xuartps_hw.h" //串口中断模式设置


/*重定义*/
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID//gic device id
#define UART0_INTR_ID XPAR_XUARTPS_0_INTR     //UART0 interrupt id,not device id,the id from "xparameters_ps.h"

/*必要变量定义*/
static XScuGic ScuGic;//初始化中断控制器变量
static XScuGic_Config * ScuGicCfgPtr;

static XUartPs Uart0;//串口初始化中断控制器
static XUartPs_Config * UartPsCfgPtr;

/*全局变量*/
unsigned char uart_rx_data[32];//存储串口接收的数据

//函数初始化
int Init_Gic(void);//通用中断控制器初始化
void Uart0_Handler(void *CallBackRef, u32 Event,u32 EventData);//串口中断处理函数
void Uart0_Init();//串口初始化函数(包含中断模式)


int main()
{
    int status = 0;
    Uart0_Init();//串口初始化放到中断控制器前面
    status = Init_Gic();
    if(status != XST_SUCCESS){
        return status;
    }

    while(1)
    {

    }
    return 0;
}


//串口中断处理函数
void Uart0_Handler(void *CallBackRef, u32 Event,u32 EventData)
{
    u32 revcnt = 0;
    if(Event = XUARTPS_IXR_TOUT)//判断触发中断的事件是哪一个
    {
        revcnt = EventData;
        if(revcnt == 8 && uart_rx_data[0] == 0x55 && uart_rx_data[1] == 0x55)
        {
            printf("frame1\n\r");
        }
        printf("串口中断成功,frame1\n\r");
        XUartPs_Recv(&Uart0,uart_rx_data,32);// 启动监听,设置接收buf的预计的字节数
    }

}


//串口初始化函数
void Uart0_Init()
{
    int state = 0;
    //寻找ID,初始化设备
    UartPsCfgPtr = XUartPs_LookupConfig(XPAR_PS7_UART_0_DEVICE_ID);//Device id
    state = XUartPs_CfgInitialize(&Uart0,UartPsCfgPtr,UartPsCfgPtr->BaseAddress);
    if(state != XST_SUCCESS)
    {
        printf("Uart initial failed");
        return state;
    }
    //设置波特率(应该与硬件相关,在设置硬件的时候就设置串口为115200)
    XUartPs_SetBaudRate(&Uart0,115200);
    //设置串口的工作模式
    XUartPs_SetOperMode(&Uart0,XUARTPS_OPER_MODE_NORMAL);//设置为普通模式
    //设置中断间隔时间
    XUartPs_SetRecvTimeout(&Uart0,8);//8*4*1/115200 间隔这么久没有数据,就算中断
    //启动监听
    XUartPs_Recv(&Uart0,uart_rx_data,32);// 启动监听,设置接收buf的预计的字节数
}
//初始化通用中断控制器
int Init_Gic(void)
{
    int status;
    //step1、初始化异常处理
    Xil_ExceptionInit();
    //step2、初始化中断控制器
    ScuGicCfgPtr = XScuGic_LookupConfig(GIC_DEV_ID);
    status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
    if(status != XST_SUCCESS)
    {
        printf("Initial Gic Failed!");
        return status;
    }

    //step3、注册异常处理回调函数
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
    //step4、异常处理使能
    Xil_ExceptionEnable();

    /******配置区域*******/
    //step5、在gic中使能uart0中断
    XScuGic_Enable(&ScuGic,UART0_INTR_ID);
    //step6、在gic中连接uart0对应的中断ID
    status = XScuGic_Connect(&ScuGic,UART0_INTR_ID,(Xil_ExceptionHandler)XUartPs_InterruptHandler,&Uart0);
    if(status != XST_SUCCESS)
    {
        printf("Connect Gic Failed!");
        return status;
    }
    //step7、设置uart0中断处理函数
    XUartPs_SetHandler(&Uart0,(XUartPs_Handler)Uart0_Handler,&Uart0);
    //step8、设置uart0中断触发方式(这里为间隔时间中断)
    XUartPs_SetInterruptMask(&Uart0,XUARTPS_IXR_TOUT);//多事件相或

    return XST_SUCCESS;
}

2、PL中断PS的配置代码(SPI)

2.1、硬中断的基础知识

        PL到PS的中断,也属于共享中断,一般都称做硬中断硬中断一共有16个ID分别是61-68和84-91,系统默认从61开始分配ID号。如下图IRQ_F2P[0] = 61,IRQ_F2P[1] = 62,依次类推,需要注意的是:IRQ_F2P的数据位宽是自动分配,不要自己去分配。

        其次,由上面可知,硬中断的触发方式可分为上升沿触发和高电平触发,因此在配置时,需要说明清楚,我一般使用都配置为边沿触发。

        注意:高电平触表示在高电平期间触发中断,但并不是说在高电平期间的每一个时刻都会触发中断。

2.2、硬中断实验内容

       本次实验,由FPGA给CPU0产生一个1s中断,FPGA每次计数到1s就产生一个1us的中断信号给CPU0。

        Verilog代码如下:

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN   : 大屁桃
// E-mail : [email protected]
// File   : intr1s.v
// Create : 2023-11-04 14:33:39
// -----------------------------------------------------------------------------
module intr1s(
	input wire clk,	//50MHz
	input wire rst,
	output wire intr1sflag
	);

//常量定义
parameter CNT_END = 49999999;//50,000,000 - 1 
parameter CNT_1US_END = 49;

//1s计数器
reg [25:0] cnt_1s;
reg flag_1s;
assign intr1sflag = flag_1s;

//1s计数器
always @(posedge clk) begin
	if (rst == 1'b1) begin
		cnt_1s <= 'd0;
	end
	else if (cnt_1s == CNT_END) begin
		cnt_1s <= 'd0;
	end
	else begin
		cnt_1s <= cnt_1s + 1'b1;
	end
end

//1us的标志信号
always @(posedge clk) begin
	if (rst == 1'b1) begin
		flag_1s <= 1'b0;
	end
	else if (cnt_1s == CNT_1US_END) begin
		flag_1s <= 1'b0;
	end
	else if(cnt_1s == CNT_END) begin
		flag_1s <= 1'b1;
	end
end

endmodule

  2.3、中断初始化代码如下

        注意:

        1、AMP模式下,需要对硬中断的ID进行绑定CPU。

        2、AMP模式下,对CPU0和CPU1同时初始化时,要有先后顺序,一般情况下先给CPU0初始化,再给CPU1初始化。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xscugic.h" //中断头文件
#include "xparameters.h"//设备ID

/*step1 重定义*/
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define GIC_BASEADDR XPAR_PS7_SCUGIC_0_DIST_BASEADDR
#define F2P_DEV_INTR0 61 //1s中断源对应的ID
#define INTR_PORI 32 //F2P中断优先级
#define TRIG_TYPE 3  //F2P中断触发类型 2'b01 高电平触发,2'b11 = 3为上升沿触发


/*step2 变量定义*/
XScuGic ScuGic;
XScuGic_Config *ScuGicCfgPtr;

/*step3 函数声明*/
int Init_Gic(void);
void F2P0_Handler(void *data);//1s中断处理函数

int main()
{
    Init_Gic();
    while(1)
    {

    }
    return 0;
}


int Init_Gic(void)
{
    int status = 0;
    /*step1、初始化异常处理*/
    Xil_ExceptionInit();
    /*step2、初始化中断控制器*/
    ScuGicCfgPtr = XScuGic_LookupConfig(GIC_DEV_ID);
    status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
    if(status != XST_SUCCESS)
    {
        printf("Initial Gic Failed!");
        return status;
    }
    /*step3、注册异常处理回调函数*/
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
    /*step4.异常处理使能*/
    Xil_ExceptionEnable();

    /******配置区域*******/
    /*step5、在gic中使能(被中断的设备ID)*/
    XScuGic_Enable(&ScuGic,F2P_DEV_INTR0);
    /*step6、在gic中连接被中断的设备ID,并注册回调函数*/
    status = XScuGic_Connect(&ScuGic,F2P_DEV_INTR0,(Xil_ExceptionHandler)F2P0_Handler,&ScuGic);
    if(status != XST_SUCCESS)
    {
        printf("Connect Gic Failed!");
        return status;
    }
    /*step7、设置F2P中断源优先级和触发类型*///设置触发类型是因为F2P有两种触发方式让你选
    XScuGic_SetPriTrigTypeByDistAddr(GIC_BASEADDR,F2P_DEV_INTR0,INTR_PORI,TRIG_TYPE);
    /*step8、在双核架构下需要,将硬件ID与对应的CPU相连接*/
//    XScuGic_InterruptMaptoCpu(&ScuGic,0,F2P_DEV_INTR0);

    return XST_SUCCESS;
}

void F2P0_Handler(void *data)
{
    printf("come from PL 1s 999!\n\r");
}

3、GPIO中断配置代码

        GPIO和串口中断比较类似,在中断初始化之前首先要对GPIO进行初始化,只有在GPIO初始化结束后再去配置GPIO的中断。

        需要注意的是:要区分开设备ID中断号ID这两者的区别。同时关于MIO和EMIO的设备ID如下图。MIO和EMIO的ID顺序都是按照初始化时数组的低位到高位排列,对应于不同bank的低位到高位。

        具体代码如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h" //设备ID号
#include "xgpiops.h"     //GPIO设置头文件
#include "xscugic.h"     //通用中断控制器头文件
#include "sleep.h"       //延时函数头文件
//全局变量
u32  led_value = 1;

/*1.重定义*/
#define GPIO_DEV_ID XPAR_PS7_GPIO_0_DEVICE_ID  //GPIO device ID
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //GIC devive ID

#define LED0 54
#define LED1 55
#define SW0  56

#define GPIO_INTR_ID 52//GPIO的中断ID,来源于表格

#define SW_BANK_ID 2   //连接按键的管脚属于EMIO,属于GPIO BANK 2
/*2.变量定义*/
XScuGic ScuGic;
XScuGic_Config * ScuGicCfgPtr;

XGpioPs GpioPs;
XGpioPs_Config * GpioPsCfPtr;

/*3.函数初始化*/
int Init_GPIO(void);
int Init_Gic(void);
void GPIO_Handler(void *CallBackRef, u32 Bank, u32 Status);

int main()
{
	int status = 0;
//	printf("GPIO interrupt !\r\n");
	Init_GPIO();
	status = Init_Gic();
	if(status != XST_SUCCESS)
	{
		return	status;
	}
	while(1)
	{
		printf("GPIO interrupt ! led_value = %d\r\n",led_value);
		sleep(1);
	}
    return 0;
}

int Init_GPIO(void)
{
	int status = 0;
	GpioPsCfPtr = XGpioPs_LookupConfig(GPIO_DEV_ID);
	status = XGpioPs_CfgInitialize(&GpioPs,GpioPsCfPtr,GpioPsCfPtr->BaseAddr);
	if(status != XST_SUCCESS){
		return	status;
	}
	//设置GPIO的方向
	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
	XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
	XGpioPs_SetDirectionPin(&GpioPs,SW0,0x00);//input for button
	//设置输出使能
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);

	return	XST_SUCCESS;
}

int Init_Gic(void)
{
	int status = 0;
	/*step1、初始化异常处理*/
	Xil_ExceptionInit();
	/*step2、初始化中断控制器*/
	ScuGicCfgPtr = XScuGic_LookupConfig(GIC_DEV_ID);
	status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
	if(status != XST_SUCCESS)
	{
		printf("Initial Gic Failed!");
		return status;
	}
	/*step3、注册异常处理回调函数*/
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
	/*step4、使能异常处理*/
	Xil_ExceptionEnable();

	/***********配置区域***********/
    //step5、在GIC中使能GPIO中断
	XScuGic_Enable(&ScuGic,GPIO_INTR_ID);
	//step6、在GIC中连接GPIO对应的中断ID
	status = XScuGic_Connect(&ScuGic,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs);
	if(status != XST_SUCCESS){
			return status;
	}
	//step7、设置GPIO中断处理函数
	XGpioPs_SetCallbackHandler(&GpioPs,(void*) &GpioPs,(XGpioPs_Handler)GPIO_Handler);
	//step8、使能GPIO对应的bank上的具体地址
	XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(SW0-54));

	return	XST_SUCCESS;
}


void GPIO_Handler(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);
		//等待按键抖动结束,100ms高电平
		u32 readSW=0;
		int cnt;
		while(cnt <100)
		{
			readSW= XGpioPs_ReadPin(GpioPtr,SW0);
			if(readSW == 1)
			{
				cnt ++;
			}
			else
			{
				cnt =0;
			}
			usleep(1000);
		}
		//打开对应GPIO的中断使能
		XGpioPs_IntrEnablePin(GpioPtr,SW0);

	}
	/*中断处理*/
	led_value = ~led_value;
	XGpioPs_WritePin(GpioPtr,LED1,led_value);
	XGpioPs_WritePin(GpioPtr,LED0,led_value);

}

4、AMP模式下软中断配置代码

        软中断的中断ID为0~15,并且全部是上升沿触发,主要用于核间中断或者CPU自己中断自己。关于AMP模式下的工程构建,请参考博客:

4.1、SGI中断配置要点

        CPU0和CPU1的中断ID固定如下

#define CPU0_INTR_DEV_ID 0x0D//CPU0 interrupt ID
#define CPU1_INTR_DEV_ID 0x0E//CPU1 interrupt ID

        触发中断的方式:在中断配置完成后,CP0可以自己中断自己,也可以中断CPU1

//XSCUGIC_SPI_CPU0_MASK和XSCUGIC_SPI_CPU1_MASK为系统自带
status = XScuGic_SoftwareIntr(&ScuGic,CPU0_INTR_DEV_ID,XSCUGIC_SPI_CPU0_MASK);//CPU0自己中断自己
status = XScuGic_SoftwareIntr(&ScuGic,CPU1_INTR_DEV_ID,XSCUGIC_SPI_CPU1_MASK);//CPU0中断CPU1

4.2、AMP中断配置完整代码

        CPU0的配置代码如下:

//cpu0 main.c
#include <stdio.h>
#include "sleep.h"
#include "xparameters.h"
#include "xscugic.h"    //通用中断控制器头文件

/*1.重定义*/
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //GIC devive ID
#define CPU0_INTR_DEV_ID 0x0D//CPU0 interrupt ID(被中断的设备ID)
#define CPU1_INTR_DEV_ID 0x0E//CPU1 interrupt ID(被中断的设备ID)

/*2.变量定义*/
XScuGic ScuGic;
XScuGic_Config * ScuGicCfgPtr;

/*3.函数初始化*/
int Init_GIC_SGI(void);
void CPU0_Handler(void * CallBackRef);

int main()
{
    int status = 0;
    status = Init_GIC_SGI();
    if(status != XST_SUCCESS)
    {
        printf("Initial GIC and SGI Failed!");
        return status;
    }
    while(1)
    {
        status = XScuGic_SoftwareIntr(&ScuGic,CPU0_INTR_DEV_ID,XSCUGIC_SPI_CPU0_MASK);//自己中断自己
        if (status != XST_SUCCESS) {
            return XST_FAILURE;
        }
        sleep(5);
    }
    return 0;
}

int Init_GIC_SGI(void)
{
    int status = 0;
    /******中断控制器初始化*******/
    //step1.初始化异常处理
    Xil_ExceptionInit();
    //step2.初始化中断控制器
    ScuGicCfgPtr = XScuGic_LookupConfig(GIC_DEV_ID);
    status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
    if(status != XST_SUCCESS)
    {
        printf("Initial Gic Failed!");
        return status;
    }
    //step3.注册异常处理回调函数
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
    //step4.异常处理使能
    Xil_ExceptionEnable();

    /******SGI配置区域*******/
    //step5.在gic中使能(被中断的设备ID)
    XScuGic_Enable(&ScuGic,CPU0_INTR_DEV_ID);
    //step6.在gic中连接被中断的设备ID,并注册回调函数
    status = XScuGic_Connect(&ScuGic,CPU0_INTR_DEV_ID,(Xil_ExceptionHandler)CPU0_Handler,&ScuGic);
    if(status != XST_SUCCESS)
    {
        printf("Connect Gic Failed!");
        return status;
    }
    return XST_SUCCESS;
}

void CPU0_Handler(void * CallBackRef)
{
    printf("i am cpu000 intr !\n\r");
}

         CPU1的配置代码如下:

//cpu1 main.c
#include <stdio.h>
#include "sleep.h"
#include "xparameters.h"
#include "xscugic.h"    //通用中断控制器头文件

/*1.重定义*/
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //GIC devive ID
#define CPU0_INTR_DEV_ID 0x0D//CPU0 interrupt ID(被中断的设备ID)
#define CPU1_INTR_DEV_ID 0x0E//CPU1 interrupt ID(被中断的设备ID)

/*2.变量定义*/
XScuGic ScuGic;
XScuGic_Config * ScuGicCfgPtr;

/*3.函数初始化*/
int Init_GIC_SGI(void);
void CPU1_Handler(void * CallBackRef);

int main()
{
	int status = 0;
    sleep(2);//让cpu0先初始化
	status = Init_GIC_SGI();
    if(status != XST_SUCCESS)
    {
        printf("Initial GIC and SGI Failed!");
        return status;
    }
	while(1)
	{
//		sleep(3);
//		printf("this is cpu1 main\n\r");
		sleep(2);
		status = XScuGic_SoftwareIntr(&ScuGic,CPU0_INTR_DEV_ID,XSCUGIC_SPI_CPU0_MASK);//中断CPU0
		if (status != XST_SUCCESS) {
			return XST_FAILURE;
		}

	}
    return 0;
}

int Init_GIC_SGI(void)
{
	int status = 0;
	/******中断控制器初始化*******/
    //step1.初始化异常处理
    Xil_ExceptionInit();
    //step2.初始化中断控制器
    ScuGicCfgPtr = XScuGic_LookupConfig(GIC_DEV_ID);
    status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
    if(status != XST_SUCCESS)
    {
        printf("Initial Gic Failed!");
        return status;
    }
    //step3.注册异常处理回调函数
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
    //step4.异常处理使能
    Xil_ExceptionEnable();

    /******SGI配置区域*******/
    //step5.在gic中使能(被中断的设备ID)
    XScuGic_Enable(&ScuGic,CPU1_INTR_DEV_ID);
    //step6.在gic中连接被中断的设备ID,并注册回调函数
    status = XScuGic_Connect(&ScuGic,CPU1_INTR_DEV_ID,(Xil_ExceptionHandler)CPU1_Handler,&ScuGic);
    if(status != XST_SUCCESS)
    {
        printf("Connect Gic Failed!");
        return status;
    }
    return XST_SUCCESS;
}

void CPU1_Handler(void * CallBackRef)
{
	printf("i am cpu1 intr !\n\r");
}

猜你喜欢

转载自blog.csdn.net/Learning1232/article/details/134200443