手把手教你为ZYNQ AXI GPIO配置UIO中断(附完整C测试代码)

发布时间:2026/6/4 10:28:18

手把手教你为ZYNQ AXI GPIO配置UIO中断(附完整C测试代码) 手把手教你为ZYNQ AXI GPIO配置UIO中断附完整C测试代码在嵌入式Linux开发中处理硬件中断是常见需求。传统方式需要编写内核驱动但UIOUserspace I/O机制提供了一种更灵活的选择——直接在用户空间处理中断。本文将带你从零开始完成ZYNQ平台上AXI GPIO的UIO中断配置与测试。1. 硬件环境准备开发板选择以Xilinx ZYNQ-7000系列开发板为例如ZedBoard或ZC706这些板卡内置ARM Cortex-A9双核处理器适合运行Linux系统。AXI GPIO配置要点在Vivado中创建AXI GPIO IP核设置GPIO为输入模式配置中断为上升沿触发分配正确的基地址如0x41200000# Vivado Tcl脚本示例 create_ip -name axi_gpio -vendor xilinx.com -library ip -module_name axi_gpio_0 set_property -dict [list \ CONFIG.C_GPIO_WIDTH {2} \ CONFIG.C_INTERRUPT_PRESENT {1} \ CONFIG.C_IS_DUAL {0} \ ] [get_ips axi_gpio_0]2. Linux系统配置2.1 内核配置要求确保Linux内核已启用UIO支持Device Drivers --- Userspace I/O drivers --- * Userspace I/O platform driver with generic IRQ handling * Userspace I/O platform driver with generic irq and dynamic memory2.2 设备树关键配置修改设备树文件如system-user.dtsi添加UIO节点/ { amba_pl { axi_gpio_0: gpio41200000 { compatible generic-uio; reg 0x41200000 0x10000; interrupt-parent intc; interrupts 0 31 1; // 中断号31 }; }; };注意中断号需根据具体硬件配置调整可通过Vivado生成的xparameters.h文件确认。3. 用户空间中断处理3.1 UIO设备操作基础UIO设备在/dev目录下显示为uioX文件/dev/uio0对应第一个UIO设备/sys/class/uio/uio0包含设备信息关键操作函数int fd open(/dev/uio0, O_RDWR); // 打开设备 read(fd, count, sizeof(count)); // 等待中断 write(fd, irq_on, sizeof(irq_on)); // 重新使能中断3.2 完整测试代码以下代码演示了如何通过UIO处理AXI GPIO中断#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/mman.h #define GPIO_MAP_SIZE 0x10000 #define IP_ISR 0x0120 int main(int argc, char **argv) { int fd, ret; unsigned count; void *regs; // 1. 打开UIO设备 if ((fd open(/dev/uio0, O_RDWR)) 0) { perror(open); return -1; } // 2. 内存映射 regs mmap(NULL, GPIO_MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (regs MAP_FAILED) { perror(mmap); close(fd); return -1; } // 3. 中断处理循环 while (1) { unsigned int *isr regs IP_ISR; // 等待中断 ret read(fd, count, sizeof(count)); if (ret ! sizeof(count)) { perror(read); break; } printf(Interrupt #%d occurred\n, count); // 清除中断状态 *isr 0x1; // 重新使能中断 write(fd, count, sizeof(count)); } munmap(regs, GPIO_MAP_SIZE); close(fd); return 0; }4. 调试技巧与常见问题4.1 调试方法检查UIO设备是否注册成功ls /dev/uio* # 查看UIO设备文件 cat /sys/class/uio/uio0/name # 查看设备名称查看中断统计cat /proc/interrupts | grep uio4.2 常见问题解决问题1/dev下没有uio设备检查内核配置是否启用UIO驱动确认设备树compatible属性为generic-uio问题2中断无法触发确认Vivado中正确配置了中断类型检查设备树中断号是否正确确保用户空间程序正确使能了中断问题3中断处理延迟大考虑使用实时内核PREEMPT_RT优化用户空间程序减少中断处理时间5. 进阶应用多中断源处理当需要处理多个AXI GPIO中断时可采用以下策略设备树配置axi_gpio_0: gpio41200000 { compatible generic-uio; interrupts 0 31 1; // ... }; axi_gpio_1: gpio41210000 { compatible generic-uio; interrupts 0 32 1; // ... };用户空间处理逻辑struct pollfd fds[2]; fds[0].fd open(/dev/uio0, O_RDWR); fds[1].fd open(/dev/uio1, O_RDWR); while (1) { poll(fds, 2, -1); // 等待任意中断 for (int i 0; i 2; i) { if (fds[i].revents POLLIN) { read(fds[i].fd, count, sizeof(count)); printf(Interrupt from GPIO%d\n, i); // ...处理中断 } } }在实际项目中UIO中断处理不仅限于GPIO还可应用于定时器、DMA等多种外设。掌握这一技术能显著提高嵌入式Linux开发的灵活性。

相关新闻