1-2 SDK Interrupt 测试

前言

  • 本日记记录使用中断的过程,以GPIO Interrupt Demo记录中断使用流程

PL 对 PS中断

在这里插入图片描述

IRQ NAMEIRQ NumberBitsRequired TypeDescription
PL_PS_Group0121:1287,8rising edge/high levelPL to PS interrupt signals 0 to 7.(3)
PL_PS_Group1136:1438rising edge/high levelPL to PS interrupt signals 8 to 15.(3)
  • ZCU106开发版对应的SOC支持两组PL to PS中断(共16个中断)
    • group0: 中断号为121–128,8个中断
    • group1: 中断号为136–143,8个中断

如何使用

  • 如果使能了IRQ0:第一组PL to PS中断
    • PL端对PS端产生多个中断,默认从ID 121开始分配
    • 第一个中断的ID:121
    • 第一个中断的ID:122
    • …累加但第一组最大ID不超过128
  • 记录使用过一个中断的过程

流程

![[Pasted image 20250111174555.png]]

BD设计

参考这一部分第一篇日记链接: 1 使用EMIO

SDK设计

/*
 * emio-interrupt.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xgpiops.h"

#define printf xil_printf

#ifndef GPIO_DEVICE_ID
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#endif

#ifndef INTR_DEVICE_ID
#define INTR_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif

#define PL_KEY_INTR XPAR_XGPIOPS_0_INTR  // 可以设置为121,表示第一个中断ID
// #define PL_KEY1_INTR  XPAR_XGPIOPS_0_INTR+1   // 如果是有两个中断,表示中断ID 加 1就行,三个四个也是如此

// PL端GPIO从78号开始,顺序分配就行,与VIVADO中进行的引脚约束的顺序无关
#define PL_LED   (78)  /* The pin connected to the LED */
#define PL_KEY   (79)  /* The pin connected to the pushbutton sw14 */
 
XGpioPs Gpio;
XScuGic Intc;

int IntrInitFunction(XScuGic *instancePtr, u16 DeviceId, XGpioPs *instanceGpio);
void GpioHandler(void *CallBackRef);

int count = 0;
int led_status = 0;

int main()
{
    int Status;
    /*
        * Initialize the GPIO
        */
    printf("Begin initial GPIO\n\r");
    XGpioPs_Config *ConfigPtr;
    ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
    if (ConfigPtr == NULL) {
        return XST_FAILURE;
    }
    Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
        * Set the direction for the LED pin to be an output
        * Set the output enable for the LED pin
        * Set the initial calue for the LED pin to be off
    */
    XGpioPs_SetDirectionPin(&Gpio, PL_LED, 1);
    XGpioPs_SetOutputEnablePin(&Gpio, PL_LED, 1);
    XGpioPs_WritePin(&Gpio, PL_LED, 0);

    /*
     * Set the direction for the PL_KEY pin to be an input
     * Set the interrupt type rising for the PL_KEY pin
     * Set the interrupt enable for the PL_KEY pin
     */
    XGpioPs_SetDirectionPin(&Gpio, PL_KEY, 0);
    XGpioPs_SetIntrTypePin(&Gpio, PL_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);  // 设置输入IO为中断类型
    XGpioPs_IntrEnablePin(&Gpio, PL_KEY);								   // 使能
    printf("End initial GPIO\n\r");

    Status = IntrInitFunction(&Intc, INTR_DEVICE_ID, &Gpio);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }
    return 0;
}

/* 初始化并建立中断函数 */
int IntrInitFunction(XScuGic *instancePtr, u16 DeviceId, XGpioPs *instanceGpio)
{
    int status;
    XScuGic_Config *IntrConfig;
    IntrConfig = XScuGic_LookupConfig(INTR_DEVICE_ID);
    if (IntrConfig == NULL) {
        return XST_FAILURE;
    }

    status = XScuGic_CfgInitialize(instancePtr, IntrConfig, IntrConfig->CpuBaseAddress);
    if (status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    XScuGic_SetPriorityTriggerType(instancePtr, PL_KEY_INTR, 0x10, 0x1); /* set pl_key failing sensitive*/

    status = XScuGic_Connect(instancePtr, PL_KEY_INTR, (Xil_InterruptHandler)GpioHandler, (void *)instanceGpio);
    if (status != XST_SUCCESS) {
        return XST_FAILURE;
    }


    XScuGic_Enable(instancePtr, PL_KEY_INTR);

    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, instancePtr);
    Xil_ExceptionEnable();

    return XST_SUCCESS;
}

