Tag Archive for embedded

Insignia Infocast

A.K.A. “BB8”, for “Best Buy 8-inch”.
First off, it’s not an alarm clock. For some reason a lot of people seem to mistake it for one. The Insignia Infocast is a Best-Buy branded Chumby device, an “internet media terminal”. It runs Linux on a 800 MHz Marvell PXA168 ARM9, has a 800×600 color touchscreen, 2 GB internal storage (on a microSD card that can easily be swapped out), 128 MB RAM, Compact Flash, SD, 2 USB 2.0 host ports, etc. And it’s extremely hackable. The board has labeled headers for an I2C bus, a 115200 8N1 USART, and 4 GPIO pins (and a good number of other GPIOs scattered around the board that could be repurposed if needed), and there’s source code with examples of using these. The whole thing runs off 5V DC, powered out of the box from a wall-wart, with a coin cell battery for RTC backup. I don’t know yet how much power it needs, but converting it for battery operation should be trivial.

For a piece of consumer electronics sold by Best Buy, it is surprisingly fast and easy to get into…nothing to jailbreak, there’s an easter egg of sorts that lets you in. Once the device is up and running, go to the apps screen, press the logo in the corner to bring up the device info screen, press the pi icon in the upper right corner to bring up a hidden control panel, and press the sshd button to enable SSH login. Log in via SSH (no password needed), type “make” or “gcc”, and it will offer to download and install a toolchain for you. It’s got enough CPU, RAM, and storage space that you don’t necessarily need a cross-compiler, you can do everything on the device itself.

The bottom is held on by four screws hidden under the rubber feet, and one snap-latch at the back near the USB ports…relocate the feet, remove the screws, and pry a bit with a flat-blade screwdriver to get it open. There’s some ventilation slots on the bottom with plastic cover bits that can be easily snapped off with pliers, letting you snake ribbon cables from the serial and I2C/GPIO headers through to the outside world.

The device uses an AU6350 for the USB ports and card slots. For Compact Flash, this chip is limited to PIO mode 6…so there’s no reason to go for an expensive card faster than 25 MB/s (and it’s entirely possible the actual bottleneck would be between this chip and the processor). I haven’t discovered if it would be possible to boot directly from a card, but you can put your own stuff on the card and overlay it over the file system with UnionFS as detailed in this forum post. A current oddity of the software is that it won’t automatically mount a SD card if it’s in the slot at boot, but I did get it to automatically mount the CF card…this may have to do with the fact that I formatted the card as ext3. This is something that merits further investigation.

Some detailed information here, including I2C source code, pictures of the main board, and schematics of the reference platform: http://www.bunniestudios.com/blog/?p=1140

ARM GCC toolchain build

I recently needed an ARM toolchain for a Luminary Cortex M3 microcontroller, and found that much of the information out there was aggravatingly vague and fragmentary, or simply out of date. So, to save others some trouble, here’s the process I used to put together an ARM toolchain using GCC 4.5.0, applicable to both Mac OS X and Linux.

First, some notes about my setup…I like to put my entire toolchain in a subdirectory of my home directory…for example, ~/arm-eabi-none/, with an entry like this in a startup file like .zshrc:

    export PATH=~/arm-none-eabi/bin:$PATH

This allows quick and easy swapping of toolchains by just renaming directories. If you’re building a new toolchain, you can just rename the other to keep it around while you test the new one. So, to start with, add a line like the above to ~/.zshrc, ~/.bashrc, or whatever is appropriate for the shell you use. Mac OS X and most Linux distros use bash by default, I prefer zsh. The following will append that line to .zshrc, creating the file if it doesn’t already exist (modify as needed for the shell you use):

    echo "export PATH=~/arm-none-eabi/bin:\$PATH" >>.zshrc

Now, either run “export PATH=~/arm-none-eabi/bin:$PATH” command or start a fresh terminal so your path is set up before continuing, and create some directories in your home directory:

    cd ~
    mkdir arm-eabi-none arm_build
    cd arm_build

To build a GCC toolchain, you need GMP, MPFR, and MPC. These may be already installed on your system, if not, you’ll need to install them. If you use a package management system, that may simplify things. You may also want to install them on your system, or build them specifically for your GCC toolchain. I chose the last approach, statically linking them into the toolchain to avoid disturbing any existing installs and to reduce dependencies on the system.

