Software Development on the E310 and E312
- 1 Application Note Number
- 2 Revision History
- 3 Abstract
- 4 Overview
- 5 Preparing the device
- 6 Preparing the development machine
- 7 Compiling and installing UHD
- 8 Running the new UHD via sshfs
- 9 Compiling and installing GNU Radio
Application Note Number
|2016-05-24|| Martin Braun
This application note will cover the software development process on the USRP E310 and E312.
Note: Linux only.
When developing software for the embedded series, the recommended workflow is to set up a cross-compiling environment. Software is *not* compiled on the device, but on a separate machine (a more powerful machine that can compile much faster).
E310/E312 manual page with supplemental info:
Preparing the device
It's best to start from scratch for any kind of embedded development, so the first step is to download the latest release for the device. For the E310/E312, this means downloading the latest SD card images from the website: http://files.ettus.com/e3xx_images/ and installing it to the SD card according to the manual.
Once the latest image is flashed, turn on the device.
For the following tutorial, it is necessary that you can SSH into the embedded device from your development machine and vice versa. For information on how to set up networking on the embedded device, consult the manual.
In the following, we will assume that the hostname of the development machine is
desktop, the hostname of the embedded device is
e3xx and the username on the development machine is
On the development machine you should be able to run the following command:
$ ssh root@e3xx
And on the embedded device you should be able to run the following command:
$ ssh dev@desktop
You might need to access the embedded device through a serial console to set up networking. Consult the device's manual for details.
Preparing the development machine
This procedure can be done by using PyBOMBS or manually installing all the elements from source.
Preparation using PyBOMBS
PyBOMBS (Python Build Overlay Managed Bundle System) has currently a recipe that automates the installation of all the elements necessary to cross-compile for the E3XX. In order to use this method, first download and install PyBOMBS:
$ sudo pip install git+https://github.com/gnuradio/pybombs.git
After you have PyBOMBS installed, download and install the necessary recipes to set up the machine:
$ pybombs recipes add gr-recipes git+https://github.com/gnuradio/gr-recipes.git $ pybombs recipes add gr-etcetera git+https://github.com/gnuradio/gr-etcetera.git $ pybombs recipes add ettus https://github.com/EttusResearch/ettus-pybombs.git
The "Ettus" recipe provides the necessary elements for the E3XX, the gr-recipes repository provides all the other packages (GNU Radio, out of tree modules, etc.). More information about the recipes and PyBOMBS in general can be found at the PyBOMBS manual (links provided in the "Overview" section).
On some distributions (e.g. Ubuntu), PyBOMBS can run into shell issues. To avoid those problems, it is recommended to run the following command before continuing, and choose "no" in the prompted dialogue:
$ sudo dpkg-reconfigure dash
Now you can proceed to install the SDK, UHD, GNU Radio and gr-ettus with this simple command:
$ pybombs prefix init /path/to/prefix -R e3xx-radio-redo [-a alias]
Where "/path/to/prefix" has to be previously created (for example ~/prefix/ or ~/prefix/e300). Keep in mind that this command will take a while to finish, due to the size and amount of files that need to be downloaded, cloned and installed.
After the installation is finished, proceed to the Running the new UHD via sshfs section.
Preparation from Source
On your development machine, you will need to create a directory in which the development will take place. This directory is called the prefix, and in the following, we will assume it is in
~/prefix. If you have not created it before, run the following command:
$ mkdir ~/prefix
Installing the SDK
Since you're cross-compiling (i.e., compiling for a different architecture than the development machine's) you require an SDK to do the development. Go the page where you downloaded the device image, and make sure you get the corresponding SDK.
SDKs have filenames such as
oecore-x86_64-armv7ahf-vfp-neon-toolchain-nodistro.0.sh. The files are quite big, so it can take a while to download them.
The SDKs contain the compiler toolchain, but also contain libraries etc. that already exist on the embedded device. This way, when compiling and linking, you know that what you compile on your development machine will also work on the device.
To install the SDK, execute the downloaded file:
$ sh ./oecore-x86_64-armv7ahf-vfp-neon-toolchain-nodistro.0.sh
Depending on your setup, you may have to use the following command:
$ bash ./oecore-x86_64-armv7ahf-vfp-neon-toolchain-nodistro.0.sh
(If that's the case, you may want to run the sudo dpkg-configure dash command, see the PyBOMBS section).
It will ask you where to install it to. Choose the prefix path (
Unzipping and installing takes a while. After it's done, you should see something like this:
$ ls ~/prefix environment-setup-armv7ahf-vfp-neon-oe-linux-gnueabi site-config-armv7ahf-vfp-neon-oe-linux-gnueabi sysroots/ usr/ version-armv7ahf-vfp-neon-oe-linux-gnueabi
(The exact contents of the directory may differ).
Setting up the environment
Before running any of the following commands, you need to set up the environment as outlined on the device manual. You need to source the environment file:
$ cd ~/prefix $ source ./environment-setup-armv7ahf-vfp-neon-oe-linux-gnueabi $ echo $CC # This is just to confirm it worked. arm-oe-linux-gnueabi-gcc -march=armv7-a -mfloat-abi=hard -mfpu=neon --sysroot=~/prefix/e300/sysroots/armv7ahf-vfp-neon-oe-linux-gnueabi
As you can see, it will change all kinds of paths to use different compilers and libraries. Note that during this shell session, you won't be able to run a lot of other things on your development machines, so you should dedicate a separate shell window for this.
Your development machine is now ready to cross-compile.
Compiling and installing UHD
To cross-compile software, the SDK and the environment settings are usually not sufficient. Your software requires a toolchain setup at configuration time to build correctly. UHD brings support for this out of the box, so let's use UHD as an example on how to build custom software. First, let's make sure you have the source code for UHD in your prefix (it can be elsewhere, but for this example we'll keep *everything* inside the prefix directory).
$ cd ~/prefix $ mkdir src/ # Let's create a src/ subdirectory which we'll use throughout the tutorial $ git clone https://github.com/EttusResearch/uhd.git $ cd src/uhd/host $ mkdir build $ cd build
Now, before we do the next step, confirm that you have the correct environment loaded (see the step before). We now need to configure the build setup to cross-compile correctly.
$ cmake -DCMAKE_TOOLCHAIN_FILE=../host/cmake/Toolchains/oe-sdk_cross.cmake -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_E300=ON ..
The exact command may differ (consult the device manual). However, two things are notable:
- We specify a toolchain file. This is how CMake knows how to set up a cross-compile, if the environment variables are set up correctly.
- Second, we specify the install prefix as
/usr. This might seem odd, but it's actually the prefix *on the device*, not on our development machine.
Now that we have it all set up, we can compile:
$ make -j4
This step might take longer than you're used to -- that's because cross-compiling is slightly slower than native compiles. However, it's much, much faster than trying to compile on the device.
Installing is also slightly different than usual:
$ make install DESTDIR=~/prefix
DESTDIR part will make sure it gets installed into the prefix, and doesn't try to actually install to
Running the new UHD via sshfs
The cleanest way to test your newly built UHD is to mount the prefix onto your embedded device. From your development machine, log onto the embedded device and mount the prefix:
$ ssh root@e3xx # After this, we're logged onto the embedded device $ pwd # Check where we are /home/root $ mkdir usr # Create a directory to mount our prefix, this only needs doing once $ sshfs dev@desktop:prefix/ usr/ # This will mount the prefix on the development machine to ~/usr $ ls usr/ # The actual output of this may differ environment-setup-armv7ahf-vfp-neon-oe-linux-gnueabi site-config-armv7ahf-vfp-neon-oe-linux-gnueabi sysroots/ usr/ version-armv7ahf-vfp-neon-oe-linux-gnueabi
The output of the final
ls command should be the same as before when doing
ls ~/prefix on the development machine.
Nearly there! Now, we need to update the environment variables and paths in our ssh session on the embedded device.
We will add a new file called
set_env into the prefix with the following contents (if you prepared your development machine with PyBOMBS, this file should be already included):
LOCALPREFIX=~/usr export PATH=$LOCALPREFIX/bin:$PATH export LD_LOAD_LIBRARY=$LOCALPREFIX/lib:$LD_LOAD_LIBRARY export LD_LIBRARY_PATH=$LOCALPREFIX/lib:$LD_LIBRARY_PATH export PYTHONPATH=$LOCALPREFIX/lib/python2.7/site-packages:$PYTHONPATH export PKG_CONFIG_PATH=$LOCALPREFIX/lib/pkgconfig:$PKG_CONFIG_PATH export GRC_BLOCKS_PATH=$LOCALPREFIX/share/gnuradio/grc/blocks:$GRC_BLOCKS_PATH export UHD_RFNOC_DIR=$LOCALPREFIX/share/uhd/rfnoc/ export UHD_IMAGES_DIR=$LOCALPREFIX/share/uhd/images
You can see the contents is very simple -- all it does is point the most important paths into our prefix. Going back to the SSH session on the embedded device, you should be able to source that file now:
$ which uhd_find_devices # This will point to the old UHD, which we do not want /usr/bin/uhd_find_devices $ source ./set_env $ which uhd_find_devices # Now it should point to the new version /home/root/usr/bin/uhd_find_devices
The last command is to make sure you're actually using the newly compiled UHD, because all of the SD card images already ship a version of UHD. In the example above, it worked, and we're ready to go!
The examples get installed to
lib/, so if you want to try your newly compiled UHD, you can do so by running, e.g., the following command:
$ ~/prefix/lib/uhd/examples/benchmark_rate --tx_rate 1e6
Or anything else in the
At this point, it should be clear why the prefix/sshfs approach is so useful. Everything that is related to the install is stored in the same directory, you can zip it up and move it another computer if you like, and the embedded device doesn't actually store any of the development files. As soon as you unmount the sshfs mount, and reset the environment, it will be back in its default state.
Compiling and installing GNU Radio
In principle, the work flow for GNU Radio is just the same as for UHD. However, GNU Radio depends on UHD, and you want it to use the new UHD instead of the one that ships with the device (and is in your SDK). There are two ways to go ahead: You could either also install UHD into your SDK, but the downside is that you then taint your SDK and it's a non-reversible operation.
A much easier way is to simply point your GNU Radio configuration to the new UHD libs instead of the old ones.
Again, clone the repo into
~/prefix/src/gnuradio, and then run the following command (again, you need to make sure the environment is set up correctly):
$ cd ~/prefix $ source ./environment-setup-armv7ahf-vfp-neon-oe-linux-gnueabi # To be sure that our environment is correctly set up $ cd src/ $ git clone --recursive https://github.com/gnuradio/gnuradio.git $ cd gnuradio $ mkdir build-arm $ cd build-arm $ cmake -Wno-dev -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/oe-sdk_cross.cmake -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_GR_VOCODER=OFF -DENABLE_GR_ATSC=OFF -DENABLE_GR_DTV=OFF -DENABLE_DOXYGEN=OFF ../ $ make -j4 # This may take a while $ make -j4 install DESTDIR=~/prefix
To confirm that this worked, it can help to open the CMake configuration in a GUI and check that the UHD-related variables point to the correct libraries. To see more detailed information about the compile, click the "Advanced" checkbox. By doing so, a several number of configuration options appear, which can be not only read but also modified. Notice that the path for UHD_includes and UHD_libraries should point to the UHD source folder installed in the step before. If they are still pointing to the UHD that comes with the device (which is [$PREFIX$}/sysroots/armv7ahf-vfp-neon-oe-linux-gnueabi/usr/lib/cmake/uhd) they should be modified by changing the path directly on the CMake GUI or by adding recompiling since cmake from terminal by adding the directives accordingly, as follows:
$ cmake -Wno-dev -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/oe-sdk_cross.cmake \-DCMAKE_INSTALL_PREFIX=/usr -DENABLE_GR_VOCODER=OFF -DENABLE_GR_ATSC=OFF -DENABLE_GR_DTV=OFF -DENABLE_DOXYGEN=OFF -DUHD_DIR=~/prefix/usr/lib/cmake/uhd/ -DUHD_INCLUDE_DIRS=~/prefix/usr/include -DUHD_LIBRARIES=~/prefix/usr/lib/libuhd.so ../
Using GNU Radio Companion
Since the embedded devices usually don't have a screen, GNU Radio Companion (GRC) is not a useful tool on the device. However, the development machine can be used to generate flow graphs and compile to Python. Some best practices:
- Save both the .grc file and the generated .py file into the prefix
- Set the 'No GUI' option for Python files that are to be executed on the embedded device
- Run the Python scripts generated from GRC on the command line on the embedded device
- If you need visualization, run a separate flow graph on the development machine with the visualization GUI widgets. Use UDP sinks/sources or ZeroMQ blocks to pass data from the embedded device to the development machine.
Compiling and installing out-of-tree modules (e.g. gr-ettus)
Again, the process is very similar to building GNU Radio. You must make sure that all the correct libraries are linked to, and that it doesn't accidentally pick up libraries from the SDK (e.g. GNU Radio libraries).
# TODO add screenshot cmake-gui on how this should look like