I've been putting a fair bit of thought into how to design a RGB LED sign that fixes some of the drawbacks that I have seen in the current LEDTriks design, and makes a few different trade-offs in the process.
Before I get into my ideas, I want to first thank RJ for coming up with the current LEDtriks design, as he has proved that it is not just possible, but also feasible, for amateurs to put together a professional-looking "moving-message" LED sign from scratch, and synchronise it with their existing computer-controlled christmas light and music system. It is a brilliant minimalist design, and construction from his plans is well within the capabilities of motivated amateurs. That is a HUGE achievement, and I'm suitably impressed by it.
However, because LEDtriks is so minimalist, it puts a quite heavy CPU load on the PC running the show, requiring huge numbers of updates just to keep the display refreshed and updated. Constant-current drivers do a great job of evening out the brightness of the individual LEDs, but preclude dimming.
To go from monochromatic LEDs to an RGB display would require, at a minimum, three times the number of updates as a standard LEDtriks, assuming we only wanted to have a maximum of 8 colors (including "black" when the LEDs are all turned off) to work with. Still, with a fast PC, it would be possible, simply by essentially wiring three LEDtriks circuits together, each feeding one of the three colors within a panel wired up from RGB LEDs.
However, I want to have more than just "on-off" control of each color; I want to be able to set multiple brightness levels, allowing the use of a larger color palette. So-called "full-color" displays take 24 bits per pixel, specifying 8 bits of brightness information for each of the three colors that make up each pixel. 24-bit color gives you 16.7 million colors to play with, at the cost of 24 times as much data to handle.
There are all sorts of compromises that can be made, here, while retaining some color choice. Going to 8 bits per pixel gives you 256 colors, which might be sufficient to produce a "decent" color display, with 1/3 the data bandwidth requirement of "full-color". Going to some sort of "smart" display controller would also reduce the CPU load, as updates could be sent to the controller, which would then continue to display whatever it was told without further commands from the PC.
My idea is to design a small pixel matrix controller that has independent control over, for example, an 8 x 8 matrix of RGB LEDs. It will use PWM techniques to set any one of 256 brightness levels for each color of each pixel under its control.
For discussion, imagine an 8x8 array of common-anode RGB LEDs, with 24 "column" inputs and 8 "row" inputs. The columns are labeled R1-R8, G1-G8, and B1-B8. The rows are labeled A1-A8 (for "anode"). When an "A" input to the matrix is energized, it turns on power (through a transistor and appropriate current-limiting resistor set to provide full brightness) to the chosen row. The column inputs are connected via an open-collector driver to ground to "energize" them. All 24 columns can be driven simultaneously in whatever combination is desired. At most one row out of 8 will ever be driven at once.
To drive the display, you need two counters: a 3-bit Row Counter (RC), and an 8-bit Brightness Counter (BC).
The main program loop does the following:
Increment RC
Turn on the Row corresponding to RC, turn off all other rows.
If RC = 0, increment BC
For each pixel column in that row, compare the programmed brightness level to BC:
If BC > programmed brightness, turn off that column
If BC <= programmed brightness, turn on that column
Go back to the start
A separate, interrupt-driven routine handles I/O requirements. Packets of data arrive via serial input. Each packet has a row and column address, as well as pixel data in some format (there are a few options here, but I want to keep the conceptual discussion general). Each packet is processed as follows:
If the row address is not zero, discard the packet and exit without doing anything.
If the column address is not zero, decrement the column address by one, and retransmit the packet before exiting.
If the column address is zero, process the pixel data, storing the brightness levels in memory.
Exit.
The serial output of one 8x8 matrix is connected to the serial input of the next 8x8 matrix in the same row.
A secondary interface circuit is needed to handle multiple rows of 8x8 matrices. It has a single serial input, and multiple serial outputs (only one of which is ever active at a given time). It processes data packets received as follows:
Assume that there are "N+1" outputs, labeled Out0 to OutN .
For packets with row addresses 0 through N, set the row address to zero, and retransmit the packet on the appropriate output.
For packets with a row address > N, subtract N from the row address, and retransmit the packet on OutN.
This way, you can extend the system to more rows by simply adding more interface circuits, OutN to In, as needed.
The interface circuit is only needed if you want more than one row of 8x8 matrices. Each row can be made as long as desired by daisy-chaining 8x8 matrices horizontally, Output to Input. All matrix circuits and code are identical and interchangeable.
The PC only has to send updates, and doesn't concern itself with maintaining the display during times when it doesn't change.
What's everyone think?
- Rick