ZYNQ-多中断控制

本文详细介绍了ZYNQ处理器的中断系统,包括PPI私有中断、SGI软件中断和SPI共享中断,并探讨了通用中断控制器GIC的角色。通过实例展示了如何配置和初始化PS端的UART中断及DMA中断,以及如何在LwIp回环历程中整合串口。重点在于多个中断的管理和中断控制器的使用,为实际项目提供了参考。
摘要由CSDN通过智能技术生成

前言

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

ZYNQ中断

在这里插入图片描述

中断分类

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

PPI 私有中断

每个CPU都有私有中断,PPI包括全局计时器、私人监督计时器、私人计时器和来自PL的FIQ/IRQ。下表是PPI的ID:
在这里插入图片描述

SGI 软件中断

软件生成的中断被路由到一个或者两个CPU中,如下表所示是SGI的中断ID:
在这里插入图片描述

SPI 共享中断

共享的外设中断(SPI)是由PS和PL中的各种I/O和内存控制器生成的,它们被路由到其中一个或两个cpu。来自PS外设的SPI中断也被路由到PL。如下表所示是SPI的中断ID:
在这里插入图片描述
在这里插入图片描述

GIC 通用中断控制器

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

从中断的结构图中可以大概理解中断可以给到不同的CPU去处理,至于代码是如何实现的就在中断初始化的代码中。
在这里插入图片描述

举例

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

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

基本配置

在这里插入图片描述

在这里插入图片描述

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 <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年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 <stdio.h>


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),将接受的数据发送给串口。
在这里插入图片描述

### 回答1: UG585-Zynq-7000-TRM是一份关于Xilinx Zynq-7000 SoC处理器的技术参考手册。Zynq-7000 SoC处理器是一款配备ARM Cortex-A9双核处理器和Xilinx可编程逻辑部分(PL)的可扩展平台,旨在为嵌入式系统开发者提供卓越的灵活性和可编程性。 TRM代表Technical Reference Manual(技术参考手册),其中包含了该处理器的体系结构和功能特性的详细描述,包括处理器内部的各种模块、外设、总线结构等等。该手册的主要目的是为开发者提供全面的指导和支持,从而加速其系统设计和开发应用,减少错误和风险。 UG585-Zynq-7000-TRM手册的内容包括Zynq-7000的基本特征、处理器硬件和软件架构、可编程逻辑PL和PS之间的通信、外设接口和寄存器映射、中断控制等内容。开发者可以根据手册中的详细说明,了解Zynq-7000的构成和功能,从而基于此设计和实现自己的应用。 总之,UG585-Zynq-7000-TRM手册是一份非常重要的技术参考资料,为开发者提供全面的指导和支持,促进了Zynq-7000处理器的应用和拓展,也为未来的嵌入式系统设计提供了参考和借鉴。 ### 回答2: UG585是Xilinx公司发布的Zynq-7000系列技术手册,全称为“Zynq-7000 All Programmable SoC Technical Reference Manual”。Zynq-7000系列是Xilinx公司推出的一款功能强大的FPGA芯片,集成了双核ARM Cortex-A9处理器和可编程逻辑资源,支持高性能中间件、操作系统和外围设备的支持。该手册详细介绍了Zynq-7000系列SoC的架构、功能、性能、测试和验证、软件和硬件开发等方面的知识。他对于学习、使用和开发Zynq-7000 SoC具有非常重要的意义,使得开发人员能够深入了解这个芯片的细节,掌握它的特性和功能,以便更加高效地使用它进行开发。如果你想要学习和使用Zynq-7000 SoC,UG585是一个非常重要的参考文献,值得认真阅读和研究。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘉鑫的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值