world leader in high performance signal processing
Trace: » cross

ADSP-BF548 EZ-KIT Quick Start: Cross Compiling Applications

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

Cross Compiling Introduction

Compiling applications for uClinux on the BF548-EZKIT is different than compiling applications for your standard x86 host machine. This is because you need to use the blackfin toolchain to compile the programs for the blackfin architecture. This section of the tutorial will give you a brief introduction into how to use the toolchain to compile and potentially port some programs as FDPIC binaries.

While the explanations in this section seem brief, the aim is to more so provide you with practical demos of compiling so you have something to cross reference back to if you run into complex compile procedures in the future.

This section assumes a basic understanding of C.

Preparation

Prior to compiling your own applications outside of the distribution compilation process, you should do the following:

  • Check that /opt/uClinux is completely writable and owned by your user
  • Make sure that the distribution you plan to integrate with has been compiled on your host machine.
  • Make sure your vendor staging install is up to date by running make vendor_staging_install on the distribution you plan to compile against.
  • Make sure the libraries you need for compiling were enabled in your Application/Library settings.

If you run into any errors on step 3, check that step 1 is completed by running the following terminal commands:

$ chmod 777 -R /opt
$ chown uclinux -R /opt

Making sure that you replace the uclinux in chown with your respective username if you're not using the custom Ubuntu ISO.

Hello World Tutorial

Hello World is a standard program used everywhere as a demonstration. It is fitting to show you how to write and compile Hello World for the BF548-EZKIT.

Copy the following code into a file named hello.c on your host machine.

#include <stdio.h>

int main() {
    printf("Hello, World\n");
    return 0;
}

Now open a terminal and go to the directory you saved hello.c in.

Then run the command “bfin-linux-uclibc-gcc hello.c -o hello”.

$ bfin-linux-uclibc-gcc hello.c -o hello

This command will compile the c file “hello.c” as an fdpic program and output the binary as the file “hello”.

This should result in the creation of the file hello.

Now you can copy this file to the bin folder in your romfs directory to integrate it into your uClinux distribution. (If you have been following along with this guide, that should be your bin folder on your SD card).

Reboot your board with the updated memory card plugged in and boot into uClinux and run the following command on your board:

Assuming everything went correctly, you should see the program respond with “Hello World!”.

SDL Hello World Tutorial

Compiling an SDL program is a good example of using a cross compiler to compile a program that relies on several external libraries. This can demonstrate the l flag and also handling some complicated parameters.

Copy the following code into a file named sdlhello.c on your host machine.

#include <stdio.h>
#include <stdlib.h>
#include <SDL_gfxPrimitives.h>

int main(int argc, char* argv[])
{
    int screen_width = 480;
    int screen_height = 272;
    int screen_bitdepth = 24;

    SDL_Surface *screen;
    SDL_Event input_event;

    int running = 0;

    // Initializes the video subsystem
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        fprintf(stderr, "Error: Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }
    atexit(SDL_Quit);
    SDL_ShowCursor (SDL_DISABLE);

    screen = SDL_SetVideoMode(screen_width, screen_height, screen_bitdepth, SDL_HWSURFACE | SDL_DOUBLEBUF);

    if (screen == NULL)
    {
        fprintf(stderr, "Error: Unable to grab screen\n");
        SDL_Quit();
        exit(1);
    }

    // Draw white background
    SDL_Rect rect0 = {0, 0, screen_width, screen_height};
    SDL_FillRect(screen, &rect0, 0xFFFFFF);

    // Draw a black rectangle
    rectangleColor(screen, 200, 120, 300, 160, 0x000000FF);

    // display surface on LCD
    SDL_Flip(screen);
    printf("Displayed. Interrupt to exit.\n");

    // Wait for user to interrupt program
    memset(&input_event, 0, sizeof(input_event));
    while (running == 0)
    {
        if (SDL_PollEvent(&input_event) && input_event.type == SDL_QUIT)
        {
            running = 1;
        }
    }

    SDL_Quit();

    return 0;
}

Now open a terminal and go to the directory you saved sdlhello.c in.

Then run the command “bfin-linux-uclibc-gcc sdlhello.c -lsdl -o sdlhello”.

$ bfin-linux-uclibc-gcc sdlhello.c $(/home/uclinux/Blackfin/blackfin-linux-dist/staging/usr/bin/sdl-config --cflags) $(/home/uclinux/Blackfin/blackfin-linux-dist/staging/usr/bin/sdl-config --libs) -lSDL_gfx -o sdlhello

This command will compile the c file “hello.c” as an fdpic program and output the binary as the file “sdlhello”.

This should result in the creation of the file sdlhello.

Now you can copy this file to the bin folder in your romfs directory to integrate it into your uClinux distribution.

Reboot your board with the updated memory card plugged in and boot into uClinux and run the following command on your board:

root:/> export SDL_NOMOUSE=1
root:/> sdlhello
Displayed. Interrupt to exit.

Assuming everything went correctly, you should see the blackfin screen draw a black rectangle on a white background.

To explain why there were more flags than previously, is a bit complicated. This compilation command relates to how SDL is compiled where external SDL libraries such as SDL_gfx must be pointed to using sdl-config. To use sdl-config, we have to supply it as an argument to get the cflags and libs, the sdl-config used is the one in the staging directory of your Blackfin compilation. Therefore this won't work if your Blackfin directory has not been compiled yet as it uses the staging libraries.

Note: Staging libraries are libraries compiled for Blackfin during the kernel compilation process, these are generally set in the application screen. Staging libraries are important because the standard libraries on your host machine are not correctly configured for Blackfin and so if you do not use the staging libraries the program will compile incorrectly.

Once the cflags and libs from sdl-config are set, the -lSDL_gfx allows the SDL and SDL_gfx library to be called upon in the program. Without these flags, the program will not be able to access any SDL functions and therefore won't compile.

This has shown an example of using staging libraries while compiling a program.

Qt Hello World Tutorial

Compiling Qt applications is much more complicated than compiling SDL as there is a staging build process via qmake. What is required to compile qt applications for Blackfin involve first running qmake to generate the standard makefile, then editing the Makefile to point to the staging libraries before running the next stage of make.

Copy the following code into a file named qthello.cpp on your PC and put it in a new folder called qthello.

#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton hello("Hello world!");
    hello.resize(100, 30);

    hello.show();
    return app.exec();
}

