---
title: "Getting started with a USRP over Ethernet"
date: "2021-01-27"
path: "/209-getting-started-with-a-usrp-over-ethernet.html"
section: "/ramblings"
description: "Building UHD 4.0 from source on Ubuntu 18.04, setting up the host network for a USRP X310, updating its FPGA image and taking a first IQ capture."
---

These are my notes from bringing up an Ettus USRP X310 on an Ubuntu 18.04 workstation in January 2021. The X310 talks to the host over Ethernet through its two SFP+ ports, so most of the work is the network, plus making sure the FPGA image on the radio matches the UHD driver on the host.

## Network first

The X310 doesn't do DHCP. Out of the box, with the default "HG" FPGA image, SFP+ port 0 is 1 Gigabit Ethernet at 192.168.10.2 and port 1 is 10 Gigabit at 192.168.40.2. I started on 1 GigE, using a 1000BASE-T SFP module in port 0 and a spare network card in the workstation, cabled directly with no switch.

Give the host side a static address on the same /24, with no gateway and no DNS so the system never tries to route normal traffic through it:

```bash
nmcli con add type ethernet ifname enp5s0 con-name usrp \
    ipv4.method manual ipv4.addresses 192.168.10.1/24 \
    ipv4.never-default yes ipv6.method ignore
nmcli con up usrp
ping -c 3 192.168.10.2
```

Swap `enp5s0` for your interface name from `ip link`. These are private addresses on a point-to-point cable, so they don't clash with anything as long as your normal LAN isn't also 192.168.10.0/24.

## Build UHD

Ubuntu 18.04's packaged UHD was well behind, so I built 4.0 from source. Dependencies:

```bash
sudo apt-get install autoconf automake build-essential ccache cmake \
    cpufrequtils doxygen ethtool g++ git inetutils-tools \
    libboost-all-dev libncurses5 libncurses5-dev libusb-1.0-0 \
    libusb-1.0-0-dev libusb-dev python3-dev python3-mako \
    python3-numpy python3-requests python3-scipy python3-setuptools \
    python3-ruamel.yaml
```

Then build from the release tag rather than whatever is on master:

```bash
git clone https://github.com/EttusResearch/uhd.git
cd uhd
git checkout v4.0.0.0
cd host
mkdir build && cd build
cmake ../
make -j"$(nproc)"
make test
sudo make install
sudo ldconfig
```

`make test` takes a while but it's worth it on a first build. Check UHD can find the radio:

```bash
uhd_find_devices
```

## Match the FPGA image to UHD

Each UHD release expects a particular FPGA compatibility number on the device. If the radio was last flashed with an older UHD, `uhd_usrp_probe` will refuse to run and tell you which number it expected and which it found. Download the images that match your UHD build, then load the HG image over the network:

```bash
sudo uhd_images_downloader
uhd_image_loader --args="type=x300,addr=192.168.10.2,fpga=HG"
```

Loading takes a few minutes and shows its progress by sector. Don't interrupt it. When it finishes, power cycle the X310 (a reboot isn't enough; the FPGA loads at power-on).

## Socket buffers

The first time I ran anything UHD warned that the network send buffer couldn't be made large enough, and printed the command to fix it:

```bash
sudo sysctl -w net.core.wmem_max=24266666
```

If it complains about the receive buffer too, it prints a matching `net.core.rmem_max` command; run that as well. `sysctl -w` doesn't survive a reboot, so put the same settings in a file:

```text
# /etc/sysctl.d/90-uhd.conf
net.core.wmem_max=24266666
```

## Probe the radio

```bash
uhd_usrp_probe --args "addr=192.168.10.2"
```

This prints the full tree of the device. The useful parts:

- `Maximum frame size: 1472 bytes`: confirms you're on the 1 GigE port. On 10 GigE with jumbo frames this goes up to 8000.
- `FW Version` and `FPGA Version`: the FPGA version should now match what your UHD expects.
- The `ip-addr0` to `ip-addr3` entries: the addresses stored in the radio's EEPROM for each port and image combination.
- `RFNoC blocks on this device`: UHD 4 exposes the FPGA as RFNoC blocks (Radio, DDC, DUC, Replay), with the static connections between them.
- The daughterboards: mine had two UBX-160 boards, each 10 MHz to 6 GHz with 160 MHz of bandwidth and 0 to 31.5 dB of gain.

## First capture

UHD installs its example programs under `/usr/local/lib/uhd/examples`. `rx_samples_to_file` is the quickest way to prove the whole chain works:

```bash
/usr/local/lib/uhd/examples/rx_samples_to_file \
    --args "addr=192.168.10.2" \
    --freq 100e6 --rate 5e6 --gain 10 \
    --duration 5 --type short --file fm-band.sc16
```

`--type short` writes interleaved 16-bit I and Q, which is what the radio sends over the wire, so nothing is converted on the host. The X310's master clock is 200 MHz, so pick a sample rate that divides into it evenly (5, 10, 20, 25 MS/s and so on).

If the console fills with `O` characters, those are overflows: the host isn't pulling samples off the network fast enough. On 1 GigE, sixteen-bit complex samples use 32 bits each, so you run out of link well before 30 MS/s. Lower the rate, write to a faster disk, or move to the 10 GigE port.

## What to watch for

- Use the 10 GigE port for anything wide. It needs a 10G NIC, an SFP+ cable or module, an MTU of 9000 on the host interface and a host address of 192.168.40.1.
- Every time you upgrade UHD, run `uhd_images_downloader` and reload the FPGA image. Mismatched versions are the most common reason the radio suddenly stops working.
- A desktop's power-saving CPU governor causes overflows. Set every core to the performance governor with `cpufreq-set` from the `cpufrequtils` package installed above:

```bash
for c in $(seq 0 $(($(nproc) - 1))); do sudo cpufreq-set -c "$c" -g performance; done
```
