Saturday, April 30, 2011

uClinux on the LPC-E2468

The story...
Some time ago I was given an Olimex LPC-E2468 development board. My company bought it for a project but ended up not using it. A couple of weeks ago I finally got around to hooking it up and very soon understood why they didn't. The manual from Olimex basically says to run 'make config' and 'make', and you will have a kernel image to load onto the board. Sounds too easy to be true? You're right!

In this article I will try boil down more than a week of compiling, googling, recompiling, scrapping it all, compiling again, giving up, starting over... I will try explain the steps necessary to compile a working kernel and create a romfs image.



Disclaimer and tips
Before we start, I take no responsibility for any consequences of doing anything mentioned on this page. It worked for me. It might crash your system, even though it should work fine. 
I assume you are a fairly advanced Linux user, who know how to compile software from source. I use Ubuntu and the packages are for this ditribution, but the methods are generic. I also assume that the normal GCC toolchain is installed. On Ubuntu this can be done with 'sudo aptitude install build-essentials'.
I posted the paths I used but unless your username is andreas, make sure what you copy and paste match your reality. Also, depending on linux version and the date you try this, you might get a differently named binutils archive, so check the paths.
You will not modify your main /usr, /lib, /etc tree, but you will use sudo to install packages so take care.
I have not figured out an easy way to include code in the blog that preserves linebreaks in the blog so check your commands before running them. Especially the long one for configuring elf2flt.
Last, but not least, do NOT run 'make clean' or 'make mrproper' in your uClinux tree. You will loose all configuration files and have to setup a complete kernel from scratch...
All that said, let's get started.

