Fun with E-Ink, X and Gumstix
I'm excited by E-paper and the promise it holds. You've probably already heard about E-Ink's E-Paper Display (EPD) and seen it in recent E-book reader products. The E-Ink display media needs no power to hold an image, and it reflects light just like real paper. I've even seen recent products that make use of the physical flexibility of the E-Ink film in order to create “rollable” displays. But yes, this technology still has a few constraints. Current EPD displays are grayscale only and have measurable display latencies. However, I'm convinced that these limitations will disappear over time, as has happened with many other disruptive technologies.
E-paper devices have been on the market since around 2006 or so. The good news is that Linux has become the de facto standard operating system for almost all of these devices. The two major products, Amazon Kindle and Sony PRS series, both utilize embedded Linux to achieve their functionality. Those products are great, but it also is fun to build your own device and use your own applications. That is where the Gumstix embedded device comes into play. E-Ink has a kit called the AM200 E-Paper Development Kit that provides all the hardware accessories you need to build your own E-paper device. Best of all, the kit is designed to work with Linux and is quite hack-friendly.
The AM200 kit serves to provide proof of concept for E-Ink. The software it provides helps you run a user-space application that lets you decode portable pixel map (PPM) images to the display. This is just to demonstrate the basic capabilities of the kit. It does not let you run normal X11 applications, such as xterm or xeyes. That's where this article comes in—it should help you add a set of building blocks that expand the system's functionality. These building blocks will enable the system to support a standard X server. Once you've gotten an X server on the system, you pretty much can run anything that's available from the realm of the penguin and the wildebeest, including your favorite Web browsers and PDF readers.
First, let's do a quick review of the hardware infrastructure we're using to better understand the software we need to add. The display shown in Figure 3 is an E-Ink Vizplex display that has a Thin-Film Transistor (TFT) back end. This is connected through the fine pitch (FPC) ribbon cable to the adapter board. This adapter board is there to distribute the correct signals to the display connectors and also to provide some expansion buttons that can be accessed using General-Purpose Input Output (GPIO) from the Gumstix. This adapter board sources its signals from the Metronome controller board, which is the display interface. It carries the Metronome controller, which has an associated Linux framebuffer driver called metronomefb to which X will be talking. The Metronome controller board is connected via another FPC ribbon cable to the Gumstix board. The Gumstix board has the XScale PXA255 CPU and all the associated interfaces, such as Bluetooth, SD card, USB and others. The Lyre mainboard is the carrier for the Gumstix board. This Lyre mainboard has the power block, battery stuff, status LEDs, USB network interface and USB serial interface that allows us to control the Gumstix from a standard PC.
Now, let's dig in to the software side of things. The Gumstix board has relatively strong Linux support. That said, the development environment for it is not yet perfect. But, these things are continuing to see rapid change, so be prepared to roll up your sleeves and hack a bit.
When your Gumstix board arrives, it could have one of two possible firmware configurations. The first is firmware built using a set of tools called buildroot. Buildroot is a collection of makefiles and scripts to help you set up a cross-compile environment for embedded systems. Buildroot will help you pull down everything you need to build a root filesystem image for your Gumstix board automatically. It was the de facto standard for Gumstix until about a year ago. The second possibility is a board with firmware built using the OpenEmbedded (OE) framework. OpenEmbedded is a new software framework for building embedded distributions. It is quite a bit more advanced than buildroot in terms of capabilities. It also is the currently preferred build environment for Gumstix. For the purpose of this project, either one should be good enough, and both are fairly easy to use. I cover the steps for both of them in this article.
The new software building block that we'll add to this system is something called deferred IO. Deferred IO is a recently added hack in the Linux kernel that allows nonmemory-mappable devices to pretend to be memory-mappable. It also allows us to hide the latency associated with the E-Ink display. This hack is what makes it possible to run X with various E-Ink controllers on Linux. We'll also add the Metronome and AM200 drivers that provide the Linux framebuffer interface for the Metronome controller together with the Gumstix board.
Okay, now we can do some real work. The first thing to do is establish a working environment on the Gumstix. Power on your Gumstix board and connect the two USB ports to your host machine. This lets you set up the USB-serial console and also creates a USB-net connection with which to transfer files. You can use minicom or cu to use the Gumstix serial console. If your board is in working condition, you should see this when you connect:
Connected. Welcome to the Gumstix Linux Distribution! gumstix login:
The user name is root, and the password is gumstix. Log in to check whether your SD card works. If all is well, you should see the following:
gumstix login: root Password: Welcome to Gumstix! # mount /dev/root on / type jffs2 (rw) proc on /proc type proc (rw) /sys on /sys type sysfs (rw) udev on /dev type ramfs (rw) devpts on /dev/pts type devpts (rw) /dev/mmcblk0p1 on /mnt/mmc type vfat ↪(rw,sync,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1) tmpfs on /tmp type tmpfs (rw)
The line with a mount entry called /mnt/mmc shows there is working SD card support.
Now that we've established a working environment, we can approach building the kernel. We want to use the 2.6.25 kernel, because it supports all the devices we are interested in and has the features we've talked about so far. To build this kernel, we need some things from our development environment—that is, the cross compiler that will allow us to compile binaries for the XScale CPU using a standard x86 host. Don't be frightened by this. It's not that hard. As mentioned before, there are two choices of tools to set up everything for you. The first is buildroot. I used the following incantation to set up a buildroot environment:
# mkdir gumstix_build # cd gumstix_build # svn co -r1441 http://svn.gumstix.com/gumstix-buildroot/ ↪trunk gumstix-buildroot # make defconfig # make
This pulls down revision 1441 of the buildroot build. Select the appropriate option for your Gumstix board. Mine was a basix, so I selected the BR2_TARGET_GUMSTIX_BASIXCONNEX and GUMSTIX_400MHZ entries. This build revision worked fine on my Ubuntu Edgy build machine, but you may need to experiment with the revision tag to find one that builds well on your chosen system. This build stage takes a while, as buildroot pulls down a wide set of sources and starts building everything from scratch. It will take at least several hours even on high-end machines. I typically leave this stage running overnight. Once it completes, key utilities will be added to your path. The ones that are necessary to our operation are:
./build_arm_nofpu/staging_dir/bin/arm-linux-gcc ./build_arm_nofpu/staging_dir/bin/mkimage ./build_arm_nofpu/staging_dir/bin/arm-linux-objcopy
That should settle things for buildroot users. If you are using OE, your incantation is slightly different:
# mkdir gumstix_build # cd gumstix_build # svn co https://gumstix.svn.sourceforge.net/svnroot/ ↪gumstix/trunk gumstix-oe # . ~/gumstix/gumstix-oe/extras/profile # # edit your build config to select the # # right machine (basix, connex, or verdex) # bitbake gumstix-basic-image
Bitbake manages the dependencies and figures out what to build and how to build the cross-compilation environment. Suffice it to say that this stage is not the speediest to complete, so plan on taking an extended break before your tools are ready. On my build machine, the OE build takes about two days to complete. Please refer to the Gumstix OE Build Details link (see Resources) in order to set up your build config for your Gumstix board.
Now that you have a working environment, you need to pull down the mainline kernel tree that has the driver for the E-Ink Metronome controller and deferred IO support. I typically just pull down Linus Torvalds' latest tree. Once that is done, select and build using the right config file for your kit. On mine, the steps to do this are:
# git pull git://git.kernel.org/pub/scm/linux/ ↪kernel/git/torvalds/linux-2.6.git # cd linux-2.6 # cp arch/arm/configs/am200epdkit_defconfig .config # make CROSS_COMPILE=arm-linux- ARCH=arm oldconfig # make CROSS_COMPILE=arm-linux- ARCH=arm menuconfig
Then, select Device Drivers→Graphics support→Support for framebuffer devices, and make sure to turn on the module option for AM200 E-Ink EPD devkit support. Here's the next step, which builds some binaries:
# make CROSS_COMPILE=arm-linux- ARCH=arm # arm-linux-objcopy -O binary -R .note -R .comment ↪-S arch/arm/boot/compressed/vmlinux linux.bin # mkimage -A arm -O linux -T kernel -C none -a 0xa0008000 ↪-e 0xa0008000 -n "uImage" -d linux.bin arch/arm/boot/uImage
This uImage file is what we will feed to the bootloader for our kernel. We also need to copy the modules that are used by the framebuffer drivers that we need to support X. We need to transfer these files to the SD card. The simplest way is to use an SD card reader and transfer it using your normal desktop mechanism. For example:
# cp arch/arm/boot/uImage /media/sd/ # cp drivers/video/metronomefb.ko drivers/video/am200epd.ko ↪drivers/video/sys*.ko drivers/video/fb_sys_fops.ko /media/sd/
Once that's done, you're ready to boot your new kernel on the Gumstix. To do this, you need to interrupt the normal boot process. On the Gumstix serial console, type reboot, and press any key to interrupt the normal boot process.
After that, you can use the following sequence of u-boot commands to let u-boot read the SD card, then retrieve and load the kernel into memory and finally boot from this memory:
# reboot The system is going down NOW !! Sending SIGTERM to all processes. Please stand by while rebooting the system. Restarting system. U-Boot 1.1.4 (Nov 6 2006 - 11:20:03) - 400 MHz - 1161 *** Welcome to Gumstix *** U-Boot code: A3F00000 -> A3F25DE4 BSS: -> A3F5AF00 RAM Configuration: Bank #0: a0000000 64 MB Flash: 16 MB SMC91C1111-0 Can't overwrite "serial#" Net: SMC91C1111-0 Hit any key to stop autoboot: 0 GUM> GUM> mmcinit MMC found. Card description is: Manufacturer ID = 464450 HW/FW Revision = c c Product Name = Name 3070FDP? Serial Number = 7a6a16 Month = 3 Year = 2007 GUM> fatload mmc 1 a2000000 uimage.bin reading uimage.bin 1094024 bytes read GUM> bootm ## Booting image at a2000000 ... Image Name: uImage Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1093960 Bytes = 1 MB Load Address: a0008000 Entry Point: a0008000 OK Starting kernel ... Uncompressing Linux............ .......done, booting the kernel. Welcome to the Gumstix Linux Distribution! gumstix login: root Password: Welcome to Gumstix! # uname -a Linux gumstix 2.6.25gum-00000-ga052754 #16 PREEMPT ↪Wed Apr 30 22:54:35 EDT 2008 armv5tel unknown
Success! We now have booted a kernel with everything we need. The next step is adding Xfbdev. With OpenEmbedded, this step is fairly straightforward; simply execute the following command:
# bitbake xserver-kdrive
This generates an appropriate package (.ipk) file in the gumstix_build/tmp/deploy/ipk/armv5t/ directory. It should look something like xserver-kdrive-fbdev_1.4-r1_armv5te.ipk. Copy this file to the SD card, and use the following command to install it on your Gumstix:
# ipkg install /mnt/mmc/xserver-kdrive-fbdev_1.4-r1_armv5te.ipk
If you have buildroot, the process is somewhat similar, but you need to do some in-build munging. First, do the following:
# cd gumstix-buildroot # make menuconfig # # Go to Package Selection for Target-> then enable # # the checkbox for the item labeled TinyX. # # This is the other name for Xfbdev. # make
This generates the Xfbdev and associated applications, such as xterm, XLogo, xeyes and others. You can copy these to your Gumstix's root filesystem. At this point, Xfbdev finally is on the system. We're almost at the finish line. On your Gumstix console, load the drivers we copied earlier:
# cd /mnt/mmc # insmod drivers/video/syscopyarea.ko && ↪insmod drivers/video/sysfillrect.ko && ↪insmod drivers/video/sysimgblt.ko && ↪insmod drivers/video/fb_sys_fops.ko # insmod drivers/video/metronomefb.ko # insmod drivers/video/am200epd.ko fb1: Metronome frame buffer device, using 505K of video memory
The fb1 kernel message indicates that we now have a real framebuffer device to play with. Now, we need to point Xfbdev at the right device, so enter this:
# # make fb0 actually become fb1 # rm /dev/fb0 # mknod /dev/fb0 c 29 1 # /usr/X11R6/bin/Xfbdev -ac &
At this point, you should see the familiar crosshatch pattern of X. Yes, we finally did it! We now have an X11-enabled E-Ink display.
What to do next? Well, the Gumstix device has USB-net support, which means you now have a remote X11 display that you can connect to from any other machine on the network. You can point any X11 application at it—for example:
# # 10.0.0.2 is the E-Ink display # # Slideshow # for i in `ls *.jpg` ; do echo $i ; ↪ xloadimage -display 10.0.0.2:0 -global -rotate 90 $i ; ↪ done # # PDF slideshow # (( i = 1 )) ; while (( $i < 21 )) ; do echo $i ; ↪xpdf -remote eink /tmp/mybook.pdf $i -display 10.0.0.2:0 ; ↪sleep 3 ; (( i = $i + 1 )) ; done # # Remote display an Ubuntu desktop on your E-Ink display # DISPLAY=10.0.0.2 vncviewer ubuntu_box:1