Go to part 3 of this article
When selecting development hardware, developers should not only
carefully make their selection with price and availability
considerations in mind, but also look for readily available open source
drivers and documentation, as well as development tools that makes life
easier e.g. Kernel, driver and application debugger, profiler, strace.
Especially when developing with open source " where software is
given as is - developers making a platform decision should also
carefully have a eye on the test methodology for kernel, drivers,
libraries and tool chain.
The Linux Test Project (LTP) [8] as an example is a joint project
started by SGI and maintained by IBM, that has a goal to deliver test
suites to the open source community that validate the reliability,
robustness, and stability of Linux. The LTP testsuite contains a
collection of tools for testing the Linux kernel and related features.
Analog Devices, Inc. sponsored the porting of LTP to architectures
running uClinux.

Trust is good, control is better " not only the kernel, also all other
tools involved during the development process needs to be tested. If
you can't trust your compiler or debugger, then you are lost.
Blackfin/uClinux uses DejaGnu [9] to ease and automate the over 44,000
toolchain tests, checking of their expected results while running on
the real target hardware. In addition there are testsuits included in
Blackfin/uClinux to do automated stress tests on kernel and device
drivers using expect scripts. All these tests can be easily reproduced
because they are well documented [10].
A typical uClinux development environment consists of a low cost
Blackfin STAMP board [11], and the GNU Compiler Collection [12] (gcc
cross compiler) and the binutils (linker, assembler, etc.) for the
Blackfin Processor. Additionally, some GNU tools like awk, sed, make,
bash ... plus tcl/tk are needed, although they usually come by default
with the desktop Linux distribution.
All sources and tools (compiler, binutils, gnu debugger) needed to
create a working uClinux kernel on the Blackfin Processors can be
freely obtained from http://www.blackfin.uclinux.org. To use the binary
rpms, a PC with a Linux distribution like RedHat or SuSE is needed.
Developers who can't install Linux on their PC, have a alternative.
Cooperative Linux (coLinux) [15] is a relatively new means to
provide Linux services on a Windows host. There already exists an
out-of-the-box solution that can be downloaded for free from http://blackfin.uclinux.org/projects/bfin-colinux.
This package comes with a complete Blackfin uClinux distribution,
including all user space applications and a graphical Windows-like
installer.
After the installation of the development environment and the
decompression of the uClinux distribution, development may start.
First the developer uses the graphical configuration utility to
select an appropriate Board Support Package (BSP) for his target
hardware. Supported target platforms are STAMP for BF533, BF537 or the
EZ-KIT for the Dual Core Blackfin BF561. Other Blackfin derivatives not
listed like BF531, BF532, BF536 or BF534 are also supported but there
isn't a default configuration file included.
After the default kernel is configured and successfully compiled,
there is a full featured Linux kernel and a file system image that can
be downloaded and executed or flashed via NFS, tftp or Kermit protocol
onto the target hardware with the help of preinstalled u-boot [16]
boot-loader. Once successful, further development can proceed.
A further step could be the creation of a simple "Hello World"
program as shown in the code example below.
The first step is to cross compile 'hello.c' on the development host
PC:
bfin-uclinux-gcc -Wl,-elf2flt hello.c -o hello
The output executable is 'hello'.
When compiling programs that run on the uClinux -bfin-uclinux-gcc is the used
compiler. Executables are linked against the uClibc runtime library. uClibc is a C
library for developing embedded Linux systems. It is much smaller than
the GNU C Library, but nearly all applications supported by glibc also
work perfectly with uClibc.
Library function calls like printf() invoke a system call, telling the
operating system to print a string to stdout, the console. The elf2flt command line option tells the
linker to generate a flat binary - elf2flt
converts a fully linked ELF object file created by the toolchain into a
binary flat (BFLT) file for use with uClinux.
The next step is to download 'hello' to the target hardware. The are
many ways to accomplish that. One convenient way is be to place 'hello'
into a NFS or SAMBA exported file share on the development host, while
mounting the share form the target uClinux system. Other alternatives
are placing 'hello' in a web server's root directory and use the wget
command on the target board. Or simply use ftp or tftp to transfer the
executable.
Debugging is in this case not a necessity, but as programs become
more sophisticated, the available debugging tools become valuable.
Sometimes an application just terminates after being executed, without
printing an appropriate error message. Reasons for this are almost
infinite, but most of the time it can be traced back to something
really simple, e.g. it can't open a file, device driver, etc.
strace is a debugging tool which
prints out a trace of all the system calls made by a another program.
System calls and signals are events that happen at the user/kernel
interface. A close examination of this boundary is very useful for bug
isolation, sanity checking and attempting to capture race conditions.
If strace doesn't lead to an quick result,
developers can follow the unspectacular way most Linux developers go "
using printf or printk
to add debug statements in the code and recompile/rerun.
Because this method can be exhausting, the standard Linux GNU Debugger (GDB) with it's
graphical front-ends can be used instead to debug user applications.
GDB supports single stepping, backtrace, breakpoints, watchpoints,
etc.. There are several options to have gdb
connected to the gdbserver on the
target board. Gdb can connect over Ethernet, Serial or JTAG (rproxy).
For debugging in the kernel space, for instance device drivers,
developers can use the kgdb Blackfin patch for the gdb debugger.
If a target application doesn't work, because of hidden
inefficiencies " profiling is the key to success. OProfile is a system-wide profiler
for Linux based systems, capable of profiling all running code at low
overhead. OProfile uses the
hardware performance counters of the CPU to enable profiling of a
variety of interesting statistics, also including basic time-spent
profiling. All code is profiled: hardware and software interrupt
handlers, kernel modules, the kernel, shared libraries, and
applications.
The Blackfin gcc compiler has very favorable performance, a
comparison with other gcc compilers can be found here: GCC Code-Size
Benchmark Environment (CSiBE) [17]. But sometimes it might be necessary
to do some hand optimization, to utilize all enhanced instruction
capabilities a processor architecture provides. There are a few
alternatives: Use Inline assembly, assembly macros or C callable
assembly.
Example: C callable assembly
For a C program to be able to call an assembly function, the names of
the function must be known to the C program. The function prototype is
therefore declared as an external function.
extern int minimum(int,int);
In the assembly file, the same function name is used as the label at
the jump address to which the function call branches. Names defined in
C are used with a leading underscore. So the function is defined as
shown below:
The function name must be declared using the .global directive in
the assembly file to let the .global_minimum;
assembler and compiler know that it's used by another file.
In this case registers R0 and R1 correspond
to the first and second function parameter. The function return value
is passed in R0.
Developers should make themselves comfortable with the C runtime
parameter passing model of the used architecture.
Not only on a processor where floating point is not natively
supported, virtually all signal processing is performed using
fractional arithmetic. Unfortunately, C doesn't have a fixed point
fractional data type. However, fractional operations can be implemented
in C using integer operations. Most fractional operations must be
implemented in multiple steps, and therefore consume many C statements
for a single operation, which makes them hard to implement on a general
purpose processor.
DSP processors directly support single cycle fractional and integer
arithmetic, while fractional arithmetic is used for the actual signal
processing operations and integer arithmetic is used for control
operations such as memory address calculations, loop counters and
control variables.
The numeric format in signed fractional notation makes sense to use
in all kind of signal processing computations, because it is hard to
overflow a fractional result, because multiplying a fraction by a
fraction results in a smaller number, which is then either truncated or
rounded.
The highest full-scale positive fractional number is 0.99999, while
the highest full scale negative number is -1.0. To convert a fractional
back to an integer number, the fractional must be multiplied by a
scaling factor so the result will be always between ±2^(N-1)
for signed and 2^(N)
for unsigned integer.
The standard uClinux distribution contains a rich set of available C
libraries for compression, cryptography and other purposes (openssl, libpcap, libldap, libm, libdes,
libaes, zlib, libpng, libjpeg, ncurses, etc.) The
Blackfin/uClinux distribution [4] additionally includes: libaudio,
libao, libSTL, flac, tremor, libid3tag, mpfr, etc.
Furthermore Blackfin/uClinux developers [4] currently incorporate a
DSP library into uClinux with highly optimized assembly funtions to
perform all kind of common signal processing algorithms such as
Convolution, FFT, DCT and IIR/FIR Filters, with low MIPS overhead.
The next step would be the development of the special applications
for the target device or the porting of additional software. A lot of
development can be done in shell scripts or languages like Perl or
Python. Where C programming is mandatory, Linux, with its extraordinary
support for protocols and device drivers, provides a powerful
environment for the development of new applications.
In Part 3 of this series, the
author covers a number of real world examples of the use of uClinux,
including in a CMOS Camera Sensor, a network oscilloscope and well as
adapting Linux to some real time embedded applications.
Since
obtaining his MSc (Computer Based Engineering) and Dipl-Ing.(FH)
(Electronics and Information Technologies) Degree from the Reutlingen
University , Michael Hennerich has worked as a design engineer on a
variety of DSP based applications. Michael now works as a DSP
Applications and Systems Engineer at Analog
Devices Inc. in Munich.
This article is excerpted from a
paper of the same name presented at the Embedded Systems Conference
Silicon Valley 2006. Used with permission of the Embedded Systems
Conference. For more information, please visit www.embedded.com/esc/sv.