void GpioHandler(void *CallBackRef)
{
    XGpioPs *GpioPtr = (XGpioPs *)CallBackRef;
    int key_value = XGpioPs_IntrGetStatusPin(GpioPtr, PL_KEY);
    if ((key_value))
    {   
        printf("get interrupt counts: %d \r\n", count);
        XGpioPs_WritePin(GpioPtr, PL_LED, led_status);
        led_status = ~led_status;
        count += 1;
    }
    XGpioPs_IntrClearPin(GpioPtr, PL_KEY);
}


  • 关与XScuGic_SetPriorityTriggerType(instancePtr, PL_KEY_INTR, 0x10, 0x1); /* set pl_key failing sensitive*/函数
    在这里插入图片描述

    • 第一个参数:中断实例化指针
    • 第二个参数:中断ID, 这里就是PL_KEY_INTR对应的宏定义ID号就是121
    • 第三个参数:中断优先级,只能值8的整数倍,越小优先级越高
    • 第三个参数:中断触发类型
      • 0x01: 高电平触发
      • 0x11: 上升沿触发
  • 关于XScuGic_Connect(instancePtr, PL_KEY_INTR, (Xil_InterruptHandler)GpioHandler, (void *)instanceGpio);函数

    • 在这里插入图片描述
    • 第一个参数:中断实例化指针
    • 第二个参数:中断ID, 这里就是PL_KEY_INTR对应的宏定义ID号就是121
    • 第三个参数:中断回调函数,这里的函数名就是GpioHandler,(Xil_InterruptHandler)是一个指针类型进行类型转换
    • 第三个参数:中断回调参考实例,可以是中断实例化指针,但一般是需要中断回调函数中使用的实例化指针
  • 关于回调函数GpioHandler

    void GpioHandler(void *CallBackRef)
    {
        XGpioPs *GpioPtr = (XGpioPs *)CallBackRef;
        int key_value = XGpioPs_IntrGetStatusPin(GpioPtr, PL_KEY);
        if ((key_value))
        {   
            printf("get interrupt counts: %d \r\n", count);
            XGpioPs_WritePin(GpioPtr, PL_LED, led_status);  /* 控制LED状态变化 */
            led_status = ~led_status;
            count += 1;
        } 
        XGpioPs_IntrClearPin(GpioPtr, PL_KEY);             /* 清除中断 */
    }
    
    • 参数:固定格式,对应的就是XScuGic_Connect第三个参数:中断回调参考实例,可以是中断实例化指针,但一般是需要中断回调函数中使用的实例化指针
    • 获得按键的值
    • 执行对应的操作
    • 清除中断,便于下次中断触发
    • 关于XGpioPs_IntrGetStatusPin函数,就是封装的读对应GPIO寄存器的值 ,只是进行了一些封装使读写更加安全。在这里插入图片描述
  • 关于异常

        Xil_ExceptionInit();
        Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, instancePtr);
        Xil_ExceptionEnable();
    
    • 需要初始化并设置 ARM 处理器的异常处理功能。
    • ARM 处理器支持 7种异常情况:复位、未定义指令、软件中断、指令预取中止、数据中止、中断请求(IRQ)和快速中断请求(FIQ)。
    • ARM 处理器支持的每种异常也都有自己的 ID 标识,其中 XIL_EXCEPTION_ID_INT 用于标识中断请求(IRQ)异常。
    • 通 过 调 用 函 数 Xil_ExceptionRegisterHandler( XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler, &scugic_inst )来给 IRQ 异常注册处理程序,它会将中断控制器 GIC 的中断处理程序与 ARM 处理器中的硬件中断处理逻辑连接起来。
    • 另外还要通过 Xil_ExceptionEnable()函数使能 IRQ 异常。
