The RFNoC software layer in UHD provides a complete C++ API for discovering, configuring, connecting, and streaming from the blocks instantiated in an FPGA image. All interaction with the hardware flows through three primary abstractions: block controllers that mirror individual NoC blocks, the rfnoc_graph object that manages the overall topology, and streamers that move sample data between the host and the FPGA.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/EttusResearch/uhd/llms.txt
Use this file to discover all available pages before exploring further.
Block Controllers
A block controller is the UHD (C++) counterpart of a NoC Shell in the FPGA. Every NoC block in the FPGA image has a corresponding block controller object instantiated automatically by UHD at connection time. Block controllers are derived fromuhd::rfnoc::noc_block_base and expose:
- Register access —
regs().peek32(addr)andregs().poke32(addr, value)for direct hardware register reads and writes. - Properties — a type-safe mechanism for communicating block configuration along graph edges.
- Actions — ephemeral operations (e.g., stream commands) that propagate through the graph.
uhd::rfnoc::noc_block_base and register it with the UHD block registry so that it is instantiated automatically whenever the matching NoC ID is found.
Block IDs
Every block instance in an RFNoC network is identified by a Block ID with the following syntax:0/DDC#0, and the second FFT block on the same device is 0/FFT#1. Multiple instances of the same block type share the same NoC ID (a 32-bit hardware identifier) but differ in their Block ID.
Register Interface
Theregister_iface (accessed via regs() inside a block controller) supports:
- Peek/poke — synchronous 32-bit register reads and writes.
- Timed commands — register writes or reads that execute at a specified hardware timestamp.
- Sleep — stall the control endpoint for a given number of clock cycles to sequence operations.
- Async message callbacks — callbacks invoked when the FPGA block sends an unsolicited control packet back to software.
Block Properties
Properties are the primary mechanism for communicating configuration both within a block and between adjacent blocks across graph edges. There are two kinds:User Properties vs. Edge Properties
Using the DDC block as an illustrative example:- User properties (
freq,decim) describe characteristics of the block itself — what it does to the data. They are set by the application or by property resolvers. - Edge properties (
samp_rate) describe something about the data stream on a particular input or output connection. They propagate automatically when adjacent blocks are connected.
samp_rate_out = samp_rate_in / decim- Normalized phase increment =
freq / samp_rate_in
samp_rate_out = 200e6 and a downstream Modem block requires samp_rate_in = 20e6, the DDC automatically resolves decim = 10 without any explicit application code.
Property Propagation Example
property_t<T> attributes and registered with register_property() before they participate in propagation:
Common Property Names
These are the conventional names that blocks should reuse when applicable:| Property | Kind | Description |
|---|---|---|
type | Edge | Data type string (e.g., sc16, fc32) |
samp_rate | Edge | Sampling rate in samples per second |
scaling | Edge | Amplitude distortion introduced by this block |
atomic_item_size | Edge | Minimum indivisible data unit in bytes |
spp | User | Samples per packet |
decim / interp | User | Decimation or interpolation factor |
Two edge property names are reserved by the framework and cannot be redefined:
tick_rate (must be uniform across all blocks in a graph) and mtu (maximum transmission unit, read from hardware registers).The Graph API
Theuhd::rfnoc::rfnoc_graph class is the top-level session object for any RFNoC-capable USRP. It discovers all blocks in all connected devices and manages the logical topology.
Creating a Graph
Connecting Blocks
Committing the Graph
After all connections are declared, callcommit() to run property propagation and validate the entire graph:
commit() and release() are reference-counted, so nested commit/release calls are safe in library code.
Streamers in RFNoC
Streamers are the host-side endpoints that send or receive sample data. In the RFNoC model, a streamer is treated as a node in the graph just like any other block — you must explicitly connect it to a block output (for RX) or input (for TX) before callingcommit().
graph->commit(), streamers are ready for recv() and send() calls using the same API as uhd::multi_usrp.
Complete Example: Radio → DDC → Streamer
The following code builds a simple receive chain on device 0:Built-in Block Controllers
UHD ships controller classes for all in-tree RFNoC blocks. The most commonly used ones are described below.RadioControl
uhd::rfnoc::radio_control — Interface to the USRP RF front-end. Controls frequency, gain, bandwidth, DC offset, IQ balance, GPIO, and timed streaming commands. Sets the samp_rate edge property on its output.DDCBlockControl
uhd::rfnoc::ddc_block_control — Digital downconverter with frequency shift and decimation. User properties: freq (Hz) and decim. Methods: set_freq(), set_output_rate(), get_input_rate().DUCBlockControl
uhd::rfnoc::duc_block_control — Digital upconverter with frequency shift and interpolation. User properties: freq (Hz) and interp. Methods: set_freq(), set_input_rate(), get_output_rate().FFTBlockControl
uhd::rfnoc::fft_block_control — Configurable forward/inverse FFT with cyclic prefix insertion and removal for OFDM. Methods: set_length(), set_direction(), set_magnitude(), set_shift_config(), set_scaling_factor().ReplayBlockControl
uhd::rfnoc::replay_block_control — Records sample data to DRAM and plays it back. Methods: record(), play(), stop(), config_play(), issue_stream_cmd(). Supports continuous looping and timed playback.BlockControl (default)
uhd::rfnoc::block_control — The fallback controller for any block whose type is not in the registry. Exposes raw register peek/poke and generic property access.FFT Block Quick Reference
Replay Block Quick Reference
Motherboard Controller
Motherboard-level settings — time source, clock reference, timekeepers, synchronization — are accessed throughuhd::rfnoc::mb_controller, not through block controllers:
get_mb_controller(). Block IDs use the same index prefix: blocks on motherboard 0 are 0/Radio#0, blocks on motherboard 1 are 1/Radio#0.