Software Development on the E310 and E312

From Ettus Knowledge Base
Revision as of 11:45, 8 June 2016 by NicolasCuervo (Talk | contribs) (Running the new UHD via sshfs)

Jump to: navigation, search

Application Note Number

AN-311

Revision History

Date Author Details
2016-05-24 Martin Braun
Nicolas Cuervo
Initial creation

Abstract

This application note will cover the software development process on the USRP E310 and E312.

Overview

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:

Also useful:

PyBOMBS documentation:

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.

Network setup

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 dev.

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 use 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. More information about the recipes and PyBOMBS in general can be found at the PyBOMBS main page (links provided in the "Overview" section). In order to avoid shell inconveniences, it is recommended to run the following command before continuing, and choose "no" in the prompted dialog:

   $ sudo dpkg-reconfigure dash

Now you can proceed to install the SDK, UHD, GNURadio and gr-ettus with this simple command:

   $ pybombs prefix init /path/to/prefix -R e3xx-radio-redo

Where "/path/to/prefix" has to be previously created (for example ~/prefix/e300/). Keep in mind that this previous command will take a while to finish, due to the size and amount of files that are being 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

It will ask you where to install it to. Choose the prefix path (~/prefix). 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

The DESTDIR part will make sure it gets installed into the prefix, and doesn't try to actually install to /usr/.

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 examples subdirectory.

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

Output example of CMakeGUI for the build of GNURadio.

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