HUB75/HUB75E - how they really work
I've been working on a project using HUB75 LED matrix panels and was surprised by the lack of information about how they work.
If you've come here to learn about how to hook up panels this is probably the wrong place, this is more about designing hardware and software to drive panels.
A word of warning: HUB75 is a 'flexible' spec, more of a variation on a theme, it's not publicly written down, and different panels have different ideas on what it should be. For example the E address line wanders
between pins, the locations of the R, G, and B pins can be swapped etc etc. You need to figure out
exactly how your particular panels are wired - and you should buy panels you want to work together
from the same supplier all at the same time.
Panel Interface
Panels are connected together with 16 wire cables, each panel has an input cable and an output cable
you can connect the output of one panel to the input of another to make wider panels, theoretically
limited by your refresh rate. Panels also have a 5V connector, each can draw an amp or two.
The input and output connectors are identical 16-pin IDC sockets the notch is on the middle of one side between pins 4 and 5.
The 'standard' pinout looks like this:

- R1/G1/B1 are RGB data for the top half of the display.
- R2/G2/B2 are for the bottom half.
- A/B/C/D/(E) address which line on the top half and bottom half are displayed.
- CLK clocks the RGB data into the display
- LATCH (active high) copies the RGB data to storage latches when high
- OE* (active low) enables the display of latched data
Pixel data is clocked into a panel on the rising edge of every clock - 2 pixels are clocked
on every clock, one into the top half of the panel, one into the bottom half.
The number of address lines depends on how many pixels high a panel is.
HUB75E simply refers to panels that are 64 pixels high and that need 5 address pins (ie need a
pin E). Sadly which pin is used for E varies between panels, usually it's either pin 9 or pin 13.
What's in a panel
Here's an educated guess at what's inside a typical HUB75 panel, the following circuit is repeated 6 times
1 each for the red, green and blue pixels for the top half and again for the RGB pixels on
the bottom half of the panel, the demux at
the top left may be in common with some or all of the 6 different pixel planes.

Each panel contains 6 shift registers, one for each of the 6 RGB inputs, each shift register
is the same length as the number of pixels wide the panel is. On each clock the data moves one pixel
from the left of the screen to the right so that after as many clocks as the width of the screen
the first pixel clocked is becomes the leftmost pixel and the last pixel clocked in is the rightmost.
Connected to the outputs of each flop is a latch which is loaded and is probably transparent when LATCH is asserted and held when it is low (may be different on different panels).
The output of the latch is a current sink (probably a constant current sink matched to the LED) - you can
think of it as an open collector/open drain transistor.
At the top left is a demux that converts ABCD(E) into 32 (64) supply lines, it's output is likely 32 (64)
PNP/PFET transistors to 5V - at any one time one of those 32 (64) lines is driven allowing one
horizontal line of pixels on the top half of the panel and one on the bottom half to be driven from
the 6 sets of latches.
When OE is high (unasserted) none of the horizontal line drivers are asserted.
Note: there are no latches on ABCD(E).
How to drive a panel
Here's the generic waveform you need to drive a panel:

Note: 'RGB' are the R1/R2/G1/G2/B1/B2 signals, 'ADDR' are the A/B/C/D/E signals. Don't infer from the diagram that ADDR is related to LATCH, it can change at any time.
Some important things to note (the main reason for this document):
- There is no frame buffer you must continually refresh the display stepping through the lines just like a CRT, fast enough that persistence of vision kicks in, not so slow that there's visible flicker.
- the only signals that care about the clock are the RGB signals - OE, LATCH and the ADDR pins can change asynchronously WRT the clock.
- The display is only on when OE is low.
- The current data in the RGB shift registers are copied to the output latches when LATCH is high.
- The when OE is low the current data in the output latches are displayed on the 2 lines (top and bottom) selected by the ADDR signals.
- ADDR are not latched (some panels may), the lines displayed are whatever lines the ADDR pins are when OE is low.
- Some panels will not latch unless OE is also high when LATCH is high.
- The brightness of the LEDS on a line depends on the amount of time OE is low and ADDR addresses a line.
- If one line is displayed longer than others it will be brighter, you must take care to refresh them at
an equal rate.
- If you change ADDR while OE is low (or latch a new row) you will see 'ghosting' caused by data for one line being displayed on another line.
- You need at exactly enough clocks for the width of the display, you should have no more clocks before latch is asserted (otherwise the image will be shifted to the left). You can have more clocks after LATCH, but any extra ones will be ignored (that data will fall off the end of the shift register).
So to break it all down you need to generate signals where: LATCH and ADDR change when OE is disabled (high) and the length of OE for every line is the same.
I have successfully got away with treating OE/LATCH/ADDR as synchronous with the clock and used the
following timing.

The big advantage of this is that you don't need a gated clock and OE is always the same length (3 clocks less than the
panel width. The potentially scary bit is that you're assuming that the latch inside the panel closes (LATCH signal falls) long enough after the shifted data is clocked that that data is correctly set up on the latch - it may be worth dropping in a buffer to delay LATCH by a few ns.
Dithering for more than 8 colours
All of the above does is tell you how to deliver 3 bits (RGB) to drive an LED - that gives you 8 colours.
But all those giant video screens out there are made of HUB75 panels .... the solution is to send each
line at a higher rate to PWM each component of each pixel (essentially dithering in time).
For example to display RGB555 (15-bits/pixel)
you need to re-display the screen really fast - 2**5 (ie 32) times using each color component value to choose how
many of those 32 times the LEDs will be turned on.
For 5 bits per colour component I use the following table:
0: 0x00000000
1: 0x00010001
2: 0x00010101
3: 0x01010101
4: 0x01010111
5: 0x01110111
6: 0x01111111
7: 0x11111111
8: 0x11111115
9: 0x11151115
10:0x11151515
11:0x15151515
12:0x15151555
13:0x15551555
14:0x15555555
15:0x55555555
16:0x55555557
17:0x55575557
18:0x55575757
19:0x57575757
20:0x57575777
21:0x57775777
22:0x57777777
23:0x77777777
24:0x7777777f
25:0x777f777f
26:0x777f7f7f
27:0x7f7f7f7f
28:0x7f7f7fff
29:0x7fff7fff
30:0x7fffffff
31:0xffffffff
Gamma Correction
PWM'd LEDS are non-linear, before you feed your dithering engine you'll need to run your data through
a gamma table.
Credits
Thanks to Wavedrom for their cool waveform editor
Disclaimer
Please note Moonbase Otago has no connection whatsoever with "Moonbase Holdings LLC" - they are racist scum