All code related to this project is viewable here.
There were pictures here at one point but the webspace I was storing them on went poof and I haven’t had the time to dig them up if they’re still around.
This rather extensive project was started by fellow Casa Zimbabwe residents Karandeep Nagra and David Murphy in April-ish of 2012, I hopped on near the end of that year and we finally “finished” it um… real soon now. The process of just getting this damn thing to work has been one of the biggest learning experiences of my career thus far. I have trouble counting the number of things this project taught me that you just don’t learn in school. So I guess this will be a guide on how not to build something like this, with the hope that anyone reading will learn from our mistakes!
In the beginning
So the story goes: someone had come into possession of a large quantity of very-high-power RGB LEDs as well as various other components on the cheap and wanted to build something shiny with them. The original idea: make a jumbo version of Seeedstudio’s Rainbowduino board, run neophob’s firmware on it and send it data using PixelController. Step one was completed before I joined the project. Because we wanted the individual LEDs to be spaced far apart, it was prohibitively expensive to make a PCB to mount them on, so the solution that was decided on was to stick the LEDs through poster board and hand-wire them point to point, then bring the row and column lines to pin headers on the PCB.
The decision to hand-wire all of the LEDs was made based on the observation that money was scarce but bored college students were plentiful, and soldering is a fairly easy task assuming that you’ve been properly instructed. The biggest mistake made with respect to this decision was that we waited until after all 18 panels were assembled to test any of them.Unfortunately, right before the soldering was finished, David’s time as an exchange student was up and he left us for good. He left us with instructions: The chips already had the firmware installed on them, just hook them all up and everything would be gravy. So we did, and… …it didn’t work. Of course. The first thing I did was to write up a very simple test firmware and program it into the board to verify that the microcontrollers were functioning properly (they were). With a few tweaks I now had it generating test patterns to find shorts and disconnects in the wiring (of which there were many). In all, over half of the eighteen panels had at least one short or bad solder joint and most of those had multiple ones. The process of diagnosing and repairing all of that took almost as long as the assembly did in the first place.
Getting the darn thing to work
The next stumbling block was that I had just overwritten the firmware that David had flashed onto the chips, and none of us knew which firmware he had used and how he got it on there. As it turns out, the neoled firmware was very old and didn’t work with newer versions of the Arduino software, so–not having a scope nor much knowledge about how I2C worked–I blindly bumbled around until I got it kind of working:
One thing you might notice from this video: The red light comes straight out of the LEDs but the green and blue light come out at opposing angles, and so since the diffuser is spaced about 2 inches away, the colors don’t mix very well. Also, the LEDs are not all in the same orientation so certain patterns look quite ugly. You might also notice that some of the light reflects off of adjacent LEDs. We’ve decided to live with these flaws for now as the real solution involves a much more expensive diffuser design–Ideally we’d want each pixel to have its own square-shaped diffuser with reflective or opaque separation between them, but there are over a thousand pixels on this board and making or buying a thousand of anything ain’t cheap.
Harder, Better, Faster, Stronger
Neophob’s original setup involved a few of these boards (less than five) being fed pixel data from a regular Arduino board, which in turn gets that pixel data from a PC via USB Serial. This works fine for up to four boards, but we had eighteen. We decided that the easiest speedup would come from removing USB, serial and the Arduino from the equation, and so what we eventually settled on was having a Raspberry Pi mastering the I2C bus directly. The bonus here was that the Pi has two available I2C ports and so we could (theoretically) split the whole thing into two buses and double our bandwidth.
(Now before any savvy readers judge me as completely clueless, it was fairly early on that I realized that I2C is the worst choice for carrying the pixel data, but I decided that squeezing the last drop of performance out of I2C would be a fun challenge and redoing the circuit boards to use serial or SPI would be time consuming and expensive.)
I had to take a hiatus from the project due to CS 150 kicking my butt (I spent almost every waking hour working on that project for a few months, but it was totally worth it), but once Fall semester ended I was ready to tackle the project head-on. It was around this time that, tired of not being able to see what was actually happening on the I2C bus, I finally broke down and bought a cheap digital scope. I immediately regretted not doing this right at the beginning as it made debugging quite a bit easier.
It was pretty early on that I had realized the shortcomings of Arduino’s Wire (it reads bytes into a buffer, then copies that buffer into another buffer, then when you call Wire.read() it copies that buffer into your buffer), so when I came back for round two with 150 under my belt I decided it would be a fun exercise to redo the TWI code from scratch. At that point I abandoned the Arduino software entirely since it was just getting in my way.
Finally, we got it to a presentable state and here’s the result:
Also, for kicks, I made a web interface for it:
That’s it for now. Part 2 will go over the bugs I had to track down, the (in retrospect) bad decisions that were made, and the lessons and tricks that were learned!