6159

Discover how the radiolab81 SDR ecosystem completes its transformation from a simple DMA data pump into a fully autonomous SDR architecture. In this third installment, we analyze native GNU Radio integration via the gr-smisdr OOT module and the realization of the "FPGA-Only" vision with rmiiSDR—an elastic-buffered, CPU-free Ethernet-to-DAC bridge.

In the first two parts of our series, we explored how smiSDR (Raspberry Pi) and parlioSDR (ESP32-P4) bypassed obsolete USB-to-VGA chips by leveraging native DMA parallel interfaces, and how an intermediate FPGA backbone equipped with Digital Up Conversion (DUC) solved the bandwidth and pin-budget bottlenecks.

However, two critical challenges remained:

  1. Software Abstraction: Host applications like GNU Radio needed a native, standardized way to multiplex high-speed I/Q data and asynchronous control commands into the gateware's 16-bit in-band protocol stream.

  2. Eliminating the Middleman: For ultra-low-cost or embedded network deployments, even a host SBC or microcontroller adds cost, power, and OS jitter.

With the release of the gr-smisdr Out-of-Tree (OOT) GNU Radio module and the rmiiSDR IP core, the radiolab81 community has solved both challenges.


1. Native Software Abstraction: The gr-smisdr OOT Module

The FPGA gateware uses an In-Band Signaling protocol on a single 16-bit parallel bus. For protocol details see https://github.com/radiolab81/smisdr/tree/main/gateware#-protocol-review-in-band-signaling-over-smibus--parlio

Key Technical Insights of the Encoder & Decoder

  • Dynamic Command Injection: Reconfiguration commands (set_shift(), set_sample_rate()) can be triggered programmatically via C++/Python APIs or asynchronously via PMT message ports (cmd). The encoder's internal state machine drains pending commands atomically before the next I/Q pair, ensuring command sequences are never torn across buffer boundaries.

  • Quantization & Clipping Safety: The protocol's native I/Q resolution is 14-bit signed ($[-8192, +8191]$). The block defaults to scale=8191 for symmetric peak-normalized mapping ($+1.0 \rightarrow +8191$, $-1.0 \rightarrow -8191$). This leaves the single negative code $-8192$ unused, providing an essential safety headroom against sign-flipping overflow at signal peaks.

  • 1:1 Hardware Receiver Emulation: Verified against the Verilator testbench and the reference HDL receiver, the C++ block accurately emulates hardware latching logic (I-samples update an internal latch; output occurs only when Q arrives) and reproduces tolerance to malformed streams.
sdribs-encoder-20260731120121.png

On the receive/monitoring side, smisdr.decoder decodes incoming 16-bit stream words back into normalized complex I/Q data while publishing decoded metadata ({"cmd": "R"|"S", "raw": uint32, "hz": double}) to PMT message ports for real-time GUI display.
sdribs-decoder-20260731120128.png
2. The "FPGA-Only" Vision Realized: rmiiSDR

While smiSDR and parlioSDR rely on host peripherals (SMI or PARLIO), rmiiSDR takes the architecture to its ultimate minimal stage: completely eliminating the host processor.

systemrev.png


rmiiSDR replaces host SBCs with a self-contained, lightweight Verilog IP core interfacing directly with a low-cost 10/100 RMII Ethernet PHY. There is no NIOS/soft-core CPU, no third-party MAC IP core, and no RTOS.

