AXI4-Stream协议详解与Vivado自定义IP核封装实战
摘要
AXI4-Stream是ARM AMBA AXI4协议族中面向高速流数据传输的轻量级接口协议,广泛应用于FPGA视频处理、高速ADC/DAC数据采集、软件无线电等场景。本文从AXI4-Stream协议的核心信号与握手机制入手,结合Vivado开发环境,详细讲解如何封装一个自定义AXI4-Stream IP核,并给出完整的Verilog代码示例,帮助读者掌握从协议理解到工程实践的全流程。
一、AXI4-Stream协议核心信号
AXI4-Stream协议取消了AXI4-Full和AXI4-Lite中的地址通道,仅保留单向数据流,信号精简但功能强大。其核心信号如下:
| 信号名 | 方向 | 描述 |
|---|---|---|
| TVALID | Master→Slave | 主端数据有效标志 |
| TREADY | Slave→Master | 从端准备好接收数据 |
| TDATA | Master→Slave | 数据总线(8/16/32/64/128位等) |
| TLAST | Master→Slave | 数据包最后一拍标志 |
| TKEEP | Master→Slave | 字节有效标志(每bit对应TDATA一个字节) |
| TUSER | Master→Slave | 用户自定义边带信息 |
最基本的握手机制可概括为:当TVALID和TREADY同时为高时,完成一次数据传输。这种设计使得主从双方都可以通过拉低各自的控制信号来实现反压(Backpressure),天然支持流水线操作。
二、握手机制的三种典型场景
verilog
// 场景1:无等待传输------主端数据一直有效,从端始终就绪
// 每个时钟周期都完成一次传输
always @(posedge clk) begin
if (tvalid && tready) begin
data_captured <= tdata;
end
end
// 场景2:主端等待------从端未就绪,主端保持数据
// TREADY=0时,主端必须保持TVALID和TDATA不变
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tvalid <= 1'b0;
tdata <= 8'd0;
end else if (data_ready) begin
tvalid <= 1'b1;
tdata <= next_data;
end else if (tvalid && !tready) begin
tvalid <= 1'b1;
end else if (tvalid && tready) begin
tvalid <= 1'b0;
end
end
// 场景3:从端等待------主端数据无效,从端保持就绪
// 这是最常见的FIFO写入场景
always @(posedge clk) begin
if (tvalid && tready) begin
fifo_wr_en <= 1'b1;
end else begin
fifo_wr_en <= 1'b0;
end
end
特别需要注意的是:TVALID不能等待TREADY为高后才置位------这会导致死锁。主端应该独立决定何时拉高TVALID,只依赖TREADY来判断是否可以撤销当前数据。
三、Vivado中封装AXI4-Stream IP核
Vivado提供了便捷的IP封装向导,但手动编写AXI4-Stream接口的IP核能让我们更灵活地控制逻辑。以下封装一个简单的数据流加法器IP核,将输入流数据加上固定偏移量后输出。
步骤1:创建工程并添加源文件
在Vivado中新建RTL工程,添加以下Verilog文件:
verilog
// axis_adder.v ------ AXI4-Stream数据流加法器
`timescale 1ns / 1ps
module axis_adder #
(
parameter DATA_WIDTH = 32,
parameter OFFSET = 32'd100
)
(
input wire clk,
input wire rst_n,
// AXI4-Stream Slave Interface
input wire [DATA_WIDTH-1:0] s_axis_tdata,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
input wire [DATA_WIDTH/8-1:0] s_axis_tkeep,
// AXI4-Stream Master Interface
output reg [DATA_WIDTH-1:0] m_axis_tdata,
output reg m_axis_tvalid,
input wire m_axis_tready,
output reg m_axis_tlast,
output reg [DATA_WIDTH/8-1:0] m_axis_tkeep
);
wire transfer = s_axis_tvalid && m_axis_tready;
assign s_axis_tready = m_axis_tready;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axis_tvalid <= 1'b0;
m_axis_tdata <= {DATA_WIDTH{1'b0}};
m_axis_tlast <= 1'b0;
m_axis_tkeep <= {DATA_WIDTH/8{1'b0}};
end else begin
if (transfer) begin
m_axis_tvalid <= 1'b1;
m_axis_tdata <= s_axis_tdata + OFFSET;
m_axis_tlast <= s_axis_tlast;
m_axis_tkeep <= s_axis_tkeep;
end else if (m_axis_tready) begin
m_axis_tvalid <= 1'b0;
end
end
end
endmodule
步骤2:封装为自定义IP
在Vivado中点击 Tools → Create and Package New IP → Package a new IP → Package your current project ,在接口配置中手动将s_axis_*和m_axis_*信号组分别映射为AXI4-Stream Slave和Master接口。确认后点击 Package IP 完成封装。
步骤3:Block Design中使用
在Block Design中,将封装好的axis_adder IP拖入画布,连接上游DMA的M_AXIS到adder的S_AXIS,adder的M_AXIS连接到下游FIFO或DDR写入模块。通过配置参数OFFSET可以灵活调整偏置值。
四、调试技巧与常见问题
-
TLAST信号缺失:DMA传输时如果TLAST没有正确拉高,DMA将永远等待数据包结束,导致传输卡死。务必在数据包最后一拍拉高TLAST。
-
TKEEP处理不当:对于非对齐传输,TKEEP必须正确指示有效字节。尤其是在32位总线传输1字节数据时,TKEEP应设为4'b0001而非4'b1111。
-
时钟域交叉 :AXI4-Stream跨时钟域时必须使用异步FIFO,不可直接连接。Vivado提供了
axis_clock_converterIP用于此目的。
总结
AXI4-Stream协议以其简洁的握手机制和强大的流控能力,成为FPGA高速数据通路设计的首选接口。掌握了TVALID/TREADY握手、自定义IP封装以及Block Design集成这三板斧,就能高效构建复杂的数据处理流水线。从简单的加法器到复杂的图像处理算法,AXI4-Stream都能提供统一、可扩展的接口方案。
以上就是关于AXI4-Stream协议与自定义IP核封装的分享。如果对FPGA开发感兴趣,需要系统学习,这里整理了一份FPGA汇总课程资料,包含BD教程、Vivado教程、IP核教程等,内容非常全面,有需要的朋友可以保存:
链接: https://pan.baidu.com/s/1pIFS8GEYu_jH1np4ZLG2Kw?pwd=wbbw 提取码: wbbw
整理不易,尽快保存,希望对大家的学习有所帮助。