Get it going
The first major step is to install the arm-linux-gcc toolchain. This proved to be quite a a challenge since one part depends on another and you only have the latest error message to work with. The following is what I came up with.
  1. Install necessary packages. These were needed on my system. If your's complain about anything else do a search in your repository for the developer version that contains the header files with descriptions.
    You'll need compressor for elf2flt later on. Choose, lzma-dev was available on Ubuntu 8.04 and xz-utils in 9.10. Both seem to work.
    Genromfs is used to create the romfs image with your filesystem.
    Binutils wants texinfo to build the manual that we won't use...
    Tftpd is for loading the images on to the board in the end.
    sudo aptitude install ncurses-dev genromfs texinfo tftpd xz-utils

  2. Create a build directory. This is wher we will put everything else. Open a terminal and create a new directory called arm:
    mkdir arm
    cd arm

  3. Copy files from the CD to your build directory.
    This is easiest done with a graphical tool like Nautilus. Copy uClinux-dist-lpc_e2468.tgz from the uClinux-dist directory and arm-linux-gcc-4.1.1-920t.tar.bz2 from Utils.

  4. Unpack the arm-linux-gcc. This is the compiler and linker for the ARM architecture.
    tar jxf arm-linux-gcc-4.1.1-920t.tar.bz2
    Rename it to make it easier to work with
    mv 4.1.1-920t uclibc

  5. Set paths to the new directories.
    PATH=$PATH:~/arm/uclibc:~/arm/uclibc/bin:~/arm/uclibc/arm-linux/bin
    You can also add this to your .bashrc file so that every new shell will have the paths.

  6. Build binutils binaries. We don't actually need the executables, just some object files to link in when building elf2flt later on.
    sudo aptitude download binutils-source
    Extract it with:
    mkdir binutils-source
    dpkg -x binutils*.deb binutils-source
    The Ubuntu package had another compressed image inside, which we will move to our root and uncompress:
    cd binutils-source/usr/src/binutils
    mv binutils-2.18.0.tar.bz2 ~/arm/
    cd ~/arm
    tar jxf binutils-2.18.0.tar.bz2
    Configure and build:
    cd binutils-2.18.0*
    ./configure --target=arm-linux --prefix=/home/andreas/arm
    make
    Don't make install, we only need the object files for the next step

  7. Build elf to flat utility. This convert ELF headers to a flat format. I've not dug deep into how this works, but it is tool we need. It will replace the original linker with a script that adds this functionality and then calls the linker. Thus you need to configure it with the path to your build root.
    Download elf2flt from git, https://docs.blackfin.uclinux.org/doku.php?id=toolchain:elf2flt
    Unpack the archive:
      tar jxf elf2flt*.tar.bz2
    Configure and build: (replace the paths to match your name and version)
    ./configure --target=arm-linux --prefix=/home/andreas/arm/ --with-bfd-include-dir=/home/andreas/arm/binutils-2.18.1~cvs20080103/bfd --with-libbfd=/home/andreas/arm/binutils-2.18.1~cvs20080103/bfd/libbfd.a --with-libiberty=/home/andreas/arm/binutils-2.18.1~cvs20080103/libiberty/libiberty.a --with-binutils-include-dir=/home/andreas/arm/binutils-2.18.1~cvs20080103/include
    Edit ld-elf2flt.c and comment out #include <filenames.h>. Don't know what it does except give errors... Works fine without, though.
     nano ld-el2flt.c
     make
     make install

  8. The next big step is to prepare the uClinux tree so that it compiles It turned out that some crucial things were left out when shipped. Well, we'll correct them below. Don't run any make commands before this is done. Unpack the uClinux-dist. This is the kernel tree, filesystem image and user space programs. You will probably spend most of your time configuring the files in here. If you somehow mess up the configuration or get lost you can always remove this directory and unpack it again.
    tar zxf uClinux-dist-lpc_e2468.tgz

  9. Fix the directory structure. It turned out that some crucial things were misnamed or missing, so here we add some symlinks and rename the kernel directory.
    The first thing the make script will complain about after running 'make menuconfig' is that it can't find the kernel directory 'linux-2.6.21.4.lpc2468.patched.x'. If you look closely you'll see it's named almost the same as the one in your directory, so we'll rename it.
    cd uClinux-dist-lpc_e2468
    Change name of linux dir
    mv linux-2.6.24.2-lpc2468-patched/ linux-2.6.24.2.lpc2468.patched.x
    Add armnommu symlink in arch
    cd linux-2.6.24.2.lpc2468.patched.x/arch
    ln -s arm armnommu
    Add asm-armnommu symlink in include
    cd ../include
    rm asm ;# remove the old one, it's wrong
    ln -s asm-arm asm-armnommu
    ln -s asm-armnommu asm
    cd ..
    cd ..
    Add symlink to default config
    cd vendors/NXP/LPC2468
    ln -s config.linux-2.6.x config.linux-2.6.24.2.lpc2468.patched.x
    cd ..
    cd ..
    cd ..

  10. Configure the kernel. Now that the enviroment is all set up we can start configuring the kernel for the first compilation.
     make menuconfig
    Verify that the Vendor/Product Selection is correct
    In Kernel/.../Settings choose Customize Kernel Settings and Customize Vendor/User Settings.
    Press Exit, Exit and save changes

  11. Kernel configuration. In the Kernel configuration go to Boot Options->Default Command Line. By default it tries to load the initial ram disk from the wrong address(well it could probably work, but the one below seems to be more standard) and more inportantly it uses the wrong console. The latter means that your kernel might be working fine, you would just not see any output (or maybe garbage) unless you change your terminal speed, which is inconvenient in the middle of a session. This took me a while to figure out. Paste this line in to the text field.
    root=/dev/ram initrd=0xA0800000,4096K console=ttyS0,115200N8

  12. More kernel. System Type. We have 16Mb of RAM, which is 0x1000000 bytes.
    Set correct SDRAM size to 0x01000000
    Set board type to Olimex LPC-E2468

  13. Exit all the way and Save changes. The Vendor/User config will popup. Just Exit and save changes. While this seems unnecessary it sets default values for a lot of options that you would otherwise have to set one by one on the command line. Now you are ready to compile.

  14. Build the kernel and rom filesystem. Because I'm curious about how long time it takes I usually run it with time and print the date/time when it finishes.
    time make;date

  15. Find your files. If everything goes well the kernel image will be located at linux-2.6.24.2.lpc2468.patched.x/arch/arm/boot/Image
    and the romfs image will be
    images/romfs.img
    While the second one seem obvious, the kernel location is not. There is actually an image.bin file in images but it's too big and doesn't work. I found the correct one by trial and error, and by looking for one that was roughly the size of the precompiled one.
  16. Setup tftpd and assign a static IP address. There are many ways to do it but this works for me. I have a crossed Ethernet cable between my board and laptop, but you can just as well use a switch and straight cables, which also has the benefit of not losing the connection every time you unplug the board. Some computers can use a straight cable direct to another device.
    If you are using a GUI Linux you can set a static IP there, I happen to use 192.168.0.202. On the command line it is
    sudo ifconfig eth0 192.168.0.202
    tftpd uses /srv/tftp as root directory on Ubuntu so you can either copy your files there or, more convieniently, make symlinks to your image and boot directory.
    ln -s /home/andreas/arm/uClinux-dist-lpc_e2468/images /srv/tftp/images
    ln -s /home/andreas/arm/uClinux-dist-lpc_e2468/linux-2.6.24.2.lpc2468.patched.x/arch/arm/boot/ /srv/tftp/boot
    ln -s /srv/tftp/boot/Image linux.bin
    ln -s /srv/tftp/images/romfs.img romfs.bin
    The last two are not necessary but are the names used in the default uBoot tftp_boot script, and that speeds up testing, since you can type 'run tftp_boot' in u-boot to load everything in one step.

  17. Set up the board. Plug in the board via USB and start a terminal. Assuming your board is the only USB-serial adapter it would be:
    screen /dev/ttyUSB0 115200
    Press reset on the board and you should see uBoot starting up. Press any key to interrupt the loading process to get a command prompt.
    Check the environment variables for network settings:
    printenv
    You should see something like this:
    ipaddr=192.168.0.157
    netmask=255.255.255.0
    ethaddr=00:de:ad:b0:05:02
    serverip=192.168.0.100
    Change serverip to match your computer's IP and save to flash:
    setenv serverip 192.168.0.202
    saveenv
  18. Download the firmware. First load the kernel to RAM:
    tftpboot 0xa0008000 /boot/Image
    Then load the ROM file system:
    tftpboot 0xa0800000 images/romfs.img
    Finally start the kernel:
    go 0xa0008000
  19. Voila! The kernel should be loading and in few seconds you get a command prompt.
    You have aquite limited system at this stage, but you can always run 'make menuconfig' to change kernel features and user packages.






2 comments:

  1. hi!
    Do you have any ideas about I can't find lsmod and insmod commands in this kernal.

    thank you!

    ReplyDelete
  2. If I remember right you compile in the modules from the beginning. My SDRAM chip gave up so I haven't worked on it for a long time.

    ReplyDelete