### Zynq PL-PS 中断配置及处理方法 #### 1. 中断源的定义与分类 Zynq SoC 支持多种类型的中断,其中 PL(可编程逻辑)可以通过特定机制向 PS(处理器系统)发送中断请求。这些中断分为共享中断和私有外设中断 (PPI)[^3]。 - **共享中断**: PL 提供多达 16 个中断线,用于支持各种 IP 核的中断需求。常见的 AXI_IP 如 `axi_ethernet`、`axi_uart` 和 `axi_pcie` 都通过这种方式触发中断[^2]。中断 ID 范围为 61-68 和 84-91,共计 16 个中断编号[^4]。 - **私有外设中断 (PPI)**: 每个 CPU 核心拥有独立的 5 条 PPI 线路,主要用于核心内部设备的专用中断。 --- #### 2. 中断信号的传输路径 PL 的中断信号需经过硬件设计中的特殊模块传递至 PS: - 使用 Concat IP 核将多个并行中断信号聚合为单一串行信号,并将其连接到 ZYNQ 的 IRQ_F2P 接口。 - 在 Vivado 工具中完成硬件设计时,确保中断信号按顺序接入 Concat IP 核的输入端口 (`in0`, `in1`, ...)。这样可以自动分配对应的中断 ID。 --- #### 3. 中断配置的具体流程 以下是基于 Vivado 和 SDK 的典型配置过程: ##### 3.1 硬件设计阶段 在 Vivado 中创建项目并集成所需 IP 核: - 将目标 IP 核(如 `AXI_UartLite` 或其他带中断功能的 IP)加入设计。 - 创建一个 Concat IP 实例,将各 IP 的中断输出信号逐一连接到其输入端口。 - 设置 Concat 输出信号连接到 ZYNQ 块的 `IRQ_F2P` 输入端口。 示例代码片段展示如何在 Tcl 文件中自动化此操作: ```tcl set concat_ip [create_bd_cell -type ip -vlnv xilinx.com:ip:concat:4.1 concat_0] set_property -dict [list CONFIG.NUM_PORTS {N}] $concat_ip connect_bd_net [get_pins axi_uart/interrupt] [get_pins concat_0/In0] connect_bd_net [get_pins concat_0/dout] [get_pins zynq_block/IRQ_F2P] ``` ##### 3.2 软件开发阶段 在 Xilinx SDK 中编写驱动程序以初始化和响应中断: - 初始化中断控制器并通过调用 API 注册回调函数来捕获指定事件。 - 对于 ARM Cortex-A9 架构下的具体实现,通常会涉及 GIC(通用中断控制器)的操作。 以下是一个典型的 C/C++ 示例代码框架说明如何注册中断服务例程 (ISR) 并启动中断监听循环: ```c #include "xil_exception.h" #include "xscugic.h" XScuGic InterruptController; // 扰动控制实例声明 // 定义自定义 ISR 函数原型 void CustomInterruptHandler(void *CallBackRef); int main() { int Status; // 初始化扰动控制系统对象 Status = XScuGic_Initialize(&InterruptController, XPAR_SCUGIC_SINGLE_DEVICE_ID); if(Status != XST_SUCCESS){ return XST_FAILURE; } // 连接用户定义的 ISR 到具体的中断 ID 上 Status |= XScuGic_Connect(&InterruptController, INTERRUPT_ID_EXAMPLE, /* 替换实际使用的中断号 */ (Xil_ExceptionHandler)CustomInterruptHandler, NULL); // 启用全局以及单个中断线路使能位 XScuGic_Enable(&InterruptController, INTERRUPT_ID_EXAMPLE); while(1){} // 主进程保持运行状态等待外部事件发生 } // 用户定制化 ISR 功能体 void CustomInterruptHandler(void *CallBackRef){ // 插入业务逻辑... } ``` 上述代码展示了基本结构,但需要根据实际情况调整参数值如 `INTERRUPT_ID_EXAMPLE` 及相关资源地址等信息[^1]。 --- #### 4. 注意事项 为了保证系统的稳定性和可靠性,在实施过程中应注意以下几个方面: - 正确匹配硬件描述文件 (.hdf) 至软件工程环境; - 确认所有参与交互组件版本兼容性良好; - 测试期间充分验证每一路信道的功能表现是否正常工作无误报漏报现象存在; ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

啥都不会的研究昇

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值