What does a geek do with his newest high-tech gadget? Exactly – he’s hacking and/or putting Linux on it! This weekend was the time for my trusty iPod nano to become modded, with the intention to run some self-written homebrew on it.
The good thing about iPods is that it’s almost impossible to brick them. A basic pre-bootloader located in the NOR flash ensures that you can always at least enter disk mode to restore the device to factory defaults. Everything else – the real bootloader and the operating system – is located in a normal partition on the normal data area.
Needless to say, there is already an unsupported, but well-working iPodLinux port for the nano. Installing it involves repartitioning the flash drive to hold a new ext2-formatted Linux root partition, and installing a new bootloader, iPodLoader 2. This nice tool sports a user-friendly boot menu that is really a bliss to work with. Apart from allowing to boot the original Apple firmware, it automatically detects iPodLinux and RockBox installations.
While RockBox is kinda like »a music player firmware done right« (except for the really humble presentation, but this can be fixed with themes), iPodLinux is pretty much what the name suggests: It’s a complete uClinux environment with some iPod-specific drivers for framebuffer and sound. It even has a console :) Normally, it boots directly into »Podzilla«, the main media player application that closely resembles Apples earlier (1G, 2G) iPod interface (including the lack of color).
iPodLinux development is really simple: There are archives with prebuilt development environments available on the iPodLinux site, so I installed them, did a Subversion checkout of the source tree and I was ready to do the first little experiments. Writing basic »hello world« programs for the iPod isn’t anything special – but running them can be a little adventurous, because Podzilla refuses to run executable files directly. I solved the problem by turning off podzilla completely, booting to the console instead. For some strange reason, the console doesn’t offer real editing capabilites. Instead, each button or clickwheel movement generates a character, the center button acting as a Enter key. So I just called my program »d«, which maps to the Play key.
The iPod nano is a media player, designed to play music and display some almost-static graphics. Consequently, Apple didn’t bother to build a high-performance graphics interface. This means that there is no memory-mapped framebuffer. The framebuffer is contained exclusively in the LCD controller, which is external to the PP502x SoC and not directly accessible from it, except for some MMIO. Unfortunately, there is no DMA, too. Every screen update involves writing the pixels, two at a time, over a mere 32-bit MMIO interface. To make things worse, the CPU has to wait for the LCD controller’s ACK after each pixel pair. Long story short, the display interface is an ugly mess.
Some research in the iPodLinux userland source tree revealed some ready-made code that updated screen portions. The code is written in a very generic way, but I decided to use it directly, at least for a little test, before trying to optimize it. The results of this test were a little bit disappointing: A simple screen pattern generator showed not more than 31 fps. However, I continued my work and developed the test application futher. I basically reimplemented the display library, kicking out all hardware-independent code, thus creating a maximally compact nano-only display library. I chose an internal 32-bit screen buffer representation that is much easier to handle than the LCD’s native 16-bpp packed pixel format. Since the display code is basically mostly waiting for the I/O operations to complete, the pixel format conversion is done on the fly and is still »free« in terms of CPU cycles.
I also implemented a minimal sprite engine capable of displaying opaque, transparent or real alpha-blended sprites, everything in pure C without any optimizations apart from GCC’s -O2. The test application used one 55×79 sprite of each type, moved (with clipping) in front of a full 176×132 background. I expected a slideshow of sorts, maybe around 5 or 6 fps. But I was wrong. I couldn’t believe what I saw – the sprites moved around the screen absolutely smoothly! The built-in frame counter revealed almost exactly 60 fps, which is a sign that the framerate isn’t limited by the CPU, but by the LCD. I don’t know why my first test application was so disgustingly slow, but this one really made up for it. Now that I know that there are still plenty CPU cycles to fill, I’ll go ahead and try to implement some other effects.