First, the pics!
Description:
- Top left, top right, bottom right are TLC5940s
- Bottom left is an Ardweeny http://solarbotics.com/products/kardw/
- Bottom row in the middle (large capacitor): 5V -> 10V charge pump
- The other 4 component clusters in the bottom row are driving assemblies for n-channel mosfets (I know p-ch might have been better but I had these on hand)
I had to greatly reduce the brightness and adjust the shutter speed to 1/80 to get this shot. Multiplexing and the brightness of the leds wreak havoc with my cheap camera.
This project was much larger than I originally anticipated (400+ solder points) and filled with challenges. The biggest was getting multiplexing going. As acleone, author of the TlcMux library notes in his examples:
Currently I'm trying to fix timing issues by putting some D-type positive edge triggered latches between PORTC and the 3:8 line decoder, clocked on the rising edge of XLAT, but this doesn't seem to help. I'm bringing the circuit in to the logic analyzer this weekend to see exactly when the ISR runs and how long it takes to shift in the GS data.
I personally experienced ghosting (dim illumination of desired pattern in adjacent rows), flickering, and some patterns that wouldn't illuminate correctly.
Also found these unresolved forum posts: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1285107015/8 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241054901 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265127525 ...
After lots of debugging and a nice pile of dead TLC5940s I think the issue is with undesired XLAT / BLANK latching even when disable_XLAT_pulses() is called.
The Workaround I have described these changes to acleone in a separate email. There is probably a more elegant solution but this works. Reference this diagram: http://students.washington.edu/acleone/codes/tlc5940arduino/img/breadboard-arduino-tlc5940.png - Attach XLAT and BLANK to Analog 0 (pin 14 in code) and 1 (pin 15 in code) instead of the pins listed to avoid any timer / PWM interaction. Set pinMode(14, OUTPUT); pinMode(15, OUTPUT); in setup.
- Change the ISR:
ISR(TIMER1_OVF_vect)
{
if (!isShifting) {
isShifting = 1;
TlcMux_shiftRow(shiftRow);
// This activates pins to facilitate multiplexed power
PORTC = shiftPower[shiftRow];
// -- THE IMPORTANT BIT -- //
digitalWrite(BLANK, HIGH);
// 3 x 62.5ns = 187.5ns (Blank needs to exceed 300ns to avoid shortening the GS cycle)
__asm__("nop\n\t""nop\n\t""nop\n\t");
digitalWrite(XLAT, HIGH);
// XLAT for 62.5 ns
__asm__("nop\n\t");
digitalWrite(XLAT, LOW);
// Another 187.5 ns safely exceeding the minimum 300ns BLANK requirement
__asm__("nop\n\t""nop\n\t""nop\n\t");
digitalWrite(BLANK, LOW);
// -- End THE IMPORTANT BIT -- //
if (++shiftRow == NUM_ROWS){
shiftRow = 0;
}
isShifting = 0;
}
}
What does this do? Well, we've taken full control of BLANK and XLAT so data is latched immediately and only after the TLCs are fully loaded. This also matches the datasheet timings as closely as was feasible. I don't think the last set of noops are entirely necessary (the instructions before likely took all the required time) but they're there for clarity against the datasheet.
Hope that helps someone.
One more thing: Why the MOSFETs? I built small scale prototypes using a variety of transistors (2N2222, TIP142, S9013, 2SA2064, 2907A, etc.) and found that the MOSFET (an irlu8721) delivered 30% - 40% more current at full 5V. The downside is the drive circuitry (homebrew charge pump and transistors to ground the gate) but they're cheap and it was an interesting part of the project.
The MOSFETs deliver so much power (only 8 milliohms of resistance) that its trivial to cook the TLC5940s so you can be guaranteed maximum brightness within the thermal limits of the TLC5940s.
It took quite a while to design and assemble but the end result is everything I was hoping for. If there's a lot of interest, I'll do up a full design / construction article.
I plan to move on to an 8x8x8 by extending the same basic design.
Thanks to the Arduino team for a great platform!