ZYNQ之中断机制

目录

一、中断简介

 二、中断寄存器

三、编程


一、中断简介

中断是一种当满足要求的突发事件发生时通知处理器进行处理的信号。中断可以由硬件处理单元和外部设备产生,也可以由软件本身产生。

对硬件来说,中断信号是一个由某个处理单元产生的异步信号,用来引起处理器的注意。对软件来说,中断是一种异步事件,用来通知处理器需要改变代码的执行。但是,轮询所产生的中断的过程是同步的。

当处理器收到中断,它会停下当前正在做的任务,然后跳转到需要处理的地方去。这和轮询的方式是相反的,轮询是由软件同步获取设备的状态。在中断方式中,不需要由处理器不断地轮询设备的 I/O 端口来查看是否需要处理,设备本身会中断处理器

中断(主要是硬件中断)可以进一步被分类为以下几种类型:

可屏蔽中断( Maskable Interrupts   IRQ):可通过在中断屏蔽寄存器中设定位掩码来闭。触发可屏蔽中断的事件源不总是重要的。程序设计人员需要决定该事件是否应该导致程序跳到所需处理的地方去。使用可屏蔽中断的设备包括定时器、比较器和 ADC

不可屏蔽中断( Non-Maskable Interrupts NMI):无法通过在中断屏蔽寄存器中设定位掩码来关闭。这些是不可忽视的中断。 NMI 的事件包括上电、外部重启和严重的设备失效。

处理器间中断( Inter-Processor Interrupts  IPI):在多处理器系统中,一个处理器可能需要中断另一个处理器的操作。在这种情况下,就会产生一个 IPI,以便于处理器间通信或同步。
 

 Zynq 芯片的 PS 部分是基于使用双核 Cortex-A9 处理器和 GIC pl390 中断控制器的 ARM 架构。中断结构与 CPU 紧密链接,并接受来自 I/O 外设( IOP)和可编程逻辑( PL)的中断。中断控制器架构如下图所示:

ZYNQ之中断机制_第1张图片

 从图中可以看出CPU 接收的中断来源有三种

①私有外设中断( private peripheral interrupts, PPI)

②软件生成的中断( software generated interrupts, SGI)

③共享外设中断( shared peripheral interrupts、 SPI)

系统级中断环境如下图

ZYNQ之中断机制_第2张图片

通用中断控制器是一个用于集中管理从 PS 和 PL 发送到 CPU 的中断,启用、禁用、屏蔽和优先化中断源的处理中心,将具有最高优先级的中断源分配给各个 CPU 之前集中所有中断源,并在 CPU 接口接受下一个中断时以编程方式将它们发送到选定的 CPU。

该控制器基于非矢量化的 ARM 通用中断控制器架构,GIC 寄存器通过 CPU 私有总线访问寄存器,以避免临时阻塞或互连中的瓶颈,从而实现快速读/写响应。GIC 确保针对多个 CPU 的中断一次只能由一个 CPU 占用。所有中断源都由唯一的中断 ID 号标识,对应有它自己的可配置优先级和目标 CPU 列表

所有的中断请求,无论是 PPI、 SGI 还是 SPI,都分配了一个唯一的 ID 编号,以用于中断控制器的仲裁。中断分派(配)器保存每个 CPU 的中断挂起列表,并从中选择优先级最高的中断,然后把它发送到 CPU 接口。如果具有相同优先级的两个中断同时到达,具有最低中断 ID 的会首先被发送。

每个 CPU 都存在着优先级定序逻辑,所以对最高优先级中断的选择是每个 CPU 各自进行的。中断分配器具有中断、处理器和活跃信息的中央列表,并负责触发 CPU 的软件中断。为了给每个处理器提供单独的副本, SGI 和 PPI 分派器寄存器是分组的。硬件确保针对多个 CPU 的中断同一时间只能被一个 CPU 获取

在发送挂起的最高优先级的中断给 CPU 接口后,中断分配器会从该 CPU 收到中断已被确认的消息,这样它就可以改变对应的中断的状态。只有确认中断的 CPU 才能结束该中断。
 

 二、中断寄存器

以GPIO MIO 的中断,了解ZYNQ的中断ZYNQ之中断机制_第3张图片寄存器。如下图所示

INT_MASK:该寄存器是只读的,显示哪些位当前被屏蔽,哪些位未被屏蔽/启用


INT_EN:向该寄存器的任何位写入 1,可以启用/解除中断信号的掩码


INT_DIS:向该寄存器的任何位写入 1 都会屏蔽该中断信号

INT_STAT:该寄存器显示是否发生了中断事件。将 1 写入该寄存器中的某个位可清除该位的中断状态。将 0 写入该寄存器中的某个位将被忽略。


INT_TYPE:该寄存器控制中断是边沿敏感还是电平敏感

INT_POLARITY:该寄存器控制中断是低电平有效还是高电平有效(或下降沿敏感或上升沿敏感)


