ZYNQ-多中断控制

目录

  • 前言
  • ZYNQ中断
    • 中断分类
      • PPI 私有中断
      • SGI 软件中断
      • SPI 共享中断
    • GIC 通用中断控制器
  • 举例
    • 使用PS端的DMA中断和口接受中断
      • 基本配置
      • PS_UART初始化和中断初始化
      • DMA初始化和中断函数
      • main.c 函数
    • LwIp的回环历程中加入串口

前言

我发现很多的讲解都是单个中断的控制是如何实现的,但是基本没有多个中断的讲解。

ZYNQ中断

ZYNQ-多中断控制_第1张图片

中断分类

中断一共被分为三类
1)PPI 私有中断
2)SGI 软件中断
3)SPI 共享中断

PPI 私有中断

每个CPU都有私有中断,PPI包括全局计时器、私人监督计时器、私人计时器和来自PL的FIQ/IRQ。下表是PPI的ID:
ZYNQ-多中断控制_第2张图片

SGI 软件中断

软件生成的中断被路由到一个或者两个CPU中,如下表所示是SGI的中断ID:
ZYNQ-多中断控制_第3张图片

SPI 共享中断

共享的外设中断(SPI)是由PS和PL中的各种I/O和内存控制器生成的,它们被路由到其中一个或两个cpu。来自PS外设的SPI中断也被路由到PL。如下表所示是SPI的中断ID:
ZYNQ-多中断控制_第4张图片
ZYNQ-多中断控制_第5张图片

GIC 通用中断控制器

通用中断控制器(GIC)是一个集中的资源,用于管理从PS和PL发送到cpu的中断。控制器启用、禁用、掩码和对中断源的优先级,并在CPU接口接受下一个中断时以编程的方式将它们发送到选定的CPU(或CPU)。此外,该控制器支持于实现安全感知系统的安全扩展。

从中断的结构图中可以大概理解中断可以给到不同的CPU去处理,至于代码是如何实现的就在中断初始化的代码中。
ZYNQ-多中断控制_第6张图片

举例

使用PS端的DMA中断和口接受中断

DMA和串口的基本理论知识就不讲解了不是本篇的重点

基本配置

ZYNQ-多中断控制_第7张图片

ZYNQ-多中断控制_第8张图片

PS_UART初始化和中断初始化

/*
 * uart.h
 *
 * Created on: 2021年11月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    	//串口设备ID
#define INTC_DEVICE_ID     XPAR_SCUGIC_SINGLE_DEVICE_ID 	//中断ID
#define UART_INT_IRQ_ID    XPAR_XUARTPS_0_INTR          	//串口中断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年11月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;

	//获取设备基础地址
	Config = XUartPs_LookupConfig(UART_DEVICE_ID);
		if (NULL == Config) {
			return XST_FAILURE;
		}
	//设备驱动实例初始化
	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;
			}
	//设置波特率
	XUartPs_SetBaudRate(UartInstPtr,BAUD_UARTPS);
	//设置模式
	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);

	//注册异常回调函数
	Xil_ExceptionInit();

	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
					(Xil_ExceptionHandler) XScuGic_InterruptHandler,
					IntcInstancePtr);
	//使能异常回调
	Xil_ExceptionEnable();
	//设置串口接收中断优先级
	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初始化和中断函数

/*
 * ps_dam.h
 *
 *  Created on: 2021年11月17日
 *      Author: heiheiの
 */

#ifndef SRC_PS_DMA_H_
#define SRC_PS_DMA_H_
#include "xdmaps.h"
#include 
#include "xscugic.h"
#include "xuartps_hw.h"
#include 

#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年11月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; 	// 目的释放量
	DmaCmd->ChanCtrl.DstBurstSize=1;	// 目的释放长度
	DmaCmd->ChanCtrl.DstInc=1;			// 目的释放递增或固定地址
	DmaCmd->ChanCtrl.SrcBurstLen=1;		//源释放量
	DmaCmd->ChanCtrl.SrcBurstSize=1;	//源释放长度
	DmaCmd->ChanCtrl.SrcInc=1;			//源的递增或固定地址

	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();
	//设备初始化
	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;

	//硬件初始化
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
				     (Xil_ExceptionHandler)XScuGic_InterruptHandler,
				     GicPtr);
	//设置通道0优先级
	XScuGic_SetPriorityTriggerType(GicPtr,DMA0_INT_ID,160,1);
	//连接中断处理函数
	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 函数

#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 


u8 RecvBuffer[BUFFER_SZE];	//接收数据缓存

u8 SendBuffer[BUFFER_SZE];	//发送数据缓存

u32 rec_data = 1 ;

/*这里需要注意切记只能使能一个中断控制驱动实例,因为只有一个中断控制,如果实例化两个会卡中断*/
XScuGic Intc;              //中断控制器驱动程序实例
/*********************************************************************************/

XUartPs Uart_Ps;           //串口驱动程序实例

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函数
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);//初始化串口中断

    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);//初始化DMA中断

    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);	//延时2s
    };
    return status;
}

初始化中断的时候需要切记 必须使用同一个中断控制器驱动程序实例,不然会导致卡中断!

LwIp的回环历程中加入串口

1)打开platform_zynq.c文件,修改函数platform_setup_interrupts,将函数修改为:

void platform_setup_interrupts(XScuGic *IntcTimer){
	XScuGic_Config *IntcConfig;
	IntcConfig=XScuGic_LookupConfig(INTC_DEVICE_ID);
	XScuGic_CfgInitialize(IntcTimer,IntcConfig,IntcConfig->CpuBaseAddress);

	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			IntcTimer);
	Xil_ExceptionEnable();

	XScuGic_SetPriorityTriggerType(IntcTimer,TIMER_IRPT_INTR,16,1);

	XScuGic_Connect(IntcTimer,TIMER_IRPT_INTR,
			(Xil_ExceptionHandler)timer_callback,
			(void *)&TimerInstance);

	XScuGic_Enable(IntcTimer,TIMER_IRPT_INTR);

	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

}

2)在main.c中定义一个XScuGic IntcTimer变量,修改init_platform()函数里的platform_setup_interrupts函数修改后就可以正常使用。
3)在echo.c文件,其中红方框部分就是实现回环的代码将接受到的数据返回。其中的p->payload就是接受的数据,p-len表示数据长度。可以使用memcpy函数将接受的数据拷贝进一个数组中处理数据。也可以在这加printf(“%s”,p->payload),将接受的数据发送给串口。
ZYNQ-多中断控制_第9张图片

你可能感兴趣的:(ZYNQ,单片机,嵌入式)