ZYNQ-多中断控制

前言

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

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的回环历程中加入串口

导入LwIp导入历程打开platform_zynq.c文件,其中的TimerInstance,就是LwIp的中断控制器驱动实例。
在这里插入图片描述
所以只需要在串口中断初始化的时候填写上改实例就行了,不要在定义一个新的实例就没有问题。

在echo.c文件,其中红方框部分就是实现回环的代码将接受到的数据返回。其中的p->payload就是接受的数据,p-len表示数据长度。可以使用memcpy函数将接受的数据拷贝进一个数组中处理数据。也可以在这加printf("%s",p->payload),将接受的数据发送给串口。
在这里插入图片描述

版权声明:本文为CSDN博主「嘿嘿の」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43460106/article/details/121719177

生成海报
点赞 0

嘿嘿の

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

最简单DIY基于51单片机的舵机控制器

51单片机物联网智能小车系列文章目录 第一篇:最简单DIY的51蓝牙遥控小车设计方案 第二篇:最简单DIY串口蓝牙硬件实现方案 第三篇:最简单DIY蓝牙PS2遥控器控制蓝牙智能小车 第四篇&#xff1a

STM32控制启动步进电机

概述 正在做的项目需要用STM32控制步进电机,本篇主要讲解利用STM32定时器外设输出脉冲来控制步进电机转动。 STM32定时器 使用STM32芯片类型:STM32c8t6。 使用外设接口:选

STM32 C++编程系列一:STM32 C++编程介绍

一、STM32及其他单片机开发现状 在目前绝大部分的单片机开发当中,C语言占据着主流的地位,但由于C语言本身是一种面向过程的语言,因此在当前利用面向对象思想构建可复用代码为主流的今天显得比较麻烦&#x

六种电平转换的优缺点

作为一名电子设计的硬件工程师,电平转换是每个人都必须面对的的话题,主芯片引脚使用的1.2V、1.8V、3.3V等,连接外部接口芯片使用的1.8V、3.3V、5V等,由于电平不匹配就必须进行