Peter Davies

Ramblings

Getting started with a USRP over Ethernet

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:

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:

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:

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:

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:

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:

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:

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

Probe the radio

uhd_usrp_probe --args "addr=192.168.10.2"

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

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:

/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

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