在前面一篇博客中,介绍了使用共享内存的方式来完成核间的通信的方式,本篇博客中将介绍通过软中断的方式来完成CPU0和CPU1之间的通信。本篇博客只需在上一篇博客中进行简单的修改即可。
ZYNQ的中断架构
在本人梦开始的地方,介绍了ZYNQ中的GPIO中断,GPIO的中断是通过SPI最终连接到GIC上的,而软中断可以从图上看出,直接连接到的GIC上的。 软中断的中断类型是固定的,固定为上升沿中断,因此在使能软中断时,不必去设置中断的类型。 软中断共有16个ID号,在本次实验中会使用到其中两个ID号,分别用于中断CPU0和CPU1。
软中断注册流程
步骤函数
初始化异常处理系统Xil_ExceptionInit();初始化中断控制器XScuGic_LookupConfig()XScuGic_CfgInitialize()注册异常回调函数Xil_ExceptionRegisterHandler()将中断控制器与对应的中断ID相连接XScuGic_Connect()使能中断控制器XScuGic_Enable()使能异常处理系统Xil_ExceptionEnable()
程序设计
CPU0程序设计
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
#define OCM3_ADDR 0xFFFF0000
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define CPU0_SW_INT_ID 0x0D
#define CPU1_SW_INT_ID 0x0E
static XScuGic gicInst
;
static XScuGic_Config
* gicCfg_Ptr
;
void swIntrHandler(void * CallBackRef
)
{
printf("CPU0 is interrupted\n");
}
int initGic()
{
int status
;
Xil_ExceptionInit();
gicCfg_Ptr
= XScuGic_LookupConfig(GIC_DEV_ID
);
status
= XScuGic_CfgInitialize(&gicInst
, gicCfg_Ptr
, gicCfg_Ptr
->CpuBaseAddress
);
if(status
!= XST_SUCCESS
)
{
printf("initialize GIC failed\n");
return XST_FAILURE
;
}
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT
, (Xil_ExceptionHandler
)XScuGic_InterruptHandler
, &gicInst
);
status
= XScuGic_Connect(&gicInst
, CPU0_SW_INT_ID
, (Xil_InterruptHandler
)swIntrHandler
, &gicInst
);
if(status
!= XST_SUCCESS
)
{
printf("Connect GIC failed\n");
return XST_FAILURE
;
}
XScuGic_Enable(&gicInst
, CPU0_SW_INT_ID
);
Xil_ExceptionEnable();
return status
;
}
int main()
{
int status
;
status
= initGic();
if(status
!= XST_SUCCESS
)
{
printf("initialize GIC failed\n");
return XST_FAILURE
;
}
u32
* onChipMemBuf
= (u32
*)OCM3_ADDR
;
Xil_SetTlbAttributes(0xFFFF0000, 0x14de2);
*onChipMemBuf
= 0;
while(1)
{
if(*onChipMemBuf
== 0)
{
printf("hello world CPU0\n");
XScuGic_SoftwareIntr(&gicInst
, CPU1_SW_INT_ID
, XSCUGIC_SPI_CPU1_MASK
);
*onChipMemBuf
= 0x01;
while(*onChipMemBuf
== 0x01)
{
}
}
}
return 0;
}
CPU1程序设计
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
#define OCM3_ADDR 0xFFFF0000
#define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define CPU0_SW_INT_ID 0x0D
#define CPU1_SW_INT_ID 0x0E
static XScuGic gicInst
;
static XScuGic_Config
* gicCfg_Ptr
;
void swIntrHandler(void * CallBackRef
)
{
printf("CPU1 is interrupted\n");
}
int initGic()
{
int status
;
Xil_ExceptionInit();
gicCfg_Ptr
= XScuGic_LookupConfig(GIC_DEV_ID
);
status
= XScuGic_CfgInitialize(&gicInst
, gicCfg_Ptr
, gicCfg_Ptr
->CpuBaseAddress
);
if(status
!= XST_SUCCESS
)
{
printf("initialize GIC failed\n");
return XST_FAILURE
;
}
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT
, (Xil_ExceptionHandler
)XScuGic_InterruptHandler
, &gicInst
);
status
= XScuGic_Connect(&gicInst
, CPU1_SW_INT_ID
, (Xil_InterruptHandler
)swIntrHandler
, &gicInst
);
if(status
!= XST_SUCCESS
)
{
printf("Connect GIC failed\n");
return XST_FAILURE
;
}
XScuGic_Enable(&gicInst
, CPU1_SW_INT_ID
);
Xil_ExceptionEnable();
return status
;
}
int main()
{
int status
;
status
= initGic();
if(status
!= XST_SUCCESS
)
{
printf("initialize GIC failed\n");
return XST_FAILURE
;
}
u32
* onChipMemBuf
= (u32
*)OCM3_ADDR
;
Xil_SetTlbAttributes(0xFFFF0000, 0x14de2);
while(1)
{
if(*onChipMemBuf
== 1)
{
printf("hello world CPU1\n");
XScuGic_SoftwareIntr(&gicInst
, CPU0_SW_INT_ID
, XSCUGIC_SPI_CPU0_MASK
);
*onChipMemBuf
= 0x00;
while(*onChipMemBuf
== 0x00)
{
}
}
}
return 0;
}
测试结果
前面设计的程序中,每个CPU打印对应的信息后,抛出中断用于中断另外一个CPU。根据显示结果,可以看到打印结果符合预期。