[[TOC(Tutorials/k0SDR*, depth=3)]] ''Last updated: 2021/07/26'' == Working with USRP X310 == === Description === For this tutorial, we will now use two USRP X310s on ORBIT Sandbox 2 to transmit and receive a single frequency over the air to demonstrate the use of the '''U'''SRP '''H'''ardware '''D'''rivers (UHD) with the USRP X310. This tutorial can be run on other USRP X310s available of the grid as well. For details on available USRPs on the grid, please see [wiki:Hardware/fDevices/cSDR/gUSRP#GRID available USRP hardware in the grid]. As with any of these tutorials, it is much more productive to ''write the commands by hand'' rather than just copy-paste them. This will help memorize what is going on. === Hardware / Software Resources Utilized === We will be using the X310 radios in ORBIT Sandbox 2. One radio will be used to transmit, and the other to receive. For more information on these radios, please see the [[Hardware/bDomains/cSandboxes/bSB2|Sandbox 2]] page. We will use the following node image: {{{baseline-gr-uhd4-rc.ndz}}} which contains UHD 4.0.0 along with GNU Radio 3.8. === Set Up === ==== Imaging ==== First, make sure you have Sandbox 2 reserved and are logged into the console over SSH. '''Please enable X11 forwarding, by using the -X flag (-Y if on Mac OS)''' We should make sure that both of the nodes are turned off: {{{mpk2138@console:~$ omf tell -a offh -t node1-1,node1-2}}} Then, we want to image the nodes with the following commands: {{{mpk2138@console:~$ omf load -i baseline-gr-uhd4-rc.ndz -t node1-1}}} {{{mpk2138@console:~$ omf load -i baseline-gr-uhd4-rc.ndz -t node1-2}}} Please note, it will take time to image the node, make sure that the first image process is finished before attempting to start the second. Once both nodes are imaged, we can now turn them back on: {{{mpk2138@console:~$ omf tell -a on -t node1-1,node1-2}}} ==== Accessing the Nodes ==== Give the node about a minute to turn on and be ready, and then SSH into the first node: {{{mpk2138@console:~$ ssh -X root@node1-1}}} Once you have SSH'd into {{{node1-1}}}, open a second SSH session and login to the Sandbox 2 console as before. On that new SSH session, SSH into the other node: {{{mpk2138@console:~$ ssh -X root@node1-2}}} At this stage, you should have two SSH windows open, each logged into one of the two nodes. {{{ #!comment ==== Install Octave on node1-2 ==== We will need Octave (the GNU version of MATLAB) to process the data from our experiment. We only need to install it on {{{node1-2}}}. To do so, use the following commands: Start by installing the new Ubuntu package manager, Snap: {{{root@node1-2:~# sudo apt update}}} {{{root@node1-2:~# sudo apt install snapd}}} Accept whatever prompts {{{sudo apt install}}} gives you. Then, reboot the node. First, exit it: {{{root@node1-2:~# exit}}} You will end up back in the Sandbox 2 console. Now, reboot the node: {{{mpk2138@console:~$ omf tell -a offh -t node1-2}}} Wait a minute or so: {{{mpk2138@console:~$ omf tell -a on -t node1-2}}} After another minute, you should now be able to log back into {{{node1-2}}}. Once you can, run the following command to install Octave: {{{root@node1-2:~# sudo snap install octave}}} Now, we need to setup a symbolic file link so Octave can find the correct X11 authentication file: {{{root@node1-2:~# ln -s ~/.Xauthority ~/snap/octave/current/.Xauthority}}} }}} ==== Configuring the Network Interface ==== Each node is physically connected to one USRP X310 over a 10 Gbps Ethernet connection. However, the default network card interface configuration will need to be changed so that the node can communicate to the correct IP address. The USRP X310 uses a default IP address of {{{192.168.40.2}}} on its first 10 Gbps interface, which is the interface being used to connect to the node. So on '''both nodes''', run the following command to setup the network interface to use the correct IP address: {{{root@node1-X:~# ifconfig enp1s0 192.168.40.1}}} By setting the IP address of the interface named {{{enp1s0}}} on the node to {{{192.168.40.1}}} and using the default subnet mask of {{{255.255.255.0}}}, we are then able to communicate with any device with an IP between {{{192.168.40.2}}} and {{{192.168.40.254}}} using that interface. Since the USRP X310 has IP address {{{192.168.40.2}}} and is connected to interface {{{enp1s0}}}, we can now communicate with it. Confirm this with the following command: {{{root@node1-X:~# uhd_find_devices}}} This should yield the following output: {{{ [INFO] [UHD] linux; GNU C++ version 7.5.0; Boost_106501; UHD_4.0.0.0-25-g1a34ba8a -------------------------------------------------- -- UHD Device 0 -------------------------------------------------- Device Address: serial: 30F10F9 addr: 192.168.40.2 fpga: HG name: product: X310 type: x300 }}} Please ensure this works before proceeding. ==== Setting up GNU Radio ==== To make sure GNU Radio can start, please run the following two commands on each node to point GNU Radio to the correct Python installation directories: {{{root@node1-X:~# export PYTHONPATH=/usr/local/lib/python3/dist-packages/:$PYTHONPATH}}} {{{root@node1-X:~# export LD_LIBRARY_PATH=/usr/local/lib/:$LD_LIBRARY_PATH}}} Now we set the network card read and write buffer size to the maximum size possible: {{{root@node1-X:~# sudo sysctl -w net.core.wmem_max=24862979}}} {{{root@node1-X:~# sudo sysctl -w net.core.rmem_max=24862979}}} === Building the GNU Radio Flowgraphs === ''See the troubleshooting section below for a common error and how to fix it.'' ==== Transmitter ==== Start GNU Radio on {{{node1-1}}}: {{{root@node1-1:~# gnuradio-companion}}} The GNU Radio interface should show up on your local machine. The goal is to build a flowgraph that looks like this for the transmitter: ||||Figure 1: Transmitter Flowgraph || || [[Image(x310_sb2_tx_flowgraph.png, 600px)]] || Here, the "Signal Source" generates samples for a 1 MHz cosine wave at the flowgraph sample rate, in this case 10 MHz. The samples then go into a "UHD USRP Sink". The "UHD USRP Sink" is what takes the signal samples generated in GNU radio and sends them to the USRP for transmission. You can add blocks by clicking the magnifying glass to open a search bar and then search. Drag the block from the list into the flowgraph or double click and it will show up. To make connections, click on a blue tab and drag to another one. You will need to set values for {{{samp_rate}}} as well as parameters in each of the blocks. Double clicking on a block will bring up an editor for all parameters that a block uses. See below for the parameters used in this experiment for each block: ||||||||Figure 2: Transmitter Flowgraph Parameters || || [[Image(x310_sb2_tx_usrp_sink.png, 280px)]] || [[Image(x310_sb2_tx_signal_source.png, 280px)]] || [[Image(x310_sb2_tx_options.png, 280px)]] || (a) UHD USRP Sink || (b) Signal Source || (c) Options || Note that in the USRP Sink, we are setting the address to be 192.168.40.2. This is the same address we were setting up the network card interface to be able to communicate with earlier. After all of these parameters have been entered, press the green play button. It will prompt you to save the flowgraph, you can save it in the default directory with the filename {{{x310_tx.grc}}}. When the flowgraph runs, it should after some seconds open up a new GUI window with nothing on it. This is OK, it is blank simply because we used no GUI blocks. To stop it running, simply close this window. ==== Receiver ==== Start GNU Radio on {{{node1-2}}}: {{{root@node1-2:~# gnuradio-companion}}} We want to build a flowgraph that looks like the following: ||||Figure 3: Transmitter Flowgraph || || [[Image(x310_sb2_rx_flowgraph.png, 600px)]] || Instead of a USRP Sink, we have a USRP Source. This gives us samples received by the radio receiver at the specified sample rate of 10 MHz. We then feed these samples into a "QT GUI Frequency Sink", which will allow us to see the frequency spectrum of the signal we are receiving. We need the following parameters set up: ||||||Figure 4: Transmitter Flowgraph Parameters || || [[Image(x310_sb2_rx_usrp_source.png, 280px)]] || [[Image(x310_sb2_rx_options.png, 280px)]] || || (a) UHD USRP Source || (b) Options || === Troubleshooting === You may run into the following error when running the experiment: {{{ [INFO] [X300] X300 initialization sequence... Error: RuntimeError: Expected FPGA compatibility number 38, but got 36: The FPGA image on your device is not compatible with this host code build. Download the appropriate FPGA images for this version of UHD. Please run: "/usr/local/lib/uhd/utils/uhd_images_downloader.py" Then burn a new image to the on-board flash storage of your USRP X3xx device using the image loader utility. Use this command: "/usr/local/bin/uhd_image_loader" --args="type=x300,addr=192.168.40.2" For more information, refer to the UHD manual: http://files.ettus.com/manual/page_usrp_x3x0.html#x3x0_flash }}} This is basically saying that the FPGA on the USRP X310 is a different version than that expected by UHD. To fix this issue, simply follow the commands as stated: {{{root@node1-X:~# /usr/local/lib/uhd/utils/uhd_images_downloader.py}}} {{{root@node1-X:~# /usr/local/bin/uhd_image_loader --args="type=x300,addr=192.168.40.2"}}} Upon running the second command, you should see the following output: {{{ [INFO] [UHD] linux; GNU C++ version 7.5.0; Boost_106501; UHD_4.0.0.0-25-g1a34ba8a Unit: USRP X310 (30F110A, 192.168.40.2) FPGA Image: /usr/local/share/uhd/images/usrp_x310_fpga_HG.bit -- Initializing FPGA loading...successful. -- Loading HG FPGA image: 0% (0/121 sectors) }}} '''''Do not do anything on the node while this is running'''''. An incomplete FPGA imaging process will brick the USRP X310 and render it totally unusable. When it has completed, exit the node: {{{root@node1-X:~# exit}}} Once back in the console, power cycle the node using OMF. You can now log back into the node over SSH and continue on by setting up the network interface again. The "imaging" outlined here is a very different procedure to "imaging" the node with a {{{.ndz}}} file. When imaging a node with a {{{.ndz}}} file, we are basically overwriting the hard drive with a backup. Imaging an FPGA on a USRP (or any FPGA in general) is the process of loading a new digital circuit configuration onto the FPGA's EEPROM - a much more delicate process which is why it must complete without disturbance.