These days, hardly a week goes by without some new toy for a hacker to play with. Few of those toys take the world by storm the way the Raspberry Pi has. Released earlier this year, demand for the Pi has outstripped supply so much that some people are still waiting for their preorders. If you look it up on Amazon, you’ll see shops trying to sell the Pi for a considerable markup over its $35 list price. Frankly, it’s a little crazy.
I’ve never been a fan of preorders (though Kickstarter has started to change that), but when I noticed that Newark had them in stock last month, I couldn’t resist getting one. $35 is enough of an impulse buy that I wasn’t too concerned about what I was going to do with it.
The Raspberry Pi is an attempt to build a cheap, small computer, primarily for educational purposes. The board’s so small that it’s got connectors coming out of every edge, which would actually be inconvenient if I were trying to mount it anywhere. The simplest thing you can do with the Pi is hook up a keyboard, mouse, and monitor, plug in an SD card with a boot image, and have a cute little Linux box running a flavor of Debian. There’s not a huge amount of horsepower here, but the Pi’s 256 (or 512) MB of RAM and 700 MHz processor is more than enough to create a usable X desktop environment. So there are plenty of people looking at the Pi as a way to do a home theater PC or a terminal, or to run projects that need more computational horsepower than an Arduino.
The Pi doesn’t have all the features of a microcontroller – it doesn’t have built-in support for analog I/O like the Arduino, for example. It does have a block of I/O pins that can be controlled by users, and those pins include a UART (for asynchronous serial) and hardware support for protocols like SPI (which I’ve talked about before) and I²C (which I think I’ll need for an upcoming project).
Of course, another thing you can do with a simple machine like this that you aren’t afraid to break is to get in at the bottom. That’s where I’ve been getting started. Since getting my hands on the Pi, I’ve been making my way through the “Baking Pi” tutorial created by Alex Chadwick, a CS student at Cambridge. The goal of the tutorial is to introduce bare metal programming of the Pi in its native assembly language, and use that to build toward the simplest operating systems concepts. (And I do mean simplest – I think the final part will be a command line with text display).
So far I’ve gone through six of the tutorial’s 11 segments. I’ve been deliberately pacing myself, because I’ve found that I retain information better that way, so I’ve done one section each week. They usually only take an hour or so, unless something goes wrong – and that’s when it gets interesting. The next few sections are going to ramp things up a bit, so I’m looking forward to that.
For me, there are a few interesting things about this particular course. One is the idea of a from-scratch operating system, because that ties into some ideas for future projects that I’ve been playing with. It’s been interesting to see how to interact with the Raspberry Pi hardware without any supporting libraries. So far I’ve gotten an introduction to the I/O pins and timers, and I’ve just started communicating with the graphics hardware. I’ll get to the USB interface in a couple more sessions, and that should also be interesting.
The assembly language for the ARM processor has been a real contrast to the 6502 assembly I’ve been using in my hobby projects. The ARM may be a poster child of RISC (reduced instruction set computing), but it’s a lot bigger and more complicated than the 6502. Even the individual instructions are more complicated, with variable numbers of arguments, optional conditionals attached, and so forth. The clearest distinction is that the CISC 6502 will operate on memory directly, while the ARM is more clearly a load/store architecture with everything going through registers. I think in this case the decades between these two processors kind of overshadow the architectural differences of RISC versus CISC.
Another thing that’s been interesting to me is seeing how application binaries are laid out in memory. I’ve learned some interesting things about linkers that you usually gloss over when writing applications in high-level languages. As is so often the case, I learned the most when something stopped working. In this case, a change to the Pi’s bootloader screwed up some of the assumptions about memory layout that the build files for the tutorial were using. After searching online, I learned what the problem was and how to adjust the linker files so that the relative addressing for my code would work correctly.
A similar, uh, opportunity, came up last night, when I was working on the first screen tutorial, Screen01. The goal of the tutorial was to tell the graphics system to give me a framebuffer of a particular size, and draw to it. Nothing you’d consider complicated. I went through quite a few iterations of staring at a black screen on my monitor before figuring it out. And let me tell you, when you don’t have any other I/O working, it can be hard to debug something like that. I resorted to flashing the Pi’s “OK” light in different patterns to see where my code was going.
This proved tricky because there doesn’t seem to be a lot of low-level information about that part of the Pi’s hardware floating around. Indeed, the whole graphics system is a proprietary black box, which seems to be one of the biggest criticisms of the Pi’s architecture. Even the author of the tutorial didn’t seem to have a deep understanding of why some things were happening, and the forum discussion I found showed a lot of pretty confused back and forth. The underlying issue turned out to be pretty subtle, and masked by another issue with the Raspberry Pi’s firmware.
One of the things that modern computers have that a 6502 system doesn’t is a cache – usually several levels of cache. That’s not a big deal when you’re writing in a high level language – you might have to mark a few variables as volatile, but most of the effects are well hidden. In this case, my code couldn’t see some of the data written by the graphics hardware (like, the address of the framebuffer I requested) because those changes weren’t written from the cache back to memory. There’s a way to change the way memory used for I/O is cached, but apparently that wasn’t working correctly with some versions of the Raspberry Pi’s firmware. Combine those two problems, and you got a lot of solutions that worked for some people and not others, or that worked sometimes but not always.
With all the pieces in place, it’s all humming along nicely. In this case I didn’t get much further than drawing gradient color bars. The next section of the tutorial is talking about Bresenham’s Line Algorithm, which I’ve implemented on the C64 before, so that should be a lot of fun.