So I had just got a couple of TI's eZ430-F2013 kits. I saw an ad for them in a magazine, and I thought that a complete microprocessor development kit for just $20 sounded interesting. Aside from a BASIC stamp, I'd never done any micro development before, so I got a couple to play with.
These things are good. They come in a DVD case with all the software and documentation you need to get developing, a USB programmer/emulation tool, and one target board. A pack of three more target boards is $10. In the picture above, that's the programmer on the left side and the target board on the right. When you're about done programming and ready to solder it into something, just unplug the target board from the end and make sure it gets somewhere between 1.8V and 3.6V to run. It even has clearly labeled and easily soldered holes for every pin on the chip. Easy easy easy.
Now, the MSP430 line aren't the most powerful microcontrollers, even a step below the Arduino's ATMega168, but the size and price are right, and they're some of the lowest power chips you can get. In one of the low-power modes, these can run happily with around 12 microwatts. TI has a video of one of these being powered by a few grapes. I've heard of projects that can collect enough RF energy out of the air with a small antenna to power one.
Anyway, once I had a couple of these in hand, I of course needed a project to put them to use. I browsed around the web a bit to look for ideas, and came across a rough description of a fairly simple method for controlling lots of LEDs with a small number of GPIO pins, called Charlieplexing. I just had to try it.
Charlieplexing was developed by Charlie Allen at Maxim, first described here in 2003. Charlieplexing takes advantage of the fact that most GPIO pins have three states they can be set in: output high, output low, and input. An output high pin is connected to a pull-up resistor inside the chip, and can act as a source of current. An output low pin is connected to a pull-down resistor inside the chip, and can act as a sink of current. An input pin is typically set to high resistance, and for our purposes is effectively disconnected.
Lets start off simple. If you apply current to an LED in the right direction, then the current flows through the LED and makes it light up. If you apply current in the opposite direction, however, it prevents any current from flowing through it (and there's no light). That's what diodes are for- LEDs just happen to be a type of diode that emit light. This property allows us to build the simplest possible LED multiplex:
If we apply current from wire 1 to wire 2, only LED a will allow that current to flow through it, and it will light up. Similarly, if we apply current from wire 2 to wire 1, then it will flow only through LED b and make it light up. Now let's step things up a bit:
Here we have six LEDs connected with only three GPIO pins, and it's possible to make any one of them light up at a time. Say, for example, that wire 1 is connected to power, wire 2 is connected to ground, and wire 3 is left unconnected. As you can see, wire 1 is connected to four of the LEDs: a, b, c, and e. However, only LEDs c and e are turned so that current can flow through them from wire 1. And of those two, only LED c provides a path to ground.
With a Charlieplexed grid of LEDs like this, different combinations of one wire connected to power, one other wire connected to ground, and everything else left unconnected will cause just one LED to light up. For our purposes, a microprocessor's GPIO pins set to output high, output low, and input are equivalent to power, ground, and unconnected, respectively. And since we can control the state of those GPIO pins in software, we can start to do some interesting things with the display. The table below shows how different combinations of power high and low cause LEDs in our small matrix to light up. I also show how we can rearrange the circuit slightly so that we get a nice rectangular grid with no blank spots. Note the circuit is completely identical; all I've done is move the LEDs to fill the gaps.
For n GPIO pins, we can build a Charlieplexed array of n*(n-1) LEDs. With four GPIO pins, we can drive 4*3=12 LEDs. Five GPIO pins allows us 20 LEDs. Six pins allows us 30 LEDs:
The problem with Charlieplexing is that we can only really drive one LED at a time. (Yes, it's technically possible to do more than one, but you're better than I if you can figure out how to do that in a useful way.) If we want more than one lit up at a time, we can quickly scan through each of the LEDs one at a time. If we do this faster than about 100 times per second, our eyes can't even see that they're blinking, so it provides a good illusion of them being lit at the same time. However, it also reduces their apparent brightness. Say one LED simply left on throws out n photons per second. If we altnerately light two LEDs, no matter how fast we do it, we can only hope that each one will throw out n/2 photons in a second. Even if we cycle through lighting all the LEDs in the matrix, the most light we can ever hope to get out of the whole thing is the same amount of light as just one LED on steady.
Fortunately, the situation isn't quite as bad as it seems. Our perception of brightness is logarithmic, not linear as one might assume. If you have a bright LED throwing out n photons per second, and another LED throwing out n/2 photons per second, the second LED will generally only look a little dimmer than the first, instead of half as bright as it really is. So it is possible to get away with dividing our time between several LEDs this way without too terrible a sacrafice in apparent brightness.
Once I had a pretty firm idea of the circuit I wanted to build, I got to work making a nice display for it. I got the idea of arranging the LEDs a small distance behind a sheet of frosted acrylic, so their light would diffuse through to the other side in a nice soft glow. A bit of doodling came up with this:
Acrylic is a real pain to cut without the right tools. In my opinion the very best tool for cutting acrylic is a laser cutter. While I was a student at CU, I got to play with a couple there, but since I graduated I unfortunately no longer have access to them. I also don't own any of the other 'right' tools, so I went to the local plastics supplier and fabrication shop, Colorado Plastics. They didn't have quite exactly what I wanted, but I settled on a nice looking 'bronze' tint, and ordered the pieces I wanted cut to the right sizes.
I had bent some little pieces of acrylic before with my little Weller handheld butane torch, but it just wasn't enough to do a 7" bend, so this time I used a full-sized propane plumber's torch instead. The trick is patience, just going back and forth along the same line, or even better if you can do both sides. It takes longer than you might think to get it soft enough to bend. Unfortunately, I wasn't as patient as I should have been. I held the torch too close and even when the center wasn't quite hot enough to bend, the surface started to bubble and deform. I did get it bent the way I wanted, but now there's a little ugliness in the form of bubbles and a wrinkle on the inside of the bend. It's not too terrible, though.
I wanted frosted acrylic, but Colorado Plastics didn't have any on hand in a decent color. Apparently the best way to frost acrylic is with a sandblaster, but fine-grit sandpaper will put a very fine frosting on it without noticable scratches or swirls.
The next problem was attaching the sheet all the LEDs would be mounted in, and the four half-inch standoff cubes to go between it and the main piece. As it turns out, when you glue together two pieces of frosted acrylic, the space between them becomes clear again, or at least it does when you use acrylic glue or superglue. Plus it tends to get bubbles in it and just look bad through the face of the main sheet. I did some experimentation, but I never did find an adhesive that worked very well, and I really didn't want to drill holes and use a fastener instead, because I liked the totally seamless look of the face. I ended up going with squares of strong double-sided tape. I know it sounds crude, but I first put it on just until I could figure out something better, but it really didn't look all that bad. If I were to do this project over again, I think it would look something more like this:
I think this design would be trickier to work with, but then there's no need for glue or tape or fasteners anywhere, keeping that perfectly smooth look. You may also notice there's a couple extra rows of holes for the LEDs on mine. The original plan was for a 7-pin version, with 7x6 = 42 LEDs. However, when I went out to buy them, I could only get 35 in any of the models I liked. So I scaled it down to 6 pins, for 6x5 = 30 LEDs. In theory, it wouldn't be difficult to add the extra rows some day.
Next, of course, I had to write software. As much as I like the MSP430, it's something of a shock to go from programming my fast multi-core PC with gigabytes of memory, to programming a 16MHz microcontroller with 1K of ROM and 128 bytes of RAM. It was a little tricky for me to figure out something interesting that I could get running on it. I considered either a binary clock, or a scrolling-sign type clock. I could have added something like this real-time clock module, and some buttons to set the time with, but it didn't really appeal to me to make an imitation of something I could already buy, and which wouldn't be all that nice to look at anyway. I played with some silly little animations for a while before coming up with the idea of implementing Conway's Game of Life. It seemed like a natural fit. Easy computationally, while providing appealing visual patterns for the LEDs.