The Fully Combinational & Clocked Network Pipeline

  1. RMII PHY Receiver (rmii_phy_rx.v): Deserializes 2-bit dibits at 50 MHz (REF_CLK) into bytes based on carrier sense (CRS_DV).

  2. Clock Domain Crossing (cdc_fifo_async.v): A dual-clock, Gray-coded pointer FIFO safely transitions bytes from the 50 MHz ref_clk domain to the internal sys_clk domain (typically 100 MHz).

  3. Packet Parsing (eth_frame_rx.v & ipv4_udp_rx.v): State machines parse Ethernet II frames, validate IPv4 headers, check CRC-32 polynomials, and extract UDP payloads. IP/UDP checksum verification is intentionally bypassed to maintain minimal LUT consumption and low latency.

  4. Port Demultiplexing (port_router.v): Directs incoming UDP datagrams based on destination port:

    • Port 5000 (Command Channel): Processed by cmd_parser.v to parse ASCII configuration strings (e.g., rate 10, width 16) on the fly.

    • Port 1234 (Sample Channel): Processed by sample_assembler.v to reassemble raw byte streams into 8-bit or 16-bit Little-Endian words. Crucially, byte-pair alignment resets at every UDP frame boundary (sof), preventing permanent single-byte phase shifts if a packet is dropped over the network.

3. Deterministic Output in a Jittery World: Elastic Buffering & Universal DDS

Streaming real-time RF samples over standard UDP introduces Ethernet jitter, burstiness, and occasional packet delays. To prevent DAC underruns without compromising timing accuracy, rmiiSDR implements a two-stage buffering and sample-rate generation architecture:

Elastic RAM Buffering (ext_ram_fifo.v)

A small on-chip FIFO acts as an immediate shock absorber, while an external RAM interface fronts a large synchronous RAM (SRAM, SDRAM, or PSRAM). Sized to hold tens of milliseconds of samples, this standing reserve absorbs network outages seamlessly.

Resource Optimization Note: Synthesis benchmarks on a Sipeed Tang Primer 20K (Gowin GW2A-18) highlight the elegance of this architecture:


  • Internal BRAM Mode (USE_INTERNAL_REF_RAM = 1): Consumes ~19,000 LUTs (nearly 100% of the FPGA logic budget) due to BRAM primitive limits forcing LUT-based memory fallback.
  • External RAM Mode (USE_INTERNAL_REF_RAM = 0): Drops logic utilization to just ~1.8k LUTs (>10x reduction), offloading buffer storage entirely to external PSRAM/SRAM.

DDS/NCO-Based Sample Rate Driver (universal_dac.v)

To avoid constraining sample rates to integer dividers of the system clock, universal_dac.v drains the elastic buffer using a DDS-style 32-bit phase accumulator. Every accumulator overflow strobes a single sample to the parallel DAC bus (dac_data_o, dac_clk_o). This enables exact, arbitrary fractional sample rates in absolute Hz, independent of the internal system clock frequency.

4. System Synergy: The Modular SDR "Baukasten"

By combining these independent building blocks, the radiolab81 ecosystem forms a completely open, modular SDR pipeline that can be individually expanded and customized by anyone building their own custom system. The rmii is therefore not a ready-to-use sdr device, nor does it intend to be:

rmiisdr-and-duc.png


  1. Host Side: GNU Radio formats baseband signals and controls hardware shifts natively using gr-smisdr.

  2. Transport Layer: rmiiSDR handles raw RMII reception, UDP parsing, ASCII command decoding, and elastic RAM buffering on a cheap FPGA without a CPU.

  3. DSP/RF Layer: The buffered stream flows directly into the smiSDR DUC gateware core, where hardware NCOs and interpolation filters mix the signal up to the target RF carrier before clocking it into the DAC.


Conclusion & Next Horizons

What began as a clever hack to replace obsolete USB-to-VGA adapters (osmo-fl2k) has evolved into a fully realized open-source SDR platform. By separating software abstraction (gr-smisdr), network transport (rmiiSDR), and DSP mixing (smiSDR Gateware), the community has created a modular architecture that mirrors high-end instruments at a fraction of the cost.

With native Gigabit Ethernet microcontrollers (such as the upcoming ESP32-S31) on the horizon and work progressing toward FPGA-based Digital Down Conversion (DDC) for full-duplex RX/TX, the low-cost SDR ecosystem continues to push the boundaries. A glance at the group's workbench already reveals multipath RX prototype systems being tested for beamforming and source localization of RF signals.


https://github.com/radiolab81/rmiisdr