目录
第一部分、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,对SDK的编程风格真的是不太习惯,不过适应一段时间后,会发现SDK还是挺好用的。这篇文章,主要是将最近学的中断系统进行一次整理,让自己的遗忘速度稍微变慢一点。
想要完全认识ZYNQ的中断,下面这张图真的要非常熟悉。主干是通用中断控制器(GIC)。GIC的左边包含三部分,分别是软中断(SGI)、私有中断(PPI)以及共享中断(SPI)。最常用的就是共享中断,只要把其中一种中断的初始化步骤弄清楚,那么其它理解起来就会变很简单。
每个中断都对应有自己的ID,这里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();
Zynq内的串口一共有四种工作模式,分别是普通模式、自动回声模式、本地回环模式和远程回环模式。
用于标准的UART操作模式。正常情况下都是用的这个模式。
这个模式下RXD引脚接收的数据,会自动路由到TXD引脚上。一边接收数据一边发送数据。
1.1.3、Local Loopback Mode模式
本地回环模式,相当于自发自收,数据不经过TXD和RXD这两个管脚。
这个模式下,CPU在TXD上不能发送任何内容,在RXD上不能接收任何内容。
配置串口中断之前,必须要对串口进行初始化,然后再去配置串口中断。初始化步骤包括:连接串口的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 */
串口中断初始化剩下的步骤如下
main.c代码如下,需要注意的是串口初始化要放在中断初始化之前,不然程序会卡死,原因:串口的初始化中,包含了寻找串口的设备ID,和初始化变量赋值的过程。
#include //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;
}
PL到PS的中断,也属于共享中断,一般都称做硬中断。硬中断一共有16个ID分别是61-68和84-91,系统默认从61开始分配ID号。如下图IRQ_F2P[0] = 61,IRQ_F2P[1] = 62,依次类推,需要注意的是:IRQ_F2P的数据位宽是自动分配,不要自己去分配。
其次,由上面可知,硬中断的触发方式可分为上升沿触发和高电平触发,因此在配置时,需要说明清楚,我一般使用都配置为边沿触发。
注意:高电平触表示在高电平期间触发中断,但并不是说在高电平期间的每一个时刻都会触发中断。
本次实验,由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
注意:
1、AMP模式下,需要对硬中断的ID进行绑定CPU。
2、AMP模式下,对CPU0和CPU1同时初始化时,要有先后顺序,一般情况下先给CPU0初始化,再给CPU1初始化。
#include
#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");
}
GPIO和串口中断比较类似,在中断初始化之前首先要对GPIO进行初始化,只有在GPIO初始化结束后再去配置GPIO的中断。
需要注意的是:要区分开设备ID和中断号ID这两者的区别。同时关于MIO和EMIO的设备ID如下图。MIO和EMIO的ID顺序都是按照初始化时数组的低位到高位排列,对应于不同bank的低位到高位。
具体代码如下:
#include
#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);
}
软中断的中断ID为0~15,并且全部是上升沿触发,主要用于核间中断或者CPU自己中断自己。关于AMP模式下的工程构建,请参考博客:
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
CPU0的配置代码如下:
//cpu0 main.c
#include
#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
#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");
}