While we’re at it, lets get some other stuff we’ll need. You’ll also need binutils, gcc-core and optionally g++, newlib, gdb, and openocd.
GMP can be obtained from http://gmplib.org/, MPFR from http://www.mpfr.org/, and MPC from http://www.multiprecision.org/. The versions I used are gmp-5.0.1, mpfr-2.4.2, and mpc-0.8.1. Download and decompress these:

    wget ftp://ftp.gmplib.org/pub/gmp-5.0.1/gmp-5.0.1.tar.bz2 http://www.mpfr.org/mpfr-current/mpfr-2.4.2.tar.bz2 http://www.multiprecision.org/mpc/download/mpc-0.8.1.tar.gz
    tar -xjf gmp-5.0.1.tar.bz2
    tar -xjf mpfr-2.4.2.tar.bz2
    tar -xzf mpc-0.8.1.tar.gz

And the GCC toolchain…pick an appropriate mirror from http://www.gnu.org/prep/ftp.html and do the same for binutils, gcc-core, g++ if you’re using C++, and gdb. I used gcc-core-4.5.0, gcc-g++-4.5.0, binutils-2.20, and gdb-7.1:

    wget http://ftp.wayne.edu/pub/gnu/binutils/binutils-2.20.tar.bz2 http://ftp.wayne.edu/pub/gnu/gcc/gcc-4.5.0/gcc-core-4.5.0.tar.bz2  http://ftp.wayne.edu/pub/gnu/gcc/gcc-4.5.0/gcc-g++-4.5.0.tar.bz2 http://ftp.wayne.edu/pub/gnu/gdb/gdb-7.1.tar.bz2
    tar -xjf binutils-2.20.tar.bz2
    tar -xjf gcc-core-4.5.0.tar.bz2
    tar -xjf gcc-g++-4.5.0.tar.bz2
    tar -xjf gdb-7.1.tar.bz2

(if you’re wondering where g++ went, it untarred into the gcc-4.5.0 directory)
And newlib, from ftp://sources.redhat.com/pub/newlib/index.html. I used newlib-1.18.0:

    wget ftp://sources.redhat.com/pub/newlib/newlib-1.18.0.tar.gz
    tar -xzf newlib-1.18.0.tar.gz

Now, to build GMP, MPFR, and MPC. Again, I’m building temporary copies and linking them statically, you can skip this step if you want to use existing installed versions, or you can install them system-wide instead.

    mkdir gmp-5.0.1/build; cd gmp-5.0.1/build
    ../configure --prefix=$HOME/arm_build/gmp --disable-shared --enable-static
    make; make install
    cd ../../
    mkdir mpfr-2.4.2/build; cd mpfr-2.4.2/build
    ../configure --prefix=$HOME/arm_build/mpfr --with-gmp=$HOME/arm_build/gmp --disable-shared --enable-static
    make; make install
    cd ../../
    mkdir mpc-0.8.1/build; cd mpc-0.8.1/build
    ../configure --prefix=$HOME/arm_build/mpc --with-gmp=$HOME/arm_build/gmp --with-mpfr=$HOME/arm_build/mpfr --disable-shared --enable-static
    make; make install
    cd ../../

There’s some “make check” targets you should run as well to make sure things are working, though I omitted them from the above.

Finally, to the GCC toolchain. First, you need to build binutils, but the version downloaded above is slightly broken. Open binutils-2.20/gas/as.h and change line 241,

    #define know(p)			/* know() checks are no-op.ed  */


    #define know(p)	do {} while(0)		/* know() checks are no-op.ed  */

When compiling this on my 64-bit Mac Pro, I also had to make some changes to binutils-2.20/binutils/strings.c to disable use of some deprecated data types and functions. This was not necessary on the 32 bit OS X and Linux systems I’ve built this on, and I don’t know if it’s needed on 64 bit Linux systems. There’s probably a cleaner way to do it, but I just commented out the relevant branches of the #ifdefs from lines 83 to 96:

    //#ifdef HAVE_FOPEN64
    //typedef off64_t file_off;
    //#define file_open(s,m) fopen64(s, m)
    typedef off_t file_off;
    #define file_open(s,m) fopen(s, m)
    //#ifdef HAVE_STAT64
    //typedef struct stat64 statbuf;
    //#define file_stat(f,s) stat64(f, s)
    typedef struct stat statbuf;
    #define file_stat(f,s) stat(f, s)