Now you need to compile this into a qt project. Open a new terminal and change its directory to match that of where you have stored qthello.cpp (qthello). Run the following commands in that terminal:

$ export QMAKESPEC=/home/uclinux/Blackfin/blackfin-linux-dist/lib/qt-embedded/qt-embedded-linux-opensource-src-4.5.1/mkspecs/qws/linux-bfin-fdpic-g++ 
$ qmake -project qthello.c
$ qmake -makefile

Please adjust the first line accordingly to match your environment settings. This should work by default if you are using the custom Ubuntu ISO.

This will create the makefile for the project using the blackfin qmake specs. However, the default makefile configuration points to different staging libraries than the Blackfin distributions staging libraries and so you must edit the makefile to point to the correct directories before proceeding. The guidelines below are rough examples and may be different depending on your environment set up.

/usr/include/qt4 
is changed to
/home/uclinux/Blackfin/blackfin-linux-dist/staging/usr/include/
/usr/lib/i386-linux-gnu 
is changed to
/home/uclinux/Blackfin/blackfin-linux-dist/staging/usr/lib/

With the modifications done, you can now finish compiling the project.

$ make

This command will compile the qt project as an fdpic program and output the binary as the file “qthello”. This filename comes from the name of the folder it is compiled in; in this case qthello.

This should result in the creation of the file qthello.

Now you can copy this file to the bin folder in your romfs directory to integrate it into your uClinux distribution.

Reboot your board with the updated memory card plugged in and boot into uClinux and run the following command on your board:

root:/> export TSLIB_FBDEVICE=/dev/fb0
root:/> export TSLIB_CONSOLEDEVICE=none
root:/> export TSLIB_CONFFILE=/etc/ts.conf
root:/> export TSLIB_CALIBFILE=/etc/pointercal
root:/> export TSLIB_TSDEVICE=/dev/input/event2
root:/> export QWS_MOUSE_PROTO=tslib
root:/> qthello -qws

Assuming everything went correctly, you should see the program appear on the LCD. Read up on the touch screen demos in case the mouse environment variables need adjusting for your kernel set up and do not work as is.

TCP Server Tutorial

Compiling a basic C program that uses some standard headers is also a common compile situation. As long as the vendor_staging_install set up is correct then this should compile smoothly. This demo compile is for a basic TCP server that when connected to will print “Hello World!” into the socket and close it.

Copy the following code into a file named tcphello.c on your host machine.

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char**argv)
{
    int listenfd,connfd,n;
    struct sockaddr_in servaddr, cliaddr;
    socklen_t clilen;
    char mesg[100] = "Hello World!\n";

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(8000);
    bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    listen(listenfd, 1024);

    for(;;)
    {
        clilen = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);

        sendto(connfd, mesg, strlen(mesg), 0, (struct sockaddr *) &cliaddr, sizeof(cliaddr));

        close(connfd);
    }
}

Now open a terminal and go to the directory you saved tcphello.c in.

Then run the command “bfin-linux-uclibc-gcc tcphello.c -o tcphello”.

$ bfin-linux-uclibc-gcc tcphello.c -o tcphello

