[Einführung in ZYNQ] Teil 2, das Interrupt-System von ZYNQ und gängige Interrupt-Initialisierungsprogramme

Inhaltsverzeichnis

Teil 1, Zynqs Interrupt-System und Architektur

1. Systemstruktur unterbrechen

Teil 2: IDs, die verschiedenen Arten von Interrupts entsprechen

1. Soft-Interrupt-SGI-ID

2. ID des privaten Interrupt-PPI

3. Gemeinsame SPI-ID (am häufigsten verwendet)

Teil 3, Häufig verwendete Interrupt-Initialisierungsprogramme

1. UART0-Interrupt-Konfigurationscode (SPI)

1.1. Arbeitsmodus der seriellen Schnittstelle

1.1.1. Normalmodus

1.1.2. Automatischer Echomodus

1.1.4. Remote-Loopback-Modus

1.2. Initialisierung der seriellen Schnittstelle

1.3. Interrupt-Initialisierungscode        

2. PL-Interrupt PS-Konfigurationscode (SPI)

2.1. Grundkenntnisse über harte Interrupts

2.2. Experimentelle Inhalte hart unterbrechen

2.3 Der Interrupt-Initialisierungscode lautet wie folgt

3. GPIO-Interrupt-Konfigurationscode

4. Soft-Interrupt-Konfigurationscode im AMP-Modus

4.1. Wichtige Punkte der SGI-Interrupt-Konfiguration

4.2. Vollständiger Code für die AMP-Interrupt-Konfiguration


Teil 1, Zynqs Interrupt-System und Architektur

        Ich habe gerade erst mit ZYNQ angefangen und bin wirklich nicht an den Programmierstil des SDK gewöhnt, aber nachdem ich mich eine Weile daran gewöhnt habe, werde ich feststellen, dass das SDK recht einfach zu verwenden ist. Dieser Artikel dient hauptsächlich dazu, das Unterbrechungssystem, das ich kürzlich gelernt habe, zu organisieren, um meine Vergessensgeschwindigkeit ein wenig zu verlangsamen.

 1. Systemstruktur unterbrechen

        Wenn Sie die Unterbrechungen von ZYNQ vollständig verstehen möchten, müssen Sie mit dem folgenden Bild vertraut sein. Das Rückgrat ist der General Interrupt Controller ( GIC ). Die linke Seite von GIC enthält drei Teile, nämlich Soft Interrupt ( SGI ) , Private Interrupt ( PPI ) und Shared Interrupt ( SPI ) . Am häufigsten wird der gemeinsam genutzte Interrupt verwendet. Solange die Initialisierungsschritte eines der Interrupts klar sind, ist es sehr einfach, die anderen zu verstehen.

Teil 2: IDs, die verschiedenen Arten von Interrupts entsprechen

        Jeder Interrupt entspricht seiner eigenen ID. Die Rolle der ID besteht hier hauptsächlich darin , bei der Initialisierung des Interrupts als Eingabeparameter für zu dienen . Der Zweck besteht darin, dem Interrupt-System mitzuteilen, welchen Interrupt ich verwende. Ich habe Ihnen den Namen gesagt, verstehen Sie ihn also nicht falsch.

1. Soft-Interrupt-SGI-ID

2. ID des privaten Interrupt-PPI

3. Gemeinsame SPI-ID (am häufigsten verwendet)

Teil 3, Häufig verwendete Interrupt-Initialisierungsprogramme

        Der Programmablauf des Interrupts ist in der folgenden Abbildung dargestellt: Die ersten vier Schritte sind feste Prozesse , da diese vier Schritte hauptsächlich zur Initialisierung des allgemeinen Interrupt-Controllers verwendet werden, bei dem es sich um die Initialisierung des Hauptteils des ersten Bildes handelt. Denn unabhängig davon, ob es sich um SGI, PPI oder SPI handelt, sind diese drei Interrupt-Typen mit GIC verbunden , sodass die Initialisierung in den ersten vier Schritten behoben werden kann.

       Der Konfigurationscode für die ersten vier Schritte lautet wie folgt:

    /*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();

1. UART0-Interrupt-Konfigurationscode (SPI)

1.1. Arbeitsmodus der seriellen Schnittstelle

        Der serielle Port in Zynq verfügt über insgesamt vier Arbeitsmodi: Normalmodus , automatischer Echomodus , lokaler Loopback-Modus und Remote-Loopback-Modus .

1.1.1. Normalmodus

        Für den Standard-UART-Betriebsmodus. Dieser Modus wird unter normalen Umständen verwendet.

1.1.2. Automatischer Echomodus

        In diesem Modus werden die vom RXD-Pin empfangenen Daten automatisch an den TXD-Pin weitergeleitet. Senden Sie Daten, während Sie Daten empfangen.

1.1.3. Lokaler Loopback-Modus

        Der lokale Loopback-Modus entspricht dem spontanen Selbstempfang, und die Daten passieren nicht die TXD- und RXD-Pins.

1.1.4. Remote-Loopback-Modus

        In diesem Modus kann die CPU nichts auf TXD senden und nichts auf RXD empfangen.

1.2. Initialisierung der seriellen Schnittstelle

        Bevor Sie den seriellen Port-Interrupt konfigurieren, müssen Sie den seriellen Port initialisieren und dann den seriellen Port-Interrupt konfigurieren. Die Initialisierungsschritte umfassen: Verbinden der ID des seriellen Anschlusses, Festlegen der Baudrate, Festlegen des Arbeitsmodus des seriellen Anschlusses, Festlegen des Interrupt-Intervalls und Starten der Interrupt-Überwachung . Code wie folgt anzeigen:

//串口初始化函数
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的预计的字节数
}

        Zu beachten ist die Interrupt-Auslösemethode für die serielle Schnittstelle. Es gibt viele Auslösemethoden für die serielle Schnittstelle. In diesem Experiment wurde der Interrupt für das Empfangszeitintervall ausgewählt. Wenn RXD über einen bestimmten Zeitraum keine Daten empfängt, wird ein Interrupt generiert. Einzelheiten finden Sie in der Header-Datei 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 */

