Bridging the Gap Part III: GNU Radio Integration and FPGA-Only Network Core
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.
- 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.
- Eliminating the Middleman: For ultra-low-cost or embedded network deployments, even a host SBC or microcontroller adds cost, power, and OS jitter.
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.

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.


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.
- RMII PHY Receiver (rmii_phy_rx.v): Deserializes 2-bit dibits at 50 MHz (REF_CLK) into bytes based on carrier sense (CRS_DV).
- 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).
- 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.
- 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.
- Port 5000 (Command Channel): Processed by cmd_parser.v to parse ASCII configuration strings (e.g., rate 10, width 16) on the fly.
- 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)

- Host Side: GNU Radio formats baseband signals and controls hardware shifts natively using gr-smisdr.
- Transport Layer: rmiiSDR handles raw RMII reception, UDP parsing, ASCII command decoding, and elastic RAM buffering on a cheap FPGA without a CPU.
- 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
https://github.com/radiolab81/rmiisdr
Want to build a project?
Bring your design to life with the Elektor PCB Service, powered by Eurocircuits. Upload the project files and order professionally manufactured PCBs or assembled boards through a proven European production platform.
Supporting KiCad, Eagle, Gerber, and ODB++ formats, the service is suitable for everything from prototypes and validation builds to series production and volume manufacturing.
Made in Europe. Fast. Reliable. Professional.

Diskussion (0 Kommentare)