You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无DMA场景下Zynq PS读取AXI连接FIFO的SDK方法及替代方案咨询

刚接触Zynq FPGA开发就遇到DMA资源被占的场景,确实得灵活调整方案。我来一步步帮你解决这两个问题:

1. 如何用Xilinx SDK读取AXI连接的FIFO数据?

首先明确:你通过AXI Interconnect挂到PS的FIFO,应该是AXI Memory-Mapped (MM) 接口的FIFO(或是搭配了AXI Stream转MM的桥接IP)。这类FIFO会被映射到PS的内存地址空间,你可以直接通过寄存器读写获取数据,步骤如下:

步骤1:确认FIFO的寄存器映射

在Vivado导出硬件到SDK后,打开xparameters.h文件,里面会有你的自定义FIFO基地址(比如XPAR_MY_CUSTOM_FIFO_0_BASEADDR)。同时要明确两个核心寄存器的偏移地址:

  • 状态寄存器:用来判断FIFO是否非空/满,通常偏移0x00,比如FIFO_STATUS_REG = 基地址 + 0x00
  • 数据寄存器:读取FIFO数据的端口,通常偏移0x04,比如FIFO_DATA_REG = 基地址 + 0x04

(注:如果是你自己用Verilog写的FIFO,要确保读数据寄存器时,FIFO会自动弹出当前数据、读指针自动递增)

步骤2:轮询方式读取(基础版)

如果数据量不大,轮询是最简单的实现方式。用Xilinx提供的Xil_In32()函数直接读写寄存器,示例代码如下:

#include "xil_io.h"
#include "xparameters.h"
#include "xil_types.h"

// 根据你的硬件定义调整地址和掩码
#define FIFO_BASE_ADDR    XPAR_MY_CUSTOM_FIFO_0_BASEADDR
#define FIFO_STATUS_REG   (FIFO_BASE_ADDR + 0x00)
#define FIFO_DATA_REG     (FIFO_BASE_ADDR + 0x04)
#define FIFO_EMPTY_MASK   0x01  // 假设状态寄存器bit0表示FIFO为空

u32 read_fifo(u32 *recv_buffer, u32 max_read_num) {
    u32 read_count = 0;
    while (read_count < max_read_num) {
        // 读取状态寄存器,检查FIFO是否非空
        u32 fifo_status = Xil_In32(FIFO_STATUS_REG);
        if (!(fifo_status & FIFO_EMPTY_MASK)) {
            // 读取一个32位数据,FIFO自动弹出下一个数据
            recv_buffer[read_count++] = Xil_In32(FIFO_DATA_REG);
        } else {
            // FIFO空了,退出循环(也可以加小延时重试)
            break;
        }
    }
    return read_count;
}

步骤3:中断方式读取(高效版)

如果数据是周期性产生,或是不想占用PS过多CPU资源,建议用中断触发:

  1. 在Vivado中把FIFO的非空中断信号连接到PS的GIC(通用中断控制器),并在SDK的xparameters.h中配置对应中断号。
  2. 在SDK中初始化GIC、注册中断处理函数,当FIFO非空时触发中断,在中断函数中批量读取数据。

核心中断处理逻辑示例:

void fifo_interrupt_handler(void *CallbackRef) {
    u32 *buffer = (u32 *)CallbackRef;
    static u32 idx = 0;
    // 读取数据直到FIFO为空
    while (!(Xil_In32(FIFO_STATUS_REG) & FIFO_EMPTY_MASK)) {
        buffer[idx++] = Xil_In32(FIFO_DATA_REG);
        // 务必清除中断标志,避免重复触发
        Xil_Out32(FIFO_STATUS_REG, 0x00); // 假设写0清除中断
    }
}

2. 无DMA时,PL到PS的其他数据传输方案

根据你的数据量、速率需求,还有这些可行方案可选:

  • 共享内存传输(推荐大数据量场景)
    利用PS和PL共享的内存(片上OCM或DDR),PL通过AXI HP/ACP接口把数据写入共享内存区域,PS直接访问该内存。注意:

    • 在Vivado中配置共享内存的地址范围,确保PL和PS都能访问
    • PS读取前要调用Xil_DCacheInvalidateRange()清除缓存,确保读到最新数据
    • 可配合中断:PL写完数据后触发中断,通知PS读取,避免轮询开销
  • AXI Stream转MM桥接
    如果PL端是AXI Stream格式的数据,用Xilinx官方的AXI Stream to Memory Mapped IP把流数据转换成MM接口,PS直接读取映射地址即可。这种方式适合连续流数据,无需自己编写FIFO逻辑。

  • MicroBlaze代理传输
    如果项目中有MicroBlaze软核,可以让MicroBlaze先接收PL的数据(比如读FIFO),再通过AXI接口转发到PS的内存或寄存器。适合需要对数据做预处理(格式转换、过滤)的场景,能减轻PS的计算负担。

  • AXI Lite寄存器批量写入
    在PL中设计多个AXI Lite寄存器,把数据分批写入这些寄存器,PS一次性读取所有寄存器。适合小批量数据,比单个FIFO更灵活,但需要硬件端额外设计寄存器组。

  • GPIO模拟简易总线(仅应急小数据量)
    极端情况下,用PS的GPIO引脚模拟并行总线(地址线、数据线、读写控制),PL把数据放到GPIO数据线上,PS通过GPIO读取。但这种方式速率极低,仅适合几个字节的极小数据量,不推荐常规使用。


内容的提问来源于stack exchange,提问作者Nikolay Josh Konovalenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:38:41