Now, go on and build binutils:

    mkdir binutils-2.20/build; cd binutils-2.20/build
    ../configure --prefix=$HOME/arm-none-eabi --target=arm-none-eabi --enable-interwork --enable-multilib --disable-nls --disable-shared --disable-threads --with-gcc --with-gnu-as --with-gnu-ld
    make; make install
    cd ../../

Building newlib for ARM requires an ARM GCC compiler, but building a full ARM GCC compiler requires newlib. You need to build an intermediate version of GCC using the –without-headers option to let it know it can’t rely on libc headers existing. Also, c++ support is unnecessary for this. Note the different make targets, “make all-gcc” and “make install-gcc”!

    mkdir gcc-4.5.0/build; cd gcc-4.5.0/build
    ../configure --prefix=$HOME/arm-none-eabi --target=arm-none-eabi --enable-interwork --enable-multilib --enable-languages=c --with-newlib --disable-nls --disable-shared --disable-threads --with-gnu-as --with-gnu-ld --with-gmp=$HOME/arm_build/gmp --with-mpfr=$HOME/arm_build/mpfr --with-mpc=$HOME/arm_build/mpc --without-headers
    make all-gcc; make install-gcc
    cd ../../

Next, build newlib:

    mkdir newlib-1.18.0/build; cd newlib-1.18.0/build
    ../configure --prefix=$HOME/arm-none-eabi --target=arm-none-eabi --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls
    make; make install
    cd ../../

Now that newlib’s built, you can build the full GCC:

    cd gcc-4.5.0
    rm -rf build
    mkdir build; cd build
    ../configure --prefix=$HOME/arm-none-eabi --target=arm-none-eabi --enable-interwork --enable-multilib --enable-languages=c,c++ --with-newlib --disable-nls --disable-shared --disable-threads --with-gnu-as --with-gnu-ld --with-gmp=$HOME/arm_build/gmp --with-mpfr=$HOME/arm_build/mpfr --with-mpc=$HOME/arm_build/mpc
    make; make install
    cd ../../

Now, that’s enough to allow you to compile programs, but you will need a debugger as well. Compile GDB:

    mkdir gdb-7.1/build; cd gdb-7.1/build
    ../configure --prefix=$HOME/arm-none-eabi --target=arm-none-eabi --disable-nls --with-gmp=$HOME/arm_build/gmp --with-mpfr=$HOME/arm_build/mpfr --with-mpc=$HOME/arm_build/mpc --with-libexpat
    make; make install
    cd ../../

Note that libexpat must be specified to get full support for things like memory maps sent to GDB from OpenOCD. Make sure it took…GDB will happily continue the configure and build process without XML support without telling you if it is unable to find or use the library, only giving you a “warning: Can not parse XML memory map; XML support was disabled at compile time” message at run time. You should get the following somewhere in your build output when you do make:

    checking for libexpat... yes
    checking how to link with libexpat... -lexpat
    checking for XML_StopParser... yes

I keep OpenOCD separate from my GCC toolchain, again installing it to ~/openocd so I can easily swap versions. You can get the latest release from http://developer.berlios.de/projects/openocd, or check it out of the Git repository with:

    git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd

The release has the advantage of reliability, but I used the latest version in the repository.

Now you’ll want to configure OpenOCD to use the JTAG device you’re using. If you’re using Mac OS X and one of the common FTDI based JTAG interfaces, you’ll want to install libftdi (http://freshmeat.net/projects/libftdi/) first, and use –enable-ft2232_libftdi. I have not had luck getting the FTD2XX direct drivers to work, OpenOCD will run for a bit and then crash. Run “configure –help” to get a list of other supported JTAG devices. I also had to install libusb, which can be obtained from http://www.libusb.org/.

    cd openocd
    mkdir build; cd build
    ../configure --enable-maintainer-mode --prefix=$HOME/openocd --enable-ft2232_libftdi
    make; make install

You will also need to add OpenOCD to your path:

    echo "export PATH=~/openocd/bin:\$PATH" >>~/.zshrc