Peel Street Lantern
|Peel Street Lantern|
The lantern makes an appearance at Bright Sparks
|Purpose||To construct a 32×32 RGB LED array as our first group project.|
|Time spent||500+ man-hours|
A sparse array of LEDs to be installed in the large window of FORMAT in Peel Street. The lantern is named after the larger Rundle Street Lantern. Our more humble version is large enough to require significant group effort, and somewhat less costly.
- 1 Specifications
- 2 Technical
- 3 Construction
- 4 Alternative controller
- 5 Firmware
- 6 Wiring
- 7 Potential applications
- 8 Version: the second
- 9 Resources
- 10 Gallery
- 1024 RGB LEDs arranged in a 32x32 array
- 10 bit PWM provided by 32 TLC5940 ICs
In operation: Video
The lantern is constructed of 4x8 and 8x8 LED modules connected by enamelled copper wire. Each module is driven by one or two PWM PCBs each mounting a single TLC module. These modules are amalgamated into four 32x8 rows. Each row has a single driver board that provides power and signal to the PWM boards in addition to applying power to one of the eight rows of LEDs.
The lantern will be installed in a segmented window. The framing between the segments of the window will take the place of missing, virtual pixels. The apparent resolution will be 36x35:
....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 35 (32+3) ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... ....x........x........x........x.... 36 (32+4)
- Firmware (see below)
- Damien's code
- Git Repository: https://github.com/damien-hackadl/peel-lantern
- contains the firmware for the arduino pro minis (the slaves) and the firmware for the arduino mega (the master).
- Processing Sketch
- Stephen Pickles's code
- Git repository: https://github.com/thatpixguy/peel-lantern-driver
- Sends data out to the lantern
We're building the LED array in 8×8 sections. Pix made some templates to build these by drilling holes in some wood. Once we're done with these, we'll pull the LEDs out of the wood, leaving a mostly translucent grid of wires.
Various Hackerspace members have been slavishly soldering these up over the last few months, while risking their respiratory health in Format's basement. Each LED has its legs bent, and are connected to their neighbours with enameled wire. It takes at least a few hours and varying degrees of frustration to solder one of these panels.
Once done, we'll check that each panel is working, then hot-glue each solder joint for strength. Each 8×8 section will be joined to another section and then hung in Format's window, ready to awe all passers by in its radiance.
To prevent confusion over the identity of the two driver boards, they have been given names
The PWM board that controls the intensity of a set of four LEDs
The initial prototype of the Electron Source boards has been completed.
There will be an electron source board for each half panel, that is 4 columns of RGB lines, there are also spare data lines for future expansion. These boards are laid out so the serial data can be easily patched in either from the left or the right allowing for more flexibility. Each source board has headers to pass on power, clocks and data to each other.
These signals originate from the harvester boards and are carried along for convenience so that there can be a single point where the micro controller hooks up to the Peel St Lantern.
Wiring oddities: the first output pin has been skipped on the chip, in order to remove a jumper wire from the pcb, this saves 64 solder connections that would have otherwise have to be made by hand.
That switches LED rows as well as providing power and signal to the Source boards
There will be 4 harvester boards in total, that will be sinking electrons on each horizontal row, each board has 8 power mosfets.
Wiring oddities: for the Harvester to be single sided and easily etched the order of the rows are changed to (bit 1 being the equivalent to output 0 on the chip):
We've had far too much trouble getting the signals from the controller board past the first six TLC boards. Neither of the signal lines are very clean beyond that point. We think that using one controller board for every two 8×8 panels (4 TLC boards) might avoid this trouble, and using a master controller talking I²C. We can also test this topology without letting the smoke out of the lantern.
It doesn't obviate all of our problems: we'll have to be careful to avoid excessive capacitance on the I²C lines, and we might have to re-write the TLC library to bit-bang the output because the cheaper AVRs do I²C and SPI on the same pins.
The I²C capacitance should be easy to test: get a bunch of Arduinos, daisychain them along some wire and see where the signal dies. By the looks of it cat5 has quite a low capacitance so that might do the job. The I²C spec suggests putting the power and ground lines between the two data lines. (There's loads of information about this bus at http://www.i2c-bus.org/.)
A benefit of I²C is that there's acks built-in. Once the system has been told to display the next row of data, the first slave controller mightn't be ready to accept input from the master controller. It signals this by ignoring the I²C address request, and the master just has to keep trying.
Half of the lantern will look a bit like this:
(The diagram isn't quite right; the TLCs should be daisy chained together.)
The master controller will send one row of data to each controller in turn, tell the slave controllers to turn their LEDs off, advance the harvester(?) boards, and tell the slave controllers to latch the next row of data and turn the LEDs on again. The communication with the slaves except for the data is sent using I²C's broadcast function. We might as well only update one row at a time since we have to contact the boards each time anyway. The slave controllers will only need 48 bytes of memory (but I think the lowest controller we can use - the ATtiny25 (or possibly the ATtiny2313) has 128 bytes). Apparently our existing code is about 1500 bytes long, so flash space won't be a problem.
I don't think the slave chips will need any supporting components, so either a dead bug circuit or some strip/donut board will do.
I've done some experiments with i2c over 2 metres of cat5 cable. Again, the circuit worked fine when connected with short cables, but when connected with the longer cable things didn't work so well.
In the accompanying image (note the traces are in different time scales - apparently the DSO can "store" signals, but I can't work out how to access them), the light blue horizontal bars are roughly where the i2c spec says the signal has to reach. With the shorter cable, the signal moves into the limits of the spec, but with the longer one, the signal transitions too slowly to change state.
It's not all bad news though. It looks like the signal only missed the thresholds because of the low slew rate. One problem is that i2c never drives the line high - it just leaves the line float back to the high state, the results of which are easily seen on the attached image (Pull up resistors might be necessary!? There's probably a recommended I2C implementation you can look up to check this). If we chose a serial protocol instead - one which actually drives the line high AND low - we may not have this problem.
I'm not sure whether to choose SPI or asynchronous serial, the latter has the advantage that we don't need a clock line and might get away with one data line. If we use the internal 8MHz oscillator on the AVR, we can run asynchronous serial at about 500kbit/s (you can actually go faster, but you risk synchronization problems on the receiver). SPI should be able to go faster, of course slew rates may limit our speed.
And if we have voltage problems, we might be able to use a RS232 or RS485 transceiver on the sender, and hopefully get away with a few resistors on the receiver.
I guess my next experiment is to repeat with asynchronous serial and see if that works better over the longer cable, or whether voltage loss or capacitance is a problem.
Using a serial protocol
I tried again using the AVR's asynchronous serial support. The results look much better - the image shows the signal having been though 2m of cat5 cable.
...and by sending the signal through the same cat5 cable 7 times - the signal looks just as good. Any capacitive problems won't show in this test though, since the crosstalk will reinforce the good signal. We'll need to try the test with a single long cable.
Another flaw in this test is that the ground wire was only 10cm long. A longer cable could cause more problems.
Lantern update 21st May
Bottom row has been split - each half ran successfully with it's own arduino. Examination of the serial lines showed very low levels of noise. Looks like this may be a solution to the signal quality issues. Board seven on row four (second from end) may be defective. Pix is going to fab up a replacement. First TLC chip in the row was blown. May have been caused by an instability in the far end - need to add insertion resistor network.
We're also developing firmware for this project.
This version used an Arduino Mega as a master (for its two serial ports), sending signals using a 9-bit serial protocol to communicate with the slaves. The BGR data was sent from the host computer to the master. The master simply routed this data to each slave. It was up to the slave to translate the BGR data to a format that the format that the TLC needs, and the Arduino TLC library sent the data to those chips.
The problem with this arrangement is that it was only capable of 12 frames per second, because the slave took too long to translate the data. At 500kbps, each byte of data took 320 clock cycles to process, which wasn't enough (for my un1337 skills) to read the data, convert it from BGR to the 12-bit TLC data, store it in memory, and also send the data from memory to the TLCs.
The lantern has a low resolution, so we'll have to make up for it with the frame rate, and 12 fps is a bit woeful. 2Mbps would be nice, but that only gives us 80 clock cycles per byte.
To do this, I needed to offload the processing to the host computer. I changed the data to 8-bit (because you can't send 9-bit data from a computer (actually you can by playing with the parity bit, but that's a bit hacky)), and sent the data to the slave exactly as the TLC needs it. I also got rid of the framebuffer, because I found that accessing memory was too slow. This means that the slave will display a single row, unless it receives data otherwise (previously it would run independently of the master). This version has no acknowledgement signals from the slaves either - you just send data, and hope for the best.
With this arrangement the master was redundant; an FTDI USB-TTL converter will do. (Not all USB-TTL chips are suitable - neither the Silicon Labs cp2101 nor the Prolific PL2303 seem to support exactly 2Mbps. Converters based on these are very cheap on ebay.)
After trying the Demystifying the TLC5940 library, I decided to handle the TLC myself to get the best speed. I also got rid of interrupts by busy-waiting instead (my best efforts to reduce the interrupt overhead still needed 40 cycles to run).
This implementation doesn't use any RAM and only uses about 700 bytes of code, but the smallest chip that we could use is the ATtiny2313 because most smaller AVRs don't have UARTS.
We needed something on the host machine to translate the BGR data to the data the slaves want, and to keep updating the slaves when there's no data coming in. I wrote an application to do this.
When I first tried it, the display flickered a lot and one line displayed very bright. I realized that I was updating all rows on a single slave, so one row was being displayed as the other 7 slaves were being updated.
We still need to confirm that the 2Mbps will survive the long serial cable.
This slave wiring applies for version 1 and 2.
|Arduino Mega¹||19 (RX1)||9||11||12||51||52||37||34|
|AVR (ATmegax8)||RX0/RX1||D3 (OC2B)||B1 (OC1A)||B2 (OC1B)||B3 (MOSI)||B5 (SCK)||PC0||PC3|
|Use||Serial in||GSCLK||XLAT||BLANK||SIN||SCLK||Shift Data||Shift Clock|
Version 2 doesn't have a master, so this is for version 1 only.
|Arduino Mega||18 (TX1)||A8-A15||12|
|Use||Serial out||Select test pattern²||CTS (connect to X3 pin 1)|
- ¹: unverified
- ²: Ground these pins to activate the pattern
People send messages via SMS or Twitter, and the lantern displays them.
Play Pong, Tetris etc via your phone. Bluetooth is probably the best for this, but wifi would work but 3G would probably be a bit laggy. Find out how to get some software onto people's phones (have a look at OBEX push and the Ubuntu package "ussp-push", but I'm not sure how you identify which make of handset they have), and send an appropriate client that connects back to the lantern (with the serial port profile?) and sends data back from the accelerometer. You could probably get Wiimotes to work as well.
It's pretty hard to read any text on it, but you could display various changing information like the tons of carbon the lantern is responsible for, world population etc. Text would probably have to be large and scrolling, like in our first video.
Version: the second
So, we are embarking on a major overhaul of the electronics. Consolidating all of the various board from one 16*8 section into one board which we will get profesionally fabricated (and will then amateurishly populate).
Peter is taking the lead on the design of this new PCB and here are his comments so far, and a schematic and board layout in SVG format:
I have completed a layout of the board based on what I could find of the circuits. The LED connectors are using 20 pin headers but we can use smaller ones like 16 pins if we want. I have assumed that the entire system runs from 5V power, though I have split the logic and LED 5V supplies. There is a header at the end of the card we can use for scoping out signals if we need. I have used a RS485 chip to make the data bus to go between the cards. There are 2 options for connecting the rows either solder points between the Fets or from the 20 pin headers. The rows are now in order. 0 at the right through to 7 at the left.
We need to check through the Circuit and make sure it dose what we need.
Attached is the Board layout and related circuit diagram in SVG format.
For the 2013 Fringe Parade, Peter made two of the lantern panels in to sandwich boards.
Pix wrote a standalone Arduino firmware that displays a hypnotic "attract mode" animation.
You can upload this with a command like:
$ARDUINO_DIR/hardware/tools/avrdude -C$ARDUINO_DIR/hardware/tools/avrdude.conf -v -v -v -v -patmega328p -carduino -P/dev/ttyUSB3 -b57600 -D -Uflash:w:/tmp/attract.hex:i
- Demystifying the TLC5940 - Free book with BSD licenced source code