Vivado 18.3实战:在PYNQ-Z2上用AXI GPIO实现按键中断控制LED(附完整工程代码)

张开发
2026/4/18 19:48:41 15 分钟阅读

分享文章

Vivado 18.3实战:在PYNQ-Z2上用AXI GPIO实现按键中断控制LED(附完整工程代码)
Vivado 18.3实战在PYNQ-Z2上用AXI GPIO实现按键中断控制LED附完整工程代码在嵌入式系统开发中ZYNQ系列芯片的独特架构为开发者提供了灵活的设计空间。本文将带领读者完成一个完整的项目实战在PYNQ-Z2开发板上使用Vivado 18.3工具链通过AXI GPIO IP核实现按键中断控制LED的功能。这个项目不仅涉及PL可编程逻辑和PS处理系统的协同设计还涵盖了从硬件搭建到软件驱动的全流程开发。1. 项目概述与准备工作PYNQ-Z2是一款基于Xilinx ZYNQ-7000系列SoC的开发板它集成了双核ARM Cortex-A9处理器和Artix-7架构的可编程逻辑。在这个项目中我们将利用AXI GPIO IP核作为PS和PL之间的桥梁实现以下功能PL端的按键通过AXI GPIO IP核连接到PS按键按下时触发中断PS端响应中断并控制LED状态翻转开发环境准备清单Vivado 18.3设计套件PYNQ-Z2开发板及配套电源线Micro USB数据线用于JTAG调试和串口通信最新版PetaLinux或SDK工具链提示确保已正确安装Vivado 18.3和对应的板级支持包(BSP)PYNQ-Z2的约束文件可以从官方GitHub仓库获取。2. 硬件平台搭建2.1 创建Vivado工程启动Vivado 18.3按照以下步骤创建新工程选择Create Project向导指定工程名称和位置建议使用英文路径选择RTL Project类型添加PYNQ-Z2的板级描述文件完成工程创建# 创建工程的基本Tcl命令供参考 create_project axi_gpio_interrupt ./axi_gpio_interrupt -part xc7z020clg400-1 set_property board_part tul.com.tw:pynq-z2:part0:1.0 [current_project]2.2 构建Block Design在新建的工程中我们需要搭建一个包含ZYNQ处理系统和AXI GPIO IP核的Block Design创建Block Design并添加ZYNQ7 Processing System IP运行Block Automation保持默认配置添加AXI GPIO IP核并双击进行配置AXI GPIO关键配置参数参数项设置值说明GPIO Width1按键信号位宽Enable Interrupt勾选使能中断功能All Inputs勾选配置为输入模式2.3 中断连接与引脚分配完成IP核添加后需要手动连接中断信号将AXI GPIO的ip2intc_irpt端口连接到ZYNQ的IRQ_F2P[0:0]端口运行Connection Automation完成其余自动连接右键Block Design选择Generate Output Products创建HDL Wrapper引脚约束是确保设计正确工作的关键步骤。以下是PYNQ-Z2开发板的约束示例# 按键约束PL端 set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {axi_gpio_0_tri_io[0]}] # LED约束PS端EMIO set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {GPIO_0_tri_io[0]}]3. 软件驱动开发3.1 导出硬件到SDK硬件设计完成后需要生成比特流并导出到SDK环境综合、实现并生成比特流文件选择File Export Export Hardware包含比特流启动SDK工具3.2 创建应用工程在SDK中新建一个空白应用工程选择File New Application Project指定工程名称如axi_gpio_interrupt选择Empty Application模板完成工程创建3.3 中断服务程序实现以下是完整的按键中断控制LED的示例代码包含详细注释#include stdio.h #include xparameters.h #include xgpio.h #include xscugic.h #include xil_printf.h // 设备ID定义 #define AXI_GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define GPIO_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR // 全局变量声明 static XGpio axi_gpio; static XScuGic intc; volatile int interrupt_flag 0; // 中断服务函数 void gpio_handler(void *InstancePtr) { // 清除中断标志 XGpio_InterruptClear(axi_gpio, 1); interrupt_flag 1; } // 中断系统初始化 int init_interrupt_system() { XScuGic_Config *intc_cfg; int status; // 查找中断控制器配置 intc_cfg XScuGic_LookupConfig(INTC_DEVICE_ID); if (NULL intc_cfg) return XST_FAILURE; // 初始化中断控制器 status XScuGic_CfgInitialize(intc, intc_cfg, intc_cfg-CpuBaseAddress); if (status ! XST_SUCCESS) return XST_FAILURE; // 设置中断优先级和触发类型 XScuGic_SetPriorityTriggerType(intc, GPIO_INTERRUPT_ID, 0xA0, 0x3); // 连接中断处理程序 status XScuGic_Connect(intc, GPIO_INTERRUPT_ID, (Xil_ExceptionHandler)gpio_handler, axi_gpio); if (status ! XST_SUCCESS) return XST_FAILURE; // 使能中断 XScuGic_Enable(intc, GPIO_INTERRUPT_ID); // 初始化异常处理 Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, intc); Xil_ExceptionEnable(); return XST_SUCCESS; } // GPIO初始化 int init_gpio() { int status; // 初始化AXI GPIO status XGpio_Initialize(axi_gpio, AXI_GPIO_DEVICE_ID); if (status ! XST_SUCCESS) return XST_FAILURE; // 设置GPIO方向为输入 XGpio_SetDataDirection(axi_gpio, 1, 0x1); // 使能GPIO中断 XGpio_InterruptEnable(axi_gpio, 1); XGpio_InterruptGlobalEnable(axi_gpio); return XST_SUCCESS; } int main() { int status; u32 led_state 0; xil_printf(AXI GPIO Interrupt Example Start\n\r); // 初始化GPIO status init_gpio(); if (status ! XST_SUCCESS) { xil_printf(GPIO Initialization Failed\n\r); return XST_FAILURE; } // 初始化中断系统 status init_interrupt_system(); if (status ! XST_SUCCESS) { xil_printf(Interrupt System Initialization Failed\n\r); return XST_FAILURE; } xil_printf(System Ready. Press the button...\n\r); while (1) { if (interrupt_flag) { // LED状态翻转 led_state ~led_state; XGpio_DiscreteWrite(axi_gpio, 1, led_state); xil_printf(Button Pressed! LED State: %d\n\r, led_state 0x1); // 重置中断标志 interrupt_flag 0; // 重新使能中断 XGpio_InterruptEnable(axi_gpio, 1); } } return XST_SUCCESS; }4. 调试与优化技巧4.1 常见问题排查在实现AXI GPIO中断功能时开发者常会遇到以下问题中断未触发检查AXI GPIO IP核的中断使能是否勾选确认中断信号线是否正确连接验证中断ID是否与硬件设计匹配中断频繁触发确保在中断服务程序中正确清除了中断状态检查按键硬件消抖电路或添加软件消抖逻辑PS端无响应确认比特流文件已正确下载检查SDK工程是否使用了正确的硬件平台描述文件4.2 性能优化建议对于需要快速响应的中断应用可以考虑以下优化措施在XScuGic_SetPriorityTriggerType中设置更高的中断优先级精简中断服务程序只保留必要的操作对于实时性要求高的应用考虑使用PL端的中断控制器// 设置更高优先级的中断示例 XScuGic_SetPriorityTriggerType(intc, GPIO_INTERRUPT_ID, 0xE0, 0x3);4.3 扩展功能实现基于当前工程可以进一步扩展以下功能多按键支持修改AXI GPIO位宽为多个位在中断服务程序中读取具体哪个按键被按下中断共享多个AXI GPIO IP核共享同一个中断线在中断服务程序中查询中断源PL端逻辑增强在PL端添加按键消抖逻辑实现按键长短按识别5. 工程源码结构与使用说明完整的Vivado工程和SDK源代码已打包包含以下关键文件axi_gpio_interrupt/ ├── vivado/ │ ├── axi_gpio_interrupt.xpr # Vivado工程文件 │ ├── constraints/ # 约束文件目录 │ │ └── pynq-z2.xdc # PYNQ-Z2引脚约束 │ └── src/ # 源代码目录 │ └── bd/ # Block Design文件 ├── sdk/ # SDK工程目录 │ ├── axi_gpio_interrupt/ # 应用工程 │ │ ├── src/ # 源代码 │ │ │ └── main.c # 主程序文件 │ │ └── Debug/ # 编译输出 │ └── hardware_platform/ # 硬件平台描述 └── README.md # 使用说明工程使用步骤在Vivado 18.3中打开axi_gpio_interrupt.xpr工程生成比特流并导出硬件到SDK在SDK中导入现有工程连接PYNQ-Z2开发板并下载程序通过串口终端观察调试信息注意实际使用时可能需要根据具体开发环境调整部分路径设置。完整工程代码可通过文末链接获取。

更多文章