为了更好的浏览体验,请不要在本页面禁用 Javascript
2020-01-06
 Tags: 

Zynq7000软件中断SGI使用摘要

参考文章
使用软件中断的基本流程如下:
1.初始化GIC中断控制器
2.设置中断异常
3.绑定中断服务函数
4.设置中断优先级和触发方式
5.绑定触发中断的CPU
6.允许中断
7.触发软件中断
相关API
1.初始化GIC中断控制器;
XScuGic_Config *XScuGic_LookupConfig(u16 DeviceId);
C
通过设备id查找设备的配置 DeviceID,设备ID的唯一标识符。 返回XScuGic_Config *型指针,指向指定设备的配置信息结构体中。
s32 XScuGic_CfgInitialize(XScuGic *InstancePtr, XScuGic_Config *ConfigPtr, u32 EffectiveAddr);
C
对指定的中断控制器实例进行初始化。 InstancePtr是指向XScuGic实例的指针。 ConfigPtr是指向所关联的特定设备的配置表的指针。 EffectiveAddr是所关联设备的有效地址。
2.设置中断异常
void Xil_ExceptionInit(void);
C
异常处理,在Coretex-A9中不做任何事,因为异常处理已被静态初始化。
void Xil_ExceptionRegisterHandler(u32 Exception_id, Xil_ExceptionHandler Handler, void *Data);
C
为特定的异常注册一个handler,当处理器发生特定异常后调用对应handler。 Exception_id异常源的id。 Handler是异常处理函数。 Data是异常发生时,传给对应handler的参数。
#define Xil_ExceptionEnable() \\ Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ)
C
允许中断的异常处理
3.绑定中断服务函数
s32 XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id, Xil_InterruptHandler Handler, void *CallBackRef);
C
将指定中断服务函数绑定到指定中断号上。 InstancePtr是指向XScuGic实例的指针。 Int_Id是中断源的中断号。 Handler是中断处理函数。 CallBackRef是回调的一个引用,会传递给中断服务函数作为参数,一般是所关联的设备的实例指针,通过类型转换在中断服务函数获取设备实例。
4.设置中断优先级和触发方式
void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id, u8 Priority, u8 Trigger);
C
为指定中断源设定中断优先级和触发类型。 InstancePtr是指向XScuGic实例的指针。 Int_Id是中断源的中断号。 Priority是要将中断源更新后的优先级,0为最高,0xF8为最低。有32个等级,以8为步长,0,8,16,...,248。 Trigger是要将中断源更新后的触发类型。
5.绑定触发中断的CPU
void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id);
C
将中断源和目标CPU绑定 InstancePtr是指向XScuGic实例的指针。 Cpu_Id目标CPU的id。 Int_Id是中断源的中断号。
6.允许中断
void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id);
C
中断使能,在该函数调用后,可使对应id的pending的中断能够发生。 InstancePtr是指向XScuGic实例的指针。 Int_Id是中断源的中断号。
7.触发软件中断
s32 XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id);
C
通过软件模拟中断的方式在中断控制器中触发中断。 InstancePtr是指向XScuGic实例的指针。 Int_Id是软件模拟的中断源的中断号。 Cpu_Id将中断送往到的目标CPU的id。
实例
搬运文章3的使用实例: 该例子中,cpu0和cpu1都注册两个软件中断,将1号软件中断注册给cpu1,表示cpu0发送中断给cpu1,将2号软件中断注册给cpu0,表示cpu1发送中断给cpu0;然后在程序运行时,cpu0触发1号软件中断,此时cpu1正在运行主程序被该中断中断,进入中断服务函数,其处理完中断后触发2号软件中断,此时该中断会中断cpu0,进入中断服务函数,cpu0处理完中断后回到主函数,再触发1号软件中断,往复运行。
代码略作修改后如下。
P0_main.c:
#include<stdio.h> #include "xil_cache.h" #include "xparameters.h" #include "xil_mmu.h" #include "xil_misc_psreset_api.h" #include "xil_exception.h" #include "xscugic.h" #include "xuartps.h" #include "stdio.h" #include "sleep.h" #include "xil_printf.h" volatile u8 software_intr_received = 0; #define TRIGGER_BY_CPU0_INT_ID 0x01 #define TRIGGER_BY_CPU1_INT_ID 0x02 //函数声明 void sys_intr_init(void); void Setup_Intr_Exception(XScuGic * IntcInstancePtr); void Scu_Intr_Init(XScuGic* IntancePtr, int Scu_Int_ID); void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHandler, u16 SoftwareIntrId, u8 CpuId); void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId); void IntrFromCPU1_Handler(void *Callback); XScuGic ScuGic; void delay(unsigned int count) { int i = 0; for (i = 0; i < count; i++); } int main(void) { sys_intr_init(); xil_printf("cpu0 start!\\r\\n"); /* Gen_Software_Intr(&ScuGic, TRIGGER_BY_CPU0_INT_ID, XSCUGIC_SPI_CPU1_MASK); */ while (1){ if (1 == software_intr_received) { software_intr_received = 0; xil_printf("So, cpu0_main can do ...\\r\\n\\r\\n"); Gen_Software_Intr(&ScuGic, TRIGGER_BY_CPU0_INT_ID, XSCUGIC_SPI_CPU1_MASK); delay(200000000); } } return 0; } void sys_intr_init(void) { //初始化GIC Scu_Intr_Init(&ScuGic, XPAR_SCUGIC_SINGLE_DEVICE_ID); //绑定中断服务函数,设置中断优先级和触发方式,绑定触发中断到目标CPU,允许中断 Init_Software_Intr(&ScuGic,IntrFromCPU1_Handler, TRIGGER_BY_CPU1_INT_ID, 1); Setup_Intr_Exception(&ScuGic); } void Setup_Intr_Exception(XScuGic * IntcInstancePtr) { //connect hardware interrupt Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, (void *) IntcInstancePtr); //enable hardware interrupt Xil_ExceptionEnable(); } //1.初始化GIC中断控制器; void Scu_Intr_Init(XScuGic* IntancePtr, int Scu_Int_ID) { XScuGic_Config *ScuConfigPtr; ScuConfigPtr = XScuGic_LookupConfig(Scu_Int_ID);//中断设置查找 1 XScuGic_CfgInitialize(IntancePtr, ScuConfigPtr,//GIC初始化 2 ScuConfigPtr->CpuBaseAddress); } void IntrFromCPU1_Handler(void *Callback) { xil_printf("P0_main.c: receive interrupt from core1!\\r\\n"); software_intr_received = 1; } //2.绑定中断服务函数;3设置中断优先级和触发方式;4.绑定触发中断的CPU;5.允许中断 void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHandler, u16 SoftwareIntrId, u8 CpuId) { int Status; XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xd0, 0x3);//设置中断优先级及中断触发方式 3 Status = XScuGic_Connect(GicInstancePtr, SoftwareIntrId, (Xil_InterruptHandler) IntrHandler, NULL);//设置中断服务程序入口地址 4 if (Status != XST_SUCCESS) { xil_printf("core%d: interrupt %d set fail!\\r\\n", XPAR_CPU_ID, SoftwareIntrId); return; } XScuGic_InterruptMaptoCpu(GicInstancePtr, CpuId, SoftwareIntrId); //配置中断到对应的CPU 5 XScuGic_Enable(GicInstancePtr, SoftwareIntrId); //GIC允许,允许中断 } //6.触发软件中断; void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId) { int Status; Status = XScuGic_SoftwareIntr(GicInstancePtr, SoftwareIntrId, CpuId);//在正在更新的内核中触发软件中断。该命令将向该指定内核发出一个软件中断 if (Status != XST_SUCCESS) { xil_printf("core%d: interrupt %d gen fail!\\r\\n", XPAR_CPU_ID, SoftwareIntrId); return; } }
C
P1_main.c
#include<stdio.h> #include "xil_cache.h" #include "xparameters.h" #include "xil_mmu.h" #include "xil_misc_psreset_api.h" #include "xil_exception.h" #include "xscugic.h" #include "xuartps.h" #include "stdio.h" #include "sleep.h" #include "xil_printf.h" volatile u8 software_intr_received = 0; #define TRIGGER_BY_CPU0_INT_ID 0x01 #define TRIGGER_BY_CPU1_INT_ID 0x02 void sys_intr_init(void); void Setup_Intr_Exception(XScuGic * IntcInstancePtr); void Scu_Intr_Init(XScuGic* IntancePtr, int Scu_Int_ID); void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHandler, u16 SoftwareIntrId, u8 CpuId); void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId); void IntrFromCPU0_Handler(void *Callback); XScuGic ScuGic; void delay(unsigned int count) { int i = 0; for (i = 0; i < count; i++); } int main(void) { sys_intr_init(); xil_printf("cpu1 start!\\r\\n"); Gen_Software_Intr(&ScuGic, TRIGGER_BY_CPU1_INT_ID, XSCUGIC_SPI_CPU0_MASK); while (1) { if (1 == software_intr_received) { software_intr_received = 0; xil_printf("So, cpu1_main can do ...\\r\\n\\r\\n"); Gen_Software_Intr(&ScuGic, TRIGGER_BY_CPU1_INT_ID, XSCUGIC_SPI_CPU0_MASK); delay(200000000); } } return 0; } void sys_intr_init(void) { Scu_Intr_Init(&ScuGic, XPAR_SCUGIC_SINGLE_DEVICE_ID); Init_Software_Intr(&ScuGic, IntrFromCPU0_Handler, TRIGGER_BY_CPU0_INT_ID, 0); Setup_Intr_Exception(&ScuGic); } void Setup_Intr_Exception(XScuGic * IntcInstancePtr) { //connect hardware interrupt Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, (void *) IntcInstancePtr); //enable hardware interrupt Xil_ExceptionEnable(); } void Scu_Intr_Init(XScuGic* IntancePtr, int Scu_Int_ID) { XScuGic_Config *ScuConfigPtr; //find device ScuConfigPtr = XScuGic_LookupConfig(Scu_Int_ID); //config scuint XScuGic_CfgInitialize(IntancePtr, ScuConfigPtr, ScuConfigPtr->CpuBaseAddress); } void IntrFromCPU0_Handler(void *Callback) { xil_printf("P1_main.c: receive interrupt from core0!\\r\\n"); software_intr_received = 1; } void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHandler, u16 SoftwareIntrId, u8 CpuId) { int Status; XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xB0, 0x2); Status = XScuGic_Connect(GicInstancePtr, SoftwareIntrId, (Xil_InterruptHandler) IntrHandler, NULL); if (Status != XST_SUCCESS) { xil_printf("core%d: interrupt %d set fail!\\r\\n", XPAR_CPU_ID, SoftwareIntrId); return; } XScuGic_InterruptMaptoCpu(GicInstancePtr, CpuId, SoftwareIntrId); //map the the Software interrupt to target CPU XScuGic_Enable(GicInstancePtr, SoftwareIntrId); //enable the interrupt for the Software interrupt at GIC } void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId) { int Status; Status = XScuGic_SoftwareIntr(GicInstancePtr, SoftwareIntrId, CpuId); if (Status != XST_SUCCESS) { xil_printf("core%d: interrupt %d gen fail!\\r\\n", XPAR_CPU_ID, SoftwareIntrId); return; } }
C
Modified based on gine-blog