INT _ANY:如果 INT_TYPE 设置为边沿敏感, 则该寄存器在上升沿和下降沿都会启用中断事件。如果INT_TYPE 设置为电平敏感,则忽略该寄存器

下面三个寄存器INT_TYPE、 INT_POLARITY 和 INT _ANY 控制监视 GPIO 输入信号的中断检测逻辑。如果检测到中断,中断检测逻辑将 GPIO 的 INT_STAT 状态设置为真

如果中断未屏蔽,则中断传输到一个或电路。该或电路将四个 BANK 中所有 GPIO 的所有中断组合成一个输出( IRQ ID# 52)到中断控制器。如果中断被禁止(屏蔽),则 INT_STAT 状态将保持直到被清除,但它不会传输到中断控制器。

由于所有 GPIO 共享相同的中断,因此软件必须同时考虑 INT_MASK 和 INT_STAT 以确定哪个 GPIO 导致中断。可以通过读取 INT_STAT 和 INT_MASK 寄存器来推断进入中断控制器的中断信号的状态。如果INT_STAT = 1 且 INT_MASK = 0,则该中断信号有效

通过向 INT_EN 和 INT_DIS 寄存器写入 1 来控制中断屏蔽状态。向 INT_EN 寄存器写入 1 将禁用屏蔽,允许活动中断传输到中断控制器。将 1 写入 INT_DIS 寄存器可启用屏蔽。可以使用INT_MASK 寄存器读取中断屏蔽的状态。

如果 GPIO 中断是边沿触发的,则 INT 状态由检测逻辑锁存。通过向 INT_STAT 寄存器写入 1 来清除INT 锁存器。对于电平触发的中断,必须清零 GPIO 中断输入源,以清除中断信号

在使用vitis编程时,并不需要操作这些寄存器,只需要调用相应的库函数即可。

三、编程

对于熟悉STN32或者ARM开发的人来说,中断经常用到的。一般按键在32开发时候的初始化的流程:

①使能相应的时钟

②配置GPIO管脚为中断功能

③设置中断优先级

④使能相应的中断

⑤实现中断服务程序

ZYNQ的中断初始化的设置流程(针对GPIO):

①初始化中断控制器

②初始化CPU异常功能、向CPU注册异常处理回调函数、使能异常处理功能

③使能中断控制器、设置中断的类型、使能对应引脚的中断

④设置中断的回调函数(用户自己设置)


#define INTC_DEVICE_ID      XPAR_SCUGIC_SINGLE_DEVICE_ID //通用中断控制器 ID
#define GPIO_INTERRUPT_ID   XPAR_XGPIOPS_0_INTR //PS 端 GPIO 中断 ID

XGpioPs gpio; //PS 端 GPIO 驱动实例
XScuGic intc; //通用中断控制器驱动实例
// @param GicInstancePtr 是一个指向 XScuGic 驱动实例的指针
// @param gpio 是一个指向连接到中断的 GPIO 组件实例的指针
// @param GpioIntrId 是 Gpio 中断 ID
// @return 如果成功返回 XST_SUCCESS, 否则返回 XST_FAILURE
int int_init(XScuGic *gic_ins_ptr, XGpioPs *gpio, u16 GpioIntrId)
{
	int status;
	XScuGic_Config *IntcConfig; //中断控制器配置信息

	//查找中断控制器配置信息并初始化中断控制器驱动
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig)
	{
		return XST_FAILURE;
	}
	status = XScuGic_CfgInitialize(gic_ins_ptr, IntcConfig,IntcConfig->CpuBaseAddress);
	if (status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	//初始化异常处理
	Xil_ExceptionInit();
	//CPU中断异常注册
	 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler, gic_ins_ptr);
	 //使能处理器中断
	 Xil_ExceptionEnable();
    
    //为中断设置中断处理函数
	 status = XScuGic_Connect(gic_ins_ptr, GpioIntrId,(Xil_ExceptionHandler) intr_handler,gpio);
	 if (status != XST_SUCCESS)
	 {
		 return status;
	 }


	 //使能来自于 Gpio 器件的中断
	 XScuGic_Enable(gic_ins_ptr, GpioIntrId);
	 //设置 KEY 按键的中断类型为下降沿中断
	 XGpioPs_SetIntrTypePin(gpio, KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
	 //使能按键 KEY 中断
	 XGpioPs_IntrEnablePin(gpio, KEY);
 
	 return XST_SUCCESS;
}

//中断处理函数
// @param CallBackRef 是指向上层回调引用的指针
static void intr_handler(void *callback_ref)
{
	XGpioPs *gpio = (XGpioPs *) callback_ref;

	//读取 KEY 按键引脚的中断状态,判断是否发生中断
	if (XGpioPs_IntrGetStatusPin(gpio, KEY))
	{
		...中断处理
		XGpioPs_IntrClearPin(gpio, KEY); 
	}
}

一般中断发生后还有清除中断,等待下次中断触发,XGpioPs_IntrClearPin()。 

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