User:WillWare/Angstrom and Beagleboard

Topics and color codes edit

This page, which I originally compiled in 2010, contains information on a few different topics: the Beagleboard (the system I work on these days uses the same processor but is mostly different otherwise), the Angstrom Linux distribution, the opkg package distribution system (Angstrom's equivalent to apt-get or yum), and Bitbake, a build tool for embedded systems.

The language is a little muddy here because Yocto/Poky has become a sort of hazy umbrella project. While Angstrom is clearly a Linux distribution, Yocto seems like one but also includes other things in a way that seems almost deliberately ambiguous. So I haven't worked too hard to pick apart Angstrom versus Yocto since they seem to be chunks of the same tradition maintained by the same people, and an apples-to-apples comparison probably doesn't make sense anyway.

Most vendors have stopped selling the Beagleboard in favor of newer boards such as the Raspberry Pi or the Beaglebone Black. The Beagleboard uses an OMAP processor, which has been discontinued for practical purposes, a more modern alternative being the Sitara ARM Processor such as the AM335x used on the Beaglebone Black.

I've tried to start to differentiate these topics by background color. This is a work in progress, don't rely on this blindly.

Stuff that is mostly Beagleboard-specific has a light orange background.

Stuff that is mostly Angstrom-specific will have a light green background. I'm not sure if I'll actually use this color, since Angstrom seems very similar to the more recent Yocto project, so the Angstrom stuff is not particularly misleading, as far as I can see.

The Beagleboard is a thing of beauty edit

 
Beagle Board described

What is Bitbake? edit

Bitbake is a build tool for embedded systems. It is oriented around packages in the same way that Ubuntu or CentOS is. You can use packages sourced by standard repositories, or create your own packages. The benefit of packages is the tracking of dependencies and compatible version numbers and all that.

Bitbake's final product is an image containing a bootloader and other Linux startup process stuff including a file system image and a kernel. Bitbake can also produce intermediate products such as packages. Bitbake can work with other embedded Linux distros such as Yocto.

It's possible to set up an autobuilder with a web interface which performs nightly builds and it can build customized images for you.

Getting started with Angstrom edit

Angstrom is a small Linux distribution for OMAP processors. I'm working in Ubuntu 10.04 and what follows will pertain to that platform. In your home directory do the following:

sudo apt-get install expect diffstat cvs subversion gawk chrpath python-psyco texi2html lighttpd python-setuptools
sudo easy_install ply
sudo easy_install progressbar
sudo rm /bin/sh   # first confirm it's a symbolic link to /bin/dash
sudo ln -s /bin/bash /bin/sh
git clone git://gitorious.org/angstrom/angstrom-setup-scripts.git
[[in case above does not work or you are sitting behind a proxy use:
git clone http://git.angstrom-distribution.org/cgi-bin/cgit.cgi/setup-scripts/ 
after appropriately setting http_proxy environment variable]]
cd angstrom-setup-scripts/
MACHINE=beagleboard ./oebb.sh config beagleboard
MACHINE=beagleboard ./oebb.sh update
(cd sources/bitbake && python setup.py build && sudo python setup.py install)
MACHINE=beagleboard ./oebb.sh bitbake virtual/kernel console-image
# Let this last command run overnight. It will take several hours but will
# prepare your machine for quicker builds in the future. It will help if you're
# on a fast wired internet connection.

One way to build an Angstrom image to run on a Beagleboard is to use the Narcissus online image builder at http://narcissus.angstrom-distribution.org/. If you want to build an image locally on your own machine, which will allow you to write your own packages, you'll need to install the bitbake tool developed by the OpenEmbedded folks. You have a couple of different options for this.

An Angstrom build is initiated by a bitbake command, which specifies a target, for instance:

bitbake helloworld-image

There is a list of several useful targets at http://docs.openembedded.org/usermanual/html/gettingoe_building_software.html. As with Ubuntu, Angstrom can have meta-packages containing no files, existing only to specify dependencies on a group of other packages. The helloworld-image target refers to the example at http://docs.openembedded.org/usermanual/html/recipes_examples.html. The inputs to a bitbake operation are recipe files with *.bb filenames like the two recipes below.

While one of these targets specifies an entire runnable Linux disk image, bitbake is a sort of make equivalent and a bitbake command can be given for a single package. The result of building a package (analogous to building a Debian or Ubuntu package) is a *.ipk file.

Another example recipe file is found here, and many more in the Angstrom distribution in the sources/openembedded/recipes directory tree.

wware-image.bb edit

This file specifies a small complete Linux distribution.

require console-base-image.bb

DEPENDS += "task-base-extended \
          "

IMAGE_INSTALL += "task-base-extended \
       python \
       helloworld \
       quux-module \
           "

export IMAGE_BASENAME = "wware-image"

IMAGE_INSTALL is the list of packages you want to include. Some of the files resulting from bitbaking an image, found in the angstrom-setup-scripts/build/tmp-angstrom_2008_1/deploy/glibc/images/beagleboard directory, are

  • Angstrom-wware-image-glibc-ipk-2011.03-beagleboard.rootfs.tar.bz2, a compressed file system image that will be unpacked onto the SD card a little later.
  • Angstrom-wware-image-glibc-ipk-2011.03-beagleboard-testlab/files-in-image.txt which lists the files you should expect to find in the disk image. This file will be helpful when you start to develop your own Angstrom modules, and want to make sure that they were installed correctly in an image.
  • Angstrom-wware-image-glibc-ipk-2011.03-beagleboard-testlab/installed-packages.txt which lists the *.ipk files used to create the disk image.

helloworld_1.0.0.bb edit

This file specifies an example package. Many recipes involve downloading a tarball, and in that case they carry MD5 and SHA256 checksums to verify the tarball's authenticity. When I build modules myself, I find it handy to write a script that automatically computes the checksums and appends them to the earlier part of the recipe file.

DESCRIPTION = "Minimal statically compiled Hello world!"
LICENSE = "GPL"
PR = "r1"

S = "${WORKDIR}"

SRC_URI = "http://127.0.0.1:8181/helloworld-1.0.0.tar.bz2 \
          "

do_install () {
       install -d ${D}${bindir} ${D}${sysconfdir}/rc5.d
       install -m 0755 helloworld ${D}${bindir}/
       ln -s ../../${bindir}/helloworld ${D}${sysconfdir}/rc5.d/S52helloworld
}

SRC_URI[md5sum] = "74d43696d6a4f7eed77ee98f325dad73"
SRC_URI[sha256sum] = "1186aa89f0ee1e5619d82bdac452e5fb3ce8ce49d5588f9064e13d125fefab55"

In this case, I've set up a little HTTP server on the same machine and bitbake is fetching a tarball with the sources. I could have included a do_compile function with instructions for building the module. If no do_compile is defined, bitbake will try to run "make", assuming that the makefile in the tarball will build the included C source file.

Yow! It's working!! edit

 
Hardware setup for trying it
 
A working Linux shell

You'll need a serial port connection. I'm using a USB-to-serial adapter which connects to the 10-pin connector between the power socket and the SD card socket. Use a power supply that gives five volts ONLY -- more will damage the board! Connect the pins between the male DB9 end of the adapter and the board's 10-pin ribbon cable connector as follows.

Male DB9    Beagleboard
2           3
3           2
5           5

and set up minicom or CoolTerm or screen or some other terminal emulator with 115.2 kbaud, 8N1, no flow control.

Use GParted to partition your SD card. First partition is 50 or 100 MBytes, VFAT32. Second partition is the rest of the card and it must be ext3. It will not work with ext2. I labelled my partitions "boot" and "Angstrom" respectively. When I plug the card in with a USB adapter, it automounts as /media/boot and /media/Angstrom. Now it's time to copy files to the boot partition with a little renaming.

export BBDIR=build/tmp-angstrom_2008_1/deploy/glibc/images/beagleboard
cp $BBDIR/u-boot-beagleboard.bin /media/boot/u-boot.bin
cp $BBDIR/uImage-beagleboard.bin /media/boot/uImage
cp $BBDIR/MLO-beagleboard /media/boot/MLO

I think the boot partition will work for most of the images; only thing likely to change is the Linux kernel, uImage. The next part is a bit trickier. After building several images overnight, I found all the files still present on my machine, so I chose console-image since it's unlikely to run into any weird hardware dependencies and it's easy to test. This shell command will unpack the file system image onto the SD card's second partition.

bunzip2 < $BBDIR/Angstrom-console-image-glibc-ipk-2011.03-beagleboard.rootfs.tar.bz2 \
  | (cd /media/Angstrom/; sudo tar xvf -)

Just for yucks I confirmed that md5sum gave the same checksums for /media/boot/uImage and /media/Angstrom/boot/uImage.bin. Then I plugged it in, and CRAP, it just started working.

Putting the board on a network edit

Get a USB hub with an ethernet connection. Put in an SD card with a standard console-image build. Plug the hub into the Beagleboard and connect an ethernet cable to a subnet, and networking should work on reset, and then you can ssh into the board as "root" with no password. Now type

opkg update; opkg install guile

and VOILA, you have Guile Scheme. It is an amazing thing to behold.

Like Ubuntu or other modern Linux distributions, an Angstrom image is built out of packages, each being a set of files, and there are dependencies between packages. The package management tool for Angstrom is opkg. It installs prebuilt packages which end up on the SD card so they survive a power cycle. After running "sync" you can pop out the SD card and save it, so you can build up the image you want that way, and you can later say "opkg list-installed" to see what you've got.

Your own little opkg repository edit

If you want to set up an opkg repository for your own packages, you'll need to hunt through anstrom-setup-scripts/build/tmp-angstrom_2008_1 to find your *.ipk files. Each package will produce three, with names like these, and you won't need the "-dbg" or "-dev" versions.

helloworld-dbg_1.0.0-r1.6_armv7a.ipk
helloworld-dev_1.0.0-r1.6_armv7a.ipk
helloworld_1.0.0-r1.6_armv7a.ipk

I found my two packages in these places. I don't know why they ended up in two different destinations.

angstrom-setup-scripts/build/tmp-angstrom_2008_1/deploy/glibc/ipk/beagleboard/quux-module_1.0.0-r100.6_beagleboard.ipk
angstrom-setup-scripts/build/tmp-angstrom_2008_1/deploy/glibc/ipk/armv7a/helloworld_1.0.0-r1.6_armv7a.ipk

In the same directory where you find each *.ipk file, find the Packages file, a large text file containing machine-readable package descriptions. Copy the descriptions for your ipks into a Packages file in your repository directory and gzip the result to produce a Packages.gz file. Configure lighttpd (see below) so that the directory is available on your subnet. Confirm the URL for reaching your Packages.gz file. On my subnet, it's http://10.10.228.138:8181/Packages.gz.

On your Beagleboard, create a file /etc/opkg/mystuff-feed.conf following this example. I think as long as it ends in ".conf", the actual name may not be crucial.

src/gz mystuff http://10.10.228.138:8181

When that's all set up, try

opkg update ; opkg install my-package

Be sure to use the actual name of your package. Anyway, assuming that works, you never need to build a complete image again, you can do everything with console-image and opkg. Remember that when you install a package it gets copied to your SD card. This process doesn't happen immediately, but you can force it to happen right away by typing "sync".

Running a lighttpd server edit

You can easily set up a little lighttpd server on the subnet connecting your development machine and Beagleboard. This is useful for two things.

  • Bitbake (running on your development machine) wants to fetch tar.gz or tar.bz2 files from a HTTP server.
  • The Beagleboard's opkg command wants to pull IPK modules off a repository, and theoretically you can run one.

First type sudo apt-get install lighttpd, then start the server with the command lighttpd -D -f lighttpd.conf, using the following config file.

server.document-root = "/path/to/angstrom/package/tarballs"
server.port = 8181
mimetype.assign = (
  ".gz" => "text/plain",
  ".bz2" => "text/plain",
)

To build a couple of example modules for use by bitbake, I have a shell script that automates a few steps for me. The sources for my BB recipe files (1, 2) have everything except the checksums, which are appended automatically by this script, and then the script kicks off the lighttpd server.

Kernel modules edit

If you've primarily worked with 8-bit controllers, you're accustomed to the idea that you GPIO pins and other peripherals are easy to read or write at any point in your code. On a 32-bit controller, Linux makes a distinction between user space where your code is running and kernel space, and the kernel mediates access to peripherals thru device drivers (which are a particular sort of kernel module), which make peripherals look like files that you read and write (since everything in Unix is a file). When the file analogy breaks down, Unix offers a back door called ioctl which gives you fairly arbitrary ways to communicate with the peripheral. The reason for all this complexity is because Unix is running many different processes simultaneously which might bump into one another, and some shouldn't be allowed access to peripherals at all for security reasons.

http://tldp.org/HOWTO/Module-HOWTO/ provides background on Linux kernel modules. It's not too hard to write a vanilla package for the Beagleboard, but a kernel module is a bit trickier. The best lead I've come across is a lab session from a university course using Beagleboard. Their source code is pretty simple (see below). They like this textbook so maybe I should pick up a copy myself.

#include <linux/module.h>
static int __init hello_init(void)
{
    printk(KERN_INFO "Hello Example Init\n");
    return 0;
}
static void __exit hello_exit(void)
{
    printk(KERN_INFO "Hello Example Exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Chris Hallinan");
MODULE_DESCRIPTION("Hello World Example");
MODULE_LICENSE("GPL");

To build it, I use this one-line Makefile:

obj-m := hello.o

and this build script:

#!/bin/bash
export SYSROOTS=${HOME}/angstrom-setup-scripts/build/tmp-angstrom_2008_1/sysroots
export PATH=${PATH}:${SYSROOTS}/i686-linux/usr/armv7a/bin
export ARCH=arm
export CROSS_COMPILE=arm-angstrom-linux-gnueabi-
export KERNELDIR=${SYSROOTS}/beagleboard-angstrom-linux-gnueabi/kernel
make -C ${KERNELDIR} M=$(pwd) modules

and that happily builds hello.ko, the kernel module. Next I copy it to the /home/root directory of my SD card and boot the Beagleboard, and voila:

# insmod hello.ko
[  239.257354] Hello Example Init
# lsmod
Module                  Size  Used by
hello                    573  0
rfcomm                 33484  0 
ipv6                  249063  8 
hidp                   11193  0 
l2cap                  30104  4 rfcomm,hidp
bluetooth              49221  3 rfcomm,hidp,l2cap
rfkill                 14838  1 bluetooth
# rmmod hello
[  246.670227] Hello Example Exit

Now copy hello.ko into the proper place for kernel modules.

# mkdir -p /lib/modules/2.6.32/kernel/drivers/char/examples/
# cp hello.ko /lib/modules/2.6.32/kernel/drivers/char/examples/
# depmod
# modprobe hello

modprobe is preferable to insmod because it's better integrated into how the kernel module system usually works. People don't usually manually insmod modules.

Kernel module as an Angstrom package edit

Having found it difficult to get bitbake to build the kernel module, I used it only to install a prebuilt hello.ko file. So hello.ko and a shell script are now the only things in my tar.bz2 archive. After banging my head on this for several days, I was finally able to write a kernel driver that creates a simple character device. Installing the module in your Angstrom build will put the file quux.ko in your /lib/modules tree, and this shell script will be found in your /home/root directory.

#!/bin/sh
modprobe quux || echo Ouch
MAJOR=$(dmesg | grep 'quux major' | tail -1 | sed 's/.*=//')
mknod /dev/quux c ${MAJOR} 0
cat /dev/quux
cat /dev/quux
cat /dev/quux
cat /dev/quux
cat /dev/quux

When you run tryit.sh, you see this::

[   37.023468] quux major=249
[   37.026611] Try: mknod /dev/quux c 249 0
Kernel module says: Hello world!
I already told you 1 times Hello world!
I already told you 2 times Hello world!
I already told you 3 times Hello world!
I already told you 4 times Hello world!

A lot of the information I needed came from the Linux Kernel Module Programming Guide, highly recommended. Section 4 of this deals with drivers for character devices. More cool info in the O'Reilly book.

Next I just need to wire up the driver to some real hardware.

Access to peripherals edit

There are some pushbuttons and LEDs on the Beagleboard. How can we get access to them? There is a magic region of the file system called Sysfs built right into the Linux kernel, so we don't need to write or find some special kernel module to enable this. Sysfs is a "virtual filesystem" which presents a simple file-like interface for dealing with what would otherwise be complex and mysterious hardware bits. Remember the scary 3500-page technical manual? Sysfs helps defer the day you need to read it.

The region of interest is /sys/class, and its usage looks like this. Similar things can be done in C, Perl, Python, etc. There are other regions (/sys/devices, /sys/bus, /sys/block) that are also useful but I haven't read the docs (1, 2) thoroughly enough yet to discuss them intelligently.

#!/bin/sh

LED=/sys/class/leds/beagleboard::usr0
BUTTON=/sys/class/gpio/gpio7
# take control of an LED. first stop triggering it with the heartbeat.
echo none > $LED/trigger
# grab the user pushbutton on GPIO7, creating /sys/class/gpio/gpio7 dir.
echo 7 > /sys/class/gpio/export
# make sure the button GPIO is an input.
echo in > $BUTTON/direction

finished () {
    # restore things to previous state and quit
    echo heartbeat > $LED/trigger
    echo 7 > /sys/class/gpio/unexport
    echo
    exit 0
}

echo Press the user button and watch the LED
trap finished SIGINT   # finish when user hits control-C
while true; do
    # read the pushbutton and turn the LED on and off
    cp $BUTTON/value $LED/brightness
done

The kernel source file that performs all this magic is board-omap3beagle.c. As of this writing I haven't wrapped my head around what's going on in there. The I/O code for the OMAP is more complicated than I feel like thinking about right now.

GPIO pins are available on the expansion connection J3 which appears on sheet 8 of the schematic. GPIO #7 discussed here appears in the lower right corner of sheet 4. Some of the other convenient GPIOs are #132 thru #139, respectively on odd-numbered pins 17, 15, 13... 3 on J3, and pins 27 and 28 are ground, and pin 2 provides +5 volts while pin 1 provides +1.8 volts. Because the GPIO lines connect directly to the OMAP chip with no buffering, they all run at 1.8 volts as well, which is slightly inconvenient in a world of predominantly either 3.3v or 5v.

In one case where I needed to drive some 3.3 volt logic from the Beagleboard, I put 3.3K pull-ups from the outputs to the 3.3 volt rail and that seemed to work fine without damaging the Beagleboard. I also had one input pin operating at 3.3 volts and I fed it directly to the Beagleboard with no voltage limiting, and again it appears to have done no damage. I can't recommend reckless behavior as a general rule but it seemed OK in this instance. I haven't looked at the OMAP datasheet recently to remember whether they comment on that approach.

Resources edit

Useful books edit

Useful URLs edit

Time permitting, I will filter these better for usefulness. Here is an online manual for OpenEmbedded, but that is subtly different from Angstrom, the exact relationship between them is unclear. So not sure that's useful, but it deals with a lot of the tools.