ZYNQ(七)PL端的中断请求

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;
}

在这里插入图片描述

发布了54 篇原创文章 · 获赞 4 · 访问量 1036

猜你喜欢

转载自blog.csdn.net/buzhiquxiang/article/details/103555068