preface
I found that many explanations are about how to realize the control of a single interrupt, but there is basically no explanation of multiple interrupts.
ZYNQ interrupt
Interrupt classification
Interrupts are divided into three categories
1) PPI private interrupt
2) SGI software interrupt
3) SPI share interrupt
PPI private interrupt
Each CPU has private interrupts. PPI includes global timer, private supervision timer, private timer and FIQ/IRQ from PL. The following table is the ID of PPI:
SGI software interrupt
The software generated interrupt is routed to one or two CPU s. The following table shows the interrupt ID of SGI:
SPI share interrupt
Shared peripheral interrupts (SPI) are generated by various I/O and memory controllers in PS and PL, which are routed to one or two CPUs. SPI interrupts from PS peripherals are also routed to pl. The following table shows the interrupt ID of SPI:
GIC general interrupt controller
The general interrupt controller (GIC) is a centralized resource for managing interrupts sent from PS and PL to the CPU. The controller enables, disables, masks and prioritizes the interrupt source, and sends them programmatically to the selected CPU (or CPU) when the CPU interface accepts the next interrupt. In addition, the controller supports the security extension of the security aware system.
From the interrupt structure diagram, it can be roughly understood that interrupts can be processed by different CPU s. How the code is implemented is in the interrupt initialization code.
give an example
Use the DMA interrupt and port of PS terminal to accept the interrupt
The basic theoretical knowledge of DMA and serial port will not be explained, which is not the focus of this article
Basic configuration
PS_UART initialization and interrupt initialization
/* * uart.h * * Created on: 2021 November 19 * Author: heiheiの */ #ifndef SRC_UART_H_ #define SRC_UART_H_ #include "xstatus.h" #include "xuartps.h" #include "xscugic.h" #include "stdio.h" #define UART_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID // Serial port device ID #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID // Interrupt ID #define UART_INT_IRQ_ID XPAR_XUARTPS_0_INTR // Serial port interrupt ID #define BAUD_UARTPS 115200 #define BUFFER_SIZE 8 #define BUFFER_SZE 100 extern u8 SendBuffer[BUFFER_SZE]; extern u8 RecvBuffer[BUFFER_SZE]; int Uart_Init(XUartPs *UartInstPtr); int Uart_Intr_Init(XScuGic *IntcInstancePtr,XUartPs *UartInstPtr); void uart_intr_handler(void *call_back_ref); #endif /* SRC_UART_H_ */
/* * uart.c * * Created on: 2021 November 19 * Author: heiheiの */ #include "uart.h" #include "ps_dma.h" #include "sleep.h" extern u8 uart_send[512]; extern u8 recv_total_byte; int Uart_Init(XUartPs *UartInstPtr){ XUartPs_Config *Config; int status; //Get device base address Config = XUartPs_LookupConfig(UART_DEVICE_ID); if (NULL == Config) { return XST_FAILURE; } //Device driver instance initialization status = XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress); if (status != XST_SUCCESS) { printf("Config Uart fail\r\n"); return XST_FAILURE; } status=XUartPs_SelfTest(UartInstPtr); if (status != XST_SUCCESS) { print("Self test Fail\r\n"); return XST_FAILURE; } //set baud rate XUartPs_SetBaudRate(UartInstPtr,BAUD_UARTPS); //Setting mode XUartPs_SetOperMode(UartInstPtr,XUARTPS_OPER_MODE_NORMAL); XUartPs_SetFifoThreshold(UartInstPtr,32); XUartPs_SetRecvTimeout(UartInstPtr,4); XUartPs_SetInterruptMask(UartInstPtr, XUARTPS_IXR_RXOVR|XUARTPS_IXR_TOUT); return XST_SUCCESS; } int Uart_Intr_Init(XScuGic *IntcInstancePtr,XUartPs *UartInstPtr){ u32 status; XScuGic_Config *IntcConfig; XScuGic_Disable(IntcInstancePtr,UART_INT_IRQ_ID); IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); status=XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); //Register exception callback function Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, IntcInstancePtr); //Enable exception callback Xil_ExceptionEnable(); //Set serial port receive interrupt priority XScuGic_SetPriorityTriggerType(IntcInstancePtr,UART_INT_IRQ_ID,32,1); XScuGic_Connect(IntcInstancePtr, UART_INT_IRQ_ID, (Xil_ExceptionHandler)uart_intr_handler, (void *) UartInstPtr); XScuGic_Enable(IntcInstancePtr,UART_INT_IRQ_ID); Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); return XST_SUCCESS; } void uart_intr_handler(void *call_back_ref) { XUartPs *InstancePtr=(XUartPs *)call_back_ref; u32 IsrStatus; u32 ReceivedCount; IsrStatus = XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_IMR_OFFSET); IsrStatus &= XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET); if (IsrStatus & ((u32)XUARTPS_IXR_RXOVR)){ XUartPs_WriteReg(InstancePtr->Config.BaseAddress,XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR) ; ReceivedCount=XUartPs_Recv(InstancePtr,&uart_send[recv_total_byte],500); recv_total_byte+=ReceivedCount; printf("uart_send1:%s\r\n",uart_send); } else if(IsrStatus & ((u32)XUARTPS_IXR_TOUT)){ XUartPs_WriteReg(InstancePtr->Config.BaseAddress,XUARTPS_ISR_OFFSET, XUARTPS_IXR_TOUT) ; ReceivedCount=XUartPs_Recv(InstancePtr,&uart_send[recv_total_byte],500); recv_total_byte+=ReceivedCount; printf("uart_send1:%d\r\n",ReceivedCount); for(int i=0;i<recv_total_byte;i++) XUartPs_SendByte(STDOUT_BASEADDRESS,uart_send[i]); recv_total_byte=0; } }
DMA initialization and interrupt functions
/* * ps_dam.h * * Created on: 2021 November 17 * Author: heiheiの */ #ifndef SRC_PS_DMA_H_ #define SRC_PS_DMA_H_ #include "xdmaps.h" #include <stdlib.h> #include "xscugic.h" #include "xuartps_hw.h" #include <stdio.h> #define DMA_DEVIEC_ID XPAR_XDMAPS_1_DEVICE_ID #define DMA_INT_DEVIEC_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define DMA0_INT_ID XPS_DMA0_INT_ID #define DMA1_INT_ID XPS_DMA1_INT_ID #define DMA2_INT_ID XPS_DMA2_INT_ID #define DMA3_INT_ID XPS_DMA3_INT_ID #define DMA4_INT_ID XPS_DMA4_INT_ID #define DMA5_INT_ID XPS_DMA5_INT_ID #define DMA6_INT_ID XPS_DMA6_INT_ID #define DMA7_INT_ID XPS_DMA7_INT_ID #define DMA_FAULT_INTR XPAR_XDMAPS_0_FAULT_INTR #define DMA_LENGTH 5 int PsDMA_Init(XDmaPs *DmaInstance,XDmaPs_Cmd *DmaCmd,void *Src,void *Dst); int PsDMA_Intr_Init(XDmaPs *DmaInstance,XScuGic *GicPtr); void IntcTypeSetup(XScuGic *InstancePtr,int intld,int intType); #endif /* SRC_PS_DMA_H_ */
/* * ps_dma.c * * Created on: 2021 November 17 * Author: heiheiの */ #include "ps_dma.h" int PsDMA_Init(XDmaPs *DmaInstance,XDmaPs_Cmd *DmaCmd,void *Src,void *Dst) { XDmaPs_Config *DmaCfg; u32 status=XST_SUCCESS; memset(DmaCmd,0,sizeof(XDmaPs_Cmd)); DmaCmd->ChanCtrl.DstBurstLen=1; //Source release DmaCmd->ChanCtrl.DstBurstSize=1; //Source release length DmaCmd->ChanCtrl.DstInc=1; //Incremental or fixed address of the source DmaCmd->ChanCtrl.SrcBurstLen=1; // Target release DmaCmd->ChanCtrl.SrcBurstSize=1; // Destination release length DmaCmd->ChanCtrl.SrcInc=1; // Destination release incremental or fixed address DmaCmd->BD.SrcAddr=((u32)(Src)); DmaCmd->BD.DstAddr=((u32)Dst); DmaCmd->BD.Length=4; DmaCfg=XDmaPs_LookupConfig(DMA_DEVIEC_ID); if(DmaCfg == NULL) return XST_FAILURE; status=XDmaPs_CfgInitialize(DmaInstance,DmaCfg,DmaCfg->BaseAddress); if(status != XST_SUCCESS) return XST_FAILURE; return XST_SUCCESS; } int PsDMA_Intr_Init(XDmaPs *DmaInstance,XScuGic *GicPtr){ u32 status=XST_SUCCESS; XScuGic_Config *GicConfig; Xil_ExceptionInit(); //Device initialization GicConfig=XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID); if(NULL == GicConfig) return XST_FAILURE; status=XScuGic_CfgInitialize(GicPtr,GicConfig,GicConfig->CpuBaseAddress); if (status != XST_SUCCESS) return XST_FAILURE; //Hardware initialization Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, GicPtr); //Set channel 0 priority XScuGic_SetPriorityTriggerType(GicPtr,DMA0_INT_ID,160,1); //Connection interrupt handling function status = XScuGic_Connect(GicPtr,DMA0_INT_ID,(Xil_InterruptHandler)XDmaPs_DoneISR_0,(void *)DmaInstance); if (status != XST_SUCCESS) return XST_FAILURE; XScuGic_Enable(GicPtr, DMA0_INT_ID); Xil_ExceptionEnable(); return XST_SUCCESS; }
main.c function
#include "xparameters.h" #include "uart.h" #include "xil_printf.h" #include "stdio.h" #include "xil_types.h" #include "xil_assert.h" #include "xil_io.h" #include "xil_exception.h" #include "xil_cache.h" #include "ps_dma.h" #include "sleep.h" #include <stdio.h> u8 RecvBuffer[BUFFER_SZE]; //Receive data cache u8 SendBuffer[BUFFER_SZE]; //Send data cache u32 rec_data = 1 ; /*It should be noted here that only one interrupt control driver instance can be enabled, because there is only one interrupt control. If two cards are instantiated, they will be interrupted*/ XScuGic Intc; //Interrupt controller driver instance /*********************************************************************************/ XUartPs Uart_Ps; //Serial driver instance XDmaPs DmaInstance; static int Src[DMA_LENGTH]; static u8 Dst[DMA_LENGTH]; volatile int Checked[XDMAPS_CHANNELS_PER_DEV]; u8 uart_send[512]; u8 recv_total_byte; XDmaPs DmaXDmaps; XDmaPs_Cmd DmaCmd; //main function int main(void) { int status=XST_SUCCESS; int Index; recv_total_byte=0; status= Uart_Init(&Uart_Ps); print("RUN1\r\n"); status=Uart_Intr_Init(&Intc,&Uart_Ps);//Initialize serial port interrupt status=PsDMA_Init(&DmaXDmaps,&DmaCmd,&rec_data,&Dst); if(status!= XST_SUCCESS){ xil_printf("Error: XDMaPs_Example_W_Intr failed\r\n"); return XST_FAILURE; } status=PsDMA_Intr_Init(&DmaXDmaps,&Intc);//Initialize DMA interrupt for (Index = 0; Index < DMA_LENGTH; Index++) Src[Index] = DMA_LENGTH-Index; for (Index = 0; Index < DMA_LENGTH; Index++) Dst[Index] = 0; print("RUN\r\n"); while (1){ for (Index = 0; Index < DMA_LENGTH; Index++) { printf("Src[%d],Dst[%d]:%d\r\n",Src[Index],Index,Dst[Index]); } printf("rec_data:%d\r\n",(int)rec_data); XDmaPs_Start(&DmaXDmaps,0,&DmaCmd,0); printf("Is Life:%d\r\n",XDmaPs_IsActive(&DmaXDmaps,0)); rec_data++; sleep(2); //Delay 2s }; return status; }
When initializing an interrupt, remember to use the same interrupt controller driver instance, otherwise the card will be interrupted!
The serial port is added in the loopback process of LwIp
Import LwIp import history open platform_zynq.c file, in which TimerInstance is the interrupt controller driver instance of LwIp.
Therefore, you only need to fill in the modified instance during serial port interrupt initialization. There is no problem defining a new instance.
In the echo.c file, the red box part is the code to return the received data. Where p - > payload is the accepted data, and p-len represents the data length. You can use the memcpy function to copy the accepted data into an array to process the data. You can also add printf ("% s", P - > payload) here to send the received data to the serial port.