We have successfully bridged the gap between the analog and digital worlds. The continuous sensor data was digitized by the ADC, and we safely crossed the asynchronous clock boundaries using Gray-coded FIFOs to avoid metastability.
But now that the data is safely sitting inside your FPGA’s main clock domain, it needs a destination. It has to route through digital filters, custom processing blocks, and eventually out to a UART transmitter. If you just wire these modules together blindly with standard data_valid flags, a fast upstream module will inevitably overwrite data before a slower downstream module can process it.
To build robust, high-throughput RTL pipelines, you need a standardized protocol. You need the language of data movement: AXI4-Stream.
The Problem with Raw Routing
In early RTL design, it is tempting to use a simple "push" architecture. A master module pulses a valid signal, and the slave module is expected to capture the data on that exact clock cycle.
This works fine in isolated, simple systems. But hardware pipelines are dynamic. What happens if the downstream module is a UART transmitter that takes thousands of clock cycles to serialize a single byte? The fast upstream module will keep pushing data, the UART module will miss it, and your carefully acquired sensor data is permanently lost into the digital void.
You need a mechanism for the receiving module to say, "Stop. I am busy."
The Elegance of the Handshake (Panel 1)
The AXI4-Stream protocol solves this through a beautifully simple, two-way handshake using two primary control signals:
TVALID: Driven by the Master. It means, "I have valid data on the bus."TREADY: Driven by the Slave. It means, "I am ready to capture data on this clock edge."
The Golden Rule of AXI-Stream: Data is only successfully transferred on the rising edge of the clock where both TVALID and TREADY are asserted HIGH simultaneously.
If TVALID is HIGH but TREADY is LOW, the Master is forbidden from changing the data. It must hold the bus perfectly stable until the Slave finally asserts TREADY.
The Power of Backpressure (Panel 2 & 3)
This requirement to hold data creates the most critical concept in pipeline architecture: Backpressure.
When a slow downstream module drops its TREADY signal, it creates a stall that propagates backward up the pipeline. Module C tells Module B to stop, which tells Module A to stop. No data is lost, and no packets are dropped.
However, you cannot stall an ADC. The physical world does not stop generating data just because your UART is slow. This is where your Asynchronous FIFO from the previous article becomes critical (see Panel 3). The FIFO acts as an elastic shock absorber. It happily accepts the relentless, fast stream of data from the ADC on its write port, while its read port handles the backpressure and stalling required by the slower AXI-Stream processing modules downstream.

The RTL Implementation
Writing an AXI-Stream interface requires careful attention to register logic. You must ensure you respect the handshake without creating combinatorial loops that will fail timing closure.
Here is a clean Verilog implementation of a simple AXI-Stream pipeline register stage. This module safely buffers the data and manages the backpressure gracefully:
Verilog
module axis_pipeline_register #(
parameter WIDTH = 16
) (
input wire clk,
input wire rst_n,
// Upstream Interface (Acting as Slave)
input wire [WIDTH-1:0] s_axis_tdata,
input wire s_axis_tvalid,
output wire s_axis_tready,
// Downstream Interface (Acting as Master)
output reg [WIDTH-1:0] m_axis_tdata,
output reg m_axis_tvalid,
input wire m_axis_tready
);
// The logic of Backpressure:
// We can accept new data from upstream IF our output is currently empty (~m_axis_tvalid)
// OR if the downstream module is taking our current data this exact cycle (m_axis_tready)
assign s_axis_tready = ~m_axis_tvalid | m_axis_tready;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axis_tvalid <= 1'b0;
m_axis_tdata <= 0;
end else begin
// If we are ready to accept data, update our master output registers
if (s_axis_tready) begin
m_axis_tvalid <= s_axis_tvalid;
if (s_axis_tvalid) begin
m_axis_tdata <= s_axis_tdata;
end
end
end
end
endmoduleConclusion
Building digital hardware is not just about instantiating logic gates; it is about orchestrating the flow of information. By wrapping your custom modules in AXI-Stream interfaces, you transform isolated blocks of Verilog into modular, highly scalable pipelines that can safely handle the chaotic, multi-speed nature of real-world data acquisition.