IGNORANT

Zynq7000软件中断SGI使用摘要

参考文章

如下:

ZYNQ有两个CPU?(三)——SGI异步通信
SoC 第三讲 AMP架构双核应用程序开发和软中断处理(二)—— ZYNQ 的中断介绍
ZYNQ开发(五)双核启动

使用软件中断的基本流程如下:

相关API

1.初始化GIC中断控制器;

XScuGic_Config *XScuGic_LookupConfig(u16 DeviceId);

通过设备id查找设备的配置
DeviceID,设备ID的唯一标识符。
返回XScuGic_Config *型指针,指向指定设备的配置信息结构体中。

s32  XScuGic_CfgInitialize(XScuGic *InstancePtr,
                XScuGic_Config *ConfigPtr,
                u32 EffectiveAddr);

对指定的中断控制器实例进行初始化。
InstancePtr是指向XScuGic实例的指针。
ConfigPtr是指向所关联的特定设备的配置表的指针。
EffectiveAddr是所关联设备的有效地址。

2.设置中断异常

void Xil_ExceptionInit(void);

异常处理,在Coretex-A9中不做任何事,因为异常处理已被静态初始化。

void Xil_ExceptionRegisterHandler(u32 Exception_id,
                    Xil_ExceptionHandler Handler,
                    void *Data);

为特定的异常注册一个handler,当处理器发生特定异常后调用对应handler。
Exception_id异常源的id。
Handler是异常处理函数。
Data是异常发生时,传给对应handler的参数。

#define Xil_ExceptionEnable() \
        Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ)

允许中断的异常处理

3.绑定中断服务函数

s32  XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
                      Xil_InterruptHandler Handler, void *CallBackRef);

将指定中断服务函数绑定到指定中断号上。
InstancePtr是指向XScuGic实例的指针。
Int_Id是中断源的中断号。
Handler是中断处理函数。
CallBackRef是回调的一个引用,会传递给中断服务函数作为参数,一般是所关联的设备的实例指针,通过类型转换在中断服务函数获取设备实例。

4.设置中断优先级和触发方式

void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
                    u8 Priority, u8 Trigger);

为指定中断源设定中断优先级和触发类型。
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);

将中断源和目标CPU绑定
InstancePtr是指向XScuGic实例的指针。
Cpu_Id目标CPU的id。
Int_Id是中断源的中断号。

6.允许中断

void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id);

中断使能,在该函数调用后,可使对应id的pending的中断能够发生。
InstancePtr是指向XScuGic实例的指针。
Int_Id是中断源的中断号。

7.触发软件中断

s32  XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id);

通过软件模拟中断的方式在中断控制器中触发中断。
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;
    }
}

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;
    }
}

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »