ZYNQ基础----AMP核间软中断

    技术2022-07-11  117

      在前面一篇博客中,介绍了使用共享内存的方式来完成核间的通信的方式,本篇博客中将介绍通过软中断的方式来完成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" // OCM #define OCM3_ADDR 0xFFFF0000 #define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //software interrupt ID is 0x00~0x0F #define CPU0_SW_INT_ID 0x0D //CPU0的软中断ID,用于中断CPU0 #define CPU1_SW_INT_ID 0x0E //CPU1的软中断ID,用于中断CPU1 static XScuGic gicInst; static XScuGic_Config * gicCfg_Ptr; void swIntrHandler(void * CallBackRef) { printf("CPU0 is interrupted\n"); } int initGic() { int status; //1. 初始化异常处理系统 Xil_ExceptionInit(); //2. 初始化中断控制器 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; } //3. 注册异常回调函数 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &gicInst); //4. 连接GIC和对应软中断ID //软中断都是上升沿触发,因此不必再去设置中断触发类型 //软中断都是直接与GIC控制器相连接,和GPIO不同 status = XScuGic_Connect(&gicInst, CPU0_SW_INT_ID, (Xil_InterruptHandler)swIntrHandler, &gicInst); if(status != XST_SUCCESS) { printf("Connect GIC failed\n"); return XST_FAILURE; } //5. 使能中断控制器 XScuGic_Enable(&gicInst, CPU0_SW_INT_ID); //6. 使能异常处理系统 Xil_ExceptionEnable(); return status; } int main() { //初始化中断控制器 int status; status = initGic(); if(status != XST_SUCCESS) { printf("initialize GIC failed\n"); return XST_FAILURE; } //使用指针指向OCM3 u32 * onChipMemBuf = (u32 *)OCM3_ADDR; //关闭cache Xil_SetTlbAttributes(0xFFFF0000, 0x14de2); *onChipMemBuf = 0; while(1) { //OCM的值为0,执行cpu0的功能 if(*onChipMemBuf == 0) { //CPU0 打印信息 printf("hello world CPU0\n"); //CPU0 抛出中断, 用于中断CPU1 XScuGic_SoftwareIntr(&gicInst, CPU1_SW_INT_ID, XSCUGIC_SPI_CPU1_MASK); //更改 OCM 的值 *onChipMemBuf = 0x01; while(*onChipMemBuf == 0x01) { } } } return 0; }

    CPU1程序设计

    #include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xparameters.h" #include "xscugic.h" // on chip memory3 address #define OCM3_ADDR 0xFFFF0000 #define GIC_DEV_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //software interrupt ID is 0x00~0x0F #define CPU0_SW_INT_ID 0x0D //CPU0的软中断ID,用于中断CPU0 #define CPU1_SW_INT_ID 0x0E //CPU1的软中断ID,用于中断CPU1 static XScuGic gicInst; static XScuGic_Config * gicCfg_Ptr; void swIntrHandler(void * CallBackRef) { printf("CPU1 is interrupted\n"); } int initGic() { int status; //1. 初始化异常处理系统 Xil_ExceptionInit(); //2. 初始化中断控制器 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; } //3. 注册异常回调函数,中断类型的异常 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &gicInst); //4. 连接GIC和对应软中断ID //软中断都是上升沿触发,因此不必再去设置中断触发类型 //软中断都是直接与GIC控制器相连接,和GPIO不同 status = XScuGic_Connect(&gicInst, CPU1_SW_INT_ID, (Xil_InterruptHandler)swIntrHandler, &gicInst); if(status != XST_SUCCESS) { printf("Connect GIC failed\n"); return XST_FAILURE; } //5. 使能中断控制器 XScuGic_Enable(&gicInst, CPU1_SW_INT_ID); //6. 使能异常处理系统 Xil_ExceptionEnable(); return status; } int main() { //初始化中断控制器 int status; status = initGic(); if(status != XST_SUCCESS) { printf("initialize GIC failed\n"); return XST_FAILURE; } //使用指针指向片上内存3 u32 * onChipMemBuf = (u32 *)OCM3_ADDR; //关闭cache Xil_SetTlbAttributes(0xFFFF0000, 0x14de2); while(1) { //若 OCM 的值为1,则执行CPU1的功能 if(*onChipMemBuf == 1) { //CPU1打印信息 printf("hello world CPU1\n"); //CPU1 抛出中断, 用于中断CPU0 XScuGic_SoftwareIntr(&gicInst, CPU0_SW_INT_ID, XSCUGIC_SPI_CPU0_MASK); //更改 OCM 的值 *onChipMemBuf = 0x00; while(*onChipMemBuf == 0x00) { } } } return 0; }

    测试结果

      前面设计的程序中,每个CPU打印对应的信息后,抛出中断用于中断另外一个CPU。根据显示结果,可以看到打印结果符合预期。

    Processed: 0.011, SQL: 9