1.3. Interrupt-Initialisierungscode        

        Die verbleibenden Schritte für die Interrupt-Initialisierung der seriellen Schnittstelle sind wie folgt:

        Der main.c-Code lautet wie folgt. Es ist zu beachten, dass die Initialisierung der seriellen Schnittstelle vor der Interrupt-Initialisierung erfolgen muss , da das Programm sonst hängen bleibt. Der Grund: Die Initialisierung der seriellen Schnittstelle umfasst den Prozess zum Ermitteln der Geräte-ID des seriellen Ports und Initialisierung der Variablenzuweisungen.

#include <stdio.h>      //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;
}

2. PL-Interrupt PS-Konfigurationscode (SPI)

2.1. Grundkenntnisse über harte Interrupts

        Der Interrupt von PL nach PS ist ebenfalls ein gemeinsam genutzter Interrupt und wird allgemein als harter Interrupt bezeichnet . Es gibt insgesamt 16 Hard-Interrupt-IDs, nämlich 61-68 und 84-91. Das System vergibt standardmäßig ID-Nummern ab 61 . Wie in der folgenden Abbildung gezeigt, ist IRQ_F2P[0] = 61, IRQ_F2P[1] = 62 usw. Es ist zu beachten: Die Datenbitbreite von IRQ_F2P wird automatisch zugewiesen, weisen Sie sie nicht selbst zu.

        Zweitens können, wie aus dem Obigen hervorgeht, die Auslösemethoden für harte Interrupts unterteilt werden in Auslösung mit steigender Flanke und Auslösung mit hohem Pegel . Daher muss dies bei der Konfiguration klar erläutert werden. Ich konfiguriere es im Allgemeinen als Flankenauslösung.

        Hinweis: Eine Berührung auf hoher Ebene bedeutet, dass während der Zeit auf hoher Ebene ein Interrupt ausgelöst wird. Dies bedeutet jedoch nicht, dass zu jedem Zeitpunkt während der Zeit auf hoher Ebene ein Interrupt ausgelöst wird.

2.2. Experimentelle Inhalte hart unterbrechen

       In diesem Experiment generiert der FPGA einen 1-s-Interrupt an CPU0. Der FPGA generiert jedes Mal, wenn er bis 1 s zählt, ein 1-us-Interruptsignal an CPU0.

        Der Verilog-Code lautet wie folgt:

// -----------------------------------------------------------------------------
// 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

  2.3 Der Interrupt-Initialisierungscode lautet wie folgt

        Beachten:

        1. Im AMP-Modus muss die ID des harten Interrupts an die CPU gebunden werden.

        2. Im AMP-Modus muss beim gleichzeitigen Initialisieren von CPU0 und CPU1 eine Reihenfolge vorhanden sein: Im Allgemeinen wird zuerst CPU0 und dann CPU1 initialisiert.

#include <stdio.h>
#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");
}

3. GPIO-Interrupt-Konfigurationscode

        GPIO- und serielle Port-Interrupts sind ähnlich. Vor der Interrupt-Initialisierung muss zuerst GPIO initialisiert werden, und GPIO-Interrupts dürfen erst konfiguriert werden, nachdem die GPIO-Initialisierung abgeschlossen ist.

        Es ist zu beachten, dass zwischen der Geräte-ID und der Interrupt-Nummer-ID unterschieden werden mussGleichzeitig sind die Geräte-IDs von MIO und EMIO wie unten dargestellt. Die ID-Reihenfolge von MIO und EMIO wird während der Initialisierung vom Low-Bit zum High-Bit des Arrays angeordnet, entsprechend dem Low-Bit bis zum High-Bit verschiedener Bänke.

        Der spezifische Code lautet wie folgt:

#include <stdio.h>
#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);

}

4. Soft-Interrupt-Konfigurationscode im AMP-Modus

        Die Interrupt-IDs von Soft-Interrupts liegen zwischen 0 und 15 und werden alle durch steigende Flanken ausgelöst. Sie werden hauptsächlich für Inter-Core-Interrupts verwendet oder die CPU selbst unterbricht sich selbst. Informationen zur Projekterstellung im AMP-Modus finden Sie im Blog:

4.1. Wichtige Punkte der SGI-Interrupt-Konfiguration

        Die Interrupt-IDs von CPU0 und CPU1 sind wie folgt festgelegt

#define CPU0_INTR_DEV_ID 0x0D//CPU0 interrupt ID
#define CPU1_INTR_DEV_ID 0x0E//CPU1 interrupt ID

        So lösen Sie Interrupts aus: Nachdem die Interrupt-Konfiguration abgeschlossen ist, kann CP0 sich selbst oder CPU1 unterbrechen

//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

4.2. Vollständiger Code für die AMP-Interrupt-Konfiguration

        Der Konfigurationscode von CPU0 lautet wie folgt:

//cpu0 main.c
#include <stdio.h>
#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");
}

         Der Konfigurationscode von CPU1 lautet wie folgt:

//cpu1 main.c
#include <stdio.h>
#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");
}

Supongo que te gusta

Origin blog.csdn.net/Learning1232/article/details/134200443
Recomendado
Clasificación