This command will compile the c file “tcphello.c” as an fdpic program and output the binary as the file “tcphello”.

This should result in the creation of the file tcphello.

Now you can copy this file to the bin folder in your romfs directory to integrate it into your uClinux distribution. (If you have been following along with this guide, that should be your bin folder on your SD card).

Reboot your board with the updated memory card plugged in and boot into uClinux. Set up a network ip if necessary (you can find more details on this in the networking demos section) and then run the following command on your board:

root:/> tcphello

To test the program, first a network connection to the board must be available (you can find more details on this in the networking demos section). Then you will need to open putty on your host machine and create a telnet connection to the board's ip and port 8000. Also make sure to set “Close window on exit” to never. Click Open when you're ready.

Assuming everything went correctly, you should see the program respond with “Hello World!” in putty.

PocketSphinx Tutorial

PocketSphinx is a popular open source voice recognition library that can be ported to use on uClinux. It is a good example for compiling a program that uses a “configure” style compilation process that should make it easy for cross compiling (as it generates the Makefile to use a specified compiler). It also makes use of distutils & python to do some parts of the build so it also demonstrates how to compile programs that use that compilation process.

Before commencing, make sure that your distribution has the Alsa lib enabled and that the kernel sound drivers are correctly enabled (Check the audio demos for more information).

The first step is to get the pocketsphinx and sphinxbase packages. These are available at CMUSphinx or are in the Documents folder on the custom Ubuntu ISO. If you are downloading them, put the tar files into the Documents folder.

Extract both tarballs to new folders as shown below.

Now open a new terminal, and change directory to the Documents folder.

Now to set the first two environment variables to set up distutils & python to build correctly. Run python in your terminal.

$ python

Now enter the following lines prefixed with >>> and view their response.

Python 2.7.3 (default, Aug 1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from distutils import sysconfig
>>> sysconfig.get_config_var('LDSHARED')
'gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro'
>>> sysconfig.get_config_var('CC')
'gcc -pthread'
>>>

Hit Ctrl+D when you are done.

As you can see, the output indicates that distutils is set up to use gcc and not bfin-linux-uclib-gcc. To resolve this they must be set as environment variables to override the defaults.

Run the following commands to update the environment variables. However potentially adjust the LDSHARED variable to match what you saw above on your host machine.

$ export LDSHARED="bfin-linux-uclibc-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro"
$ export CC=bfin-linux-uclibc-gcc

Now that your environment variables are updated, you can begin to configure the sphinxbase package and compile it. Change directory into the sphinxbase folder.

Run the following configure command to set the make process to use bfin-linux-uclibc.

$ ./configure --host=bfin-linux-uclibc

Now to actually compile sphinxbase, run make.

$ make

Then to install the files somewhere accessible, run make install with a DESTDIR. Note that this directory must be writable, and also an exact location. In this case, a new folder called romfs in the Documents folder.

$ make install DESTDIR=/home/uclinux/Documents/romfs

The process must be repeated with pocketsphinx. Change directory back out and into the pocketsphinx directory.

$ cd ../pocketsphinx-0.8

The environment variables set for distutils & python previously should still be set so you do not need to redo it.

Run the following configure command to set the make process to use bfin-linux-uclibc.

$ ./configure --host=bfin-linux-uclibc

Now to actually compile pocketsphinx, run make.

$ make

Then install the files to the same folder as with sphinxbase.

$ make install DESTDIR=/home/uclinux/Documents/romfs

This should leave your romfs directory in the Documents folder with a “usr” folder inside. Inside that usr folder should be a “local” folder. Inside that you should find the files you need to merge into your uClinux distribution to install pocketsphinx.

Copy & merge these folders/files into the usr folder of your uClinux distribution (on the SD card if you are following this guide, or the romfs folder in your distribution otherwise).

To test whether pocketsphinx was succesfully installed into your distribution, simply boot up uClinux on your blackfin board and have a microphone plugged in. When it has started, you can run a demo program that comes with pocketsphinx to test it. Use the commands below:

root:/> amixer sset Mic 100%
root:/> amixer sset 'Mic Boost' on
root:/> pocketsphinx_continuous -hmm /usr/share/pocketsphinx/model/hmm/en/tidigits/ -lm /usr/share/pocketsphinx/model/lm/en/tidigits.DMP -dict usr/share/pocketsphinx/model/lm/en/tidigits.dic -adcdev plughw:0,0

This program should recognise the english numbers 0 to 9.

Further information about pocketsphinx can be found on its website.

If you were to develop an external application that uses the pocketsphinx headers, since it is not in the staging directory the blackfin toolchain will not automatically find them. In this case you need to compile using the -isystem flag and point it to where pocketsphinx has compiled its headers on your host system. You can find more information about using -isystem at http://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html.