ZYNQ的中断框图:
ZYNQ使用两个cortex-A9处理器(CPU)以及GIC(Generic Interrupt Controller) 中断控制器。可以接收来自I/O外设和PL部分的中断,中断主要分为私有外设中断PPI(private peripheral interrupts)、软件生成中断SGI(software generated interrupts) 和共享外设中断SPI(shared peripheral interrupts)。
而所有中断请求(PPI、SGI、SPI)都分配了唯一的ID号,中断控制器通过仲裁ID号,选择中断优先级最高的中断,将其发送给CPU接口。中断优先级相同则选择ID号小的中断。
如果中断和多个CPU有关,SGI和PPI寄存器为每个CPU提供了独立的副本。
GIC管理从PS和PL端发送到CPU的中断:
三种中断源:
(1)每个CPU都有一组私有外设中断,PPI,这些中断使用存储寄存器进行私有访问。PPI包括全局定时器、私有看门狗定时器、私有定时器和来自PL端的FIQ/IRQ 五种外设,中断ID为27-31
(2)软件生成中断SGI,通过写入GIC的寄存器ICDSGIR,并设置目标CPU来产生软件中断,每个CPU都可以产生16个软件中断,中断号为0-15;
(3)共享外设中断SPI由PS和PL中的各种I/O和内存控制器产生,共有60个;共享中断就是PL的中断可以发送给PS进行处理,如下图所示,黄色区域就是16个PL的中断,它们可以设置为高电平或者低电平触发。
步骤:
(1)creat block design ->配置ps端(时钟和DDR,uart 以及使能中断)
(2)添加两个逻辑门(Vector)和concat IP
(3)将逻辑门配置成1位宽且非门
(4)按照下图连接IP,并将门的外部引脚换成SW开关
(5)generate output product ->creat HDL Wrapper
(6)添加开关约束,并生成bit流文件
(7)将硬件信息发送到SDK,并且创建main.c函数
#include <stdio.h>
#include "xscugic.h"
#include "xil_exception.h"
#define INT_CFG0_OFFSET 0x00000C00
// Parameter definitions
#define SW1_INT_ID 61 //中断ID号
#define SW2_INT_ID 62
#define SW3_INT_ID 63
#define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //Definitions for peripheral PS7_SCUGIC_0
#define INT_TYPE_RISING_EDGE 0x03
#define INT_TYPE_HIGHLEVEL 0x01
#define INT_TYPE_MASK 0x03
static XScuGic INTCInst;
static void SW_intr_Handler(void *param); //中断处理函数
static int IntcInitFunction(u16 DeviceId); //初始化
static void SW_intr_Handler(void *param)//将传递进来的指针传递给sw_id,然后会打印哪个按钮,即中断触发。
{
int sw_id = (int)param;
printf("SW%d int\n\r", sw_id);
}
void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType)
{
int mask;
intType &= INT_TYPE_MASK;
mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4);
mask &= ~(INT_TYPE_MASK << (intId%16)*2);
mask |= intType << ((intId%16)*2);
XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask);
}
int IntcInitFunction(u16 DeviceId)
{
XScuGic_Config *IntcConfig;
int status;
// Interrupt controller initialisation
IntcConfig = XScuGic_LookupConfig(DeviceId);
status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress);
if(status != XST_SUCCESS) return XST_FAILURE;
// Call to interrupt setup
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&INTCInst);
Xil_ExceptionEnable();
// Connect SW1~SW3 interrupt to handler
status = XScuGic_Connect(&INTCInst,
SW1_INT_ID,
(Xil_ExceptionHandler)SW_intr_Handler,
(void *)1);
if(status != XST_SUCCESS) return XST_FAILURE;
status = XScuGic_Connect(&INTCInst,
SW2_INT_ID,
(Xil_ExceptionHandler)SW_intr_Handler,
(void *)2);
if(status != XST_SUCCESS) return XST_FAILURE;
status = XScuGic_Connect(&INTCInst,
SW3_INT_ID,
(Xil_ExceptionHandler)SW_intr_Handler,
(void *)3);
if(status != XST_SUCCESS) return XST_FAILURE;
// Set interrupt type of SW1~SW3 to rising edge
IntcTypeSetup(&INTCInst, SW1_INT_ID, INT_TYPE_RISING_EDGE);
IntcTypeSetup(&INTCInst, SW2_INT_ID, INT_TYPE_RISING_EDGE);
IntcTypeSetup(&INTCInst, SW3_INT_ID, INT_TYPE_RISING_EDGE);
// Enable SW1~SW3 interrupts in the controller
XScuGic_Enable(&INTCInst, SW1_INT_ID);
XScuGic_Enable(&INTCInst, SW2_INT_ID);
XScuGic_Enable(&INTCInst, SW3_INT_ID);
return XST_SUCCESS;
}
int main(void)
{
print("PL int test\n\r");
IntcInitFunction(INTC_DEVICE_ID);
while(1);
return 0;
}