I have long wanted to make some kind of LED-based display for my wall, but when I looked into it a while back, RGB LEDs were too expensive for me. I was excited to find the RGB matrix offered by Adafruit for just about $40! With 512 RGB pixels, this is a good value! I was also pleased to discover that this thing is BRIGHT. It is almost uncomfortable to look at the fully lit display in indoor lighting. Perfect!
Sadly, there is no datasheet available for the matrix. Several people have done a nice job explaining the basics of the display. (Adafruit, HobbyPCB, RaysLogic, RHB) However, it still took me several reads of these posts and some diving into the example code before I really understood how it works. I will try to fill in the blanks here to provide a reasonable description for anyone wanting to experiment with this display on their own. I also drew a conceptual schematic of part of the matrix to help explain what’s going on. It is not an accurate depiction of the actual matrix circuitry, but it should help to explain how it works.
The electornics of the matrix are configured as two 8-row by 32-column matrices of pixels, one on top of the other. I will describe how a single 8×32 matrix works, then expand a bit at the end to incorporate the full 16×32 display.
Each LED in the matrix has separate red, green, and blue color elements. Each element is controlled separately, but they are all in the same “pixel” so that they blend well to form a color. The matrix does not handle PWM control of the LEDs automatically. Each RGB element can only be turned on or off. If the software does not perform PWM itself, the display can only show 8 colors (all combinations of red/green/blue each on or off). The matrix is designed for software PWM, and in practice a huge range of colors are available.
Each color element has two devices determining whether it is on or off: a switch allowing current to flow into the anode (positive) side, and a current sink allowing a controlled current to flow out of the cathode (negative) side.
The switches are controlled by the row selector lines A, B, and C. These are run into a decoder. The decoder uses the binary number made by the three row bits to turn on one (and only one) of the eight output lines. These outputs are then used to control switches that enable or disable the power to an entire row of pixels. For any state of the inputs A, B, and C, there is always one and only one row of pixels enabled at any time. All color elements in the same row are enabled by the same switch.
The real workhorse of the LED matrix is the CYT62726 constant current LED driver. This is the device on the “bottom” of the LED that allows current to flow out of it. There are two main parts to this device, a shift register and a constant current sink. Internally the device stores 16 bits of data in a register. Each time the clock pin pulses, the data in the register is shifted down one spot. The bit in spot 0 moves to spot 1, spot 1 to spot 2, and so on. The data in spot 15 shows up on the “SDO” (serial data out) line. (More on this in a minute). This is pretty simple. To fill the register up with ones, drive the SDI (serial data in) line high and pulse the clock 16 times. To fill with zeros, drive the SDI low and pulse 16 times. To fill with a pattern of data, set the SDI line to the desired bit before each clock.
The second part of the CYT62726 is a constant current sink. This just means that the device only allows a certain amount of current to flow into it. (It’s kind of confusing that they call the pins “outputs” when the current goes into them, but it’s an output in the sense that you control the “input” lines (SDI/CLK/LAT/EN) and the behavior of the “outputs” changes). Each output can either draw the set amount of current or no current at all, depending on whether it is on or off. Each time the “Latch” signal is pulsed, the data that is currently in the shift register is used to update the state of each output. If bit 0 is 1, then output 0 will be on (drawing current). If it is 0, then output 0 will be off (drawing no current).
If more than 16 outputs are needed, the SDO line can be connected to the SDI line of another CYT62726 chip. Since this line reflects the previous state of shift register bit 15, bit 15 on the first chip is shifted into bit 0 of the second chip. This makes two 16-bit chips behave as though they are one 32-bit register.
Since there are 32 pixels in each row, two CYT62726 chips are hooked together to provide 32 “outputs” for the current to flow into. And since there are 3 color elements in each pixel, 3 pairs of chips are used to control a row, one pair per color. Instead of using six chips for every row in the display (which would reqire 96 chips for a 16-row display!), the same six chips are shared by all eight rows. The cathode (output) of all red color elements in each column are all connected to the same output line on the red CYT chip, and the same for the blue and green elements.
Okay, so we have the rows of LEDs powered by selecting the correct row on the row lines (A,B,C), and we have the constant current sinks allowing current to flow out of each pixel in the row. So how do we tell this thing what to do?
To program a row, shift in the 32 pixels of RGB values to turn the color elements on or off. It is important to remember that the shift mechanism works independently of the latched current sinks, so you can shift in the next display values while a row of LEDs is still lit. Once the data is shifted in, disable the enable line to turn off all the LEDs. With the LEDs briefly off, pulse the latch line to update the state of the current sinks with the register values. Select the row value on the ABC lines to send power to the correct row, then enable the current sinks by re-enabling the enable line. The new row of LEDs should light!
RaysLogic notes that there is some circuitry that is designed to shut down the whole display if the row lines are not changing at some certain rate. This is to protect the LEDs from burning out. LEDs have a maximum current with which they can be continuously driven without overheating and breaking. It is okay to drive them with more current, but only for very short periods of time so that they can cool off in between. Since the display is designed to cycle through the 8 rows very quickly, the constant current sunk by the CYT chips is high. After being driven for 1/8th of a frame period, each row has 7/8 of a frame period to cool off while the other rows are driven. However, if you don’t cycle the rows and instead continuously drive a single row, the LEDs will quickly burn out. This is a nice protection feature, but it does make it hard to experiment with the matrix, as you can’t send a command to just one row or pixel and leave it on for a test.
Earlier I promised to explain how the 8×32 arrangement is expanded into 16×32. Basically the full matrix is just two 8×32 matrices, one on top of the other. All of the signals to them are the same, except for the RGB lines.
When a row is selected, it provides power to two rows, one row in the top eight and the corresponding row in the bottom eight. When you turn on row 0, row 8 is also powered. Rows 1 and 9, 2 and 10 are pairs, and so on. If these rows also shared the same current sink chips, both rows would display the same pixels. To control the pixels separately, there is a complete second set of current sinks for the lower matrix. Instead of just 6 constant current chips, there are 12. There are two sets of RGB control pins for the matrix: R1,G1,B1 and R2,G2,B2. With each clock pulse, the RGB values for both the upper row and the lower row are shifted into their respective registers. When the row is selected and the enable line is enabled, both rows light up with their correct data.
In a later post, I plan to explain how the Adafruit code works. It is the basis for the code I wrote to drive the matrix and uses a lot of good concepts for getting the maximum performance out of this display with a simple microcontroller.