Software Development on the E310 and E312
Contents
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:
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
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
.
$ 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
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 $ 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:
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
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):
# TODO: Post the correct cmake command
To confirm that this worked, it can help to open the CMake configuration in a GUI and check the UHD-related variables point to the correct libraries.
# TODO add screenshot from cmake-gui
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