Monochrome 32*16 P10 HUB12 LED matrix control with ESP32

(Repost of GitHub Issue #133)


From what I have read this library should be able to directly (no adapter/extra hardware) control a monochrome 32*16 P10 HUB12 LED matrix with an ESP32 microcontroller.

I have uploaded the following code to the ESP32-Devkit board:


#include <MatrixHardware_ESP32_V0.h>
#include <SmartMatrix.h>

#define COLOR_DEPTH 24
const uint16_t kMatrixWidth = 32;
const uint16_t kMatrixHeight = 32;
const uint8_t kRefreshDepth = 36;
const uint8_t kDmaBufferRows = 4;
const uint8_t kPanelType = SMARTMATRIX_HUB12_16ROW_32COL_MOD4SCAN;
const uint32_t kMatrixOptions = (SMARTMATRIX_OPTIONS_HUB12_MODE);

SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions);

#if 1
  const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_GFX_OPTIONS_NONE);
  SMARTMATRIX_ALLOCATE_BACKGROUND_GFX_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions);
  const uint8_t kGFXMonoLayerOptions = (SM_GFX_MONO_OPTIONS_NONE);
  SMARTMATRIX_ALLOCATE_GFX_MONO_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kGFXMonoLayerOptions);

#define BLACK   0x0000
#define RED     0xF800

void setup() {


void loop() {
//  for(uint8_t rotation=0; rotation<4; rotation++) {
//    backgroundLayer.setRotation(rotation);
//    testText();
//    backgroundLayer.swapBuffers();
//    delay(1000);
//  }

In the MatrixHardware_ESP32_V0.h file I have selected the following option:

I made the following connections:

A - GPIO 5
B - GPIO 18
C - GPIO 19
R1 - GPIO 2
OE - GPIO 25

All GND’s are grounded to the same ground as the power supply and devkit. E & D are not connected, as per the instructions at

On the back of the LED matrix panel, near the connector it is clearly written „HUB12” and the model of the matrix is „RK-P10(1R)-320*160-V2.0 V10”

My sketch is based on the Adafruit GFX example of the library and I am running on the 4.0.0 release from 5 days ago. I would also like to note that I encountered some compilation issues related to error: 'textsize_y' was not declared in this scope smartmatrix , in a graphic font related if-statement which I commented out (I do not have graphic fonts included).

Unfortunately the result shown on the matrix is this:

(the greenish dots in the lower side of the image are camera sensor reflections, only the white dots are actually on the screen)

Do you have any ideas of what fixes to try? Should I ask the vendor for the row scan pattern (1/2, 1/4 or 1/8) or does the library have different scan pattern options? (like the PxMatrix library has ZIGZAG, ZAGGIZ, WZAGZIG2, etc.)

Thank you very much in advance for your time looking into this and for developing such a good and useful library in the first place.

You say “no extra hardware” but you selected the hardware config that needs an external latch. I think if you change GPIOPINOUT back to ESP32_FORUM_PINOUT it should work

If the documentation wasn’t clear, please let me know where so I can update it. The Wiki is also editable if you want to add any clarifications that would have helped someone in your situation

Also, I’m sorry to say you’re one of the (hopefully few) users that upgraded to 4.0 in the last few days, before I changed the GFX layer API. Next time you update SmartMatrix Library, you’ll need to edit your sketch:


I’m not seeing this when I just compiled. Do you think you might have an older Adafruit_GFX Library? I have 1.10.0, and just updated to 1.10.3 and don’t see the error. Can you please paste the full compiler output that shows the error?

I have upgraded the library to 4.0.3, change the sketch and it worked (compiled) without issues.

Yep that was the issue regarding this. I was running Adafruit_GFX 1.2.x, running the latest release it is alright.

The ESP32_FORUM_PINOUT had a mention in it´s source code comments about “LED Drivers’ Clock” and “LED Drivers’ Latch” which implied the use of external hardware. I assumed the ESP32_FORUM_PINOUT_WITH_LATCH meant it will use the ESP32 as latch. After the above-mentioned changes to the dependencies and sketch, I also switched to ESP32_FORUM_PINOUT and there´s a much needed improvement, as you can see below:

There seem to be some “noise” LEDs lit up besides what I wanted to write (only Test). The “interference” seems to be somehow deliberately output by the board, because it does not otherwise behave like electrical interference. I have tried swapping out / separating (MCU & panel) power supplies, moving the wires around, the noise LEDs do not flicker or move or go away. (again, ignore the green/red reflection from the camera sensor, only the solid white dots are actually on)

I have also tried lowering the ESP32_I2S_CLOCK_SPEED, to no avail (the same result displays).

Thanks again!

I’m not seeing those issues with my P12 panel, and ESP32_FORUM_PINOUT with long wires and no buffers:

It could be an issue with that panel, or could be improved by adding buffers

Same result with another panel (very different model using THT LEDs)

What exactly do you mean by buffers? Are those to be implemented in software or hardware? I couldn’t find mentions of such buffer examples on the GitHub homepage or Wiki of the project.

Also, what are you doing with all the grounds of the HUB12 connector? Did you connect all of them to the board’s ground or just one? What about the unused D and E ports, are they connected to ground or just floating?

Maybe it’s a wiring problem on my side after all. Thanks!

I didn’t connect up C as you don’t need that line for a /4 panel. C,D,E are left floating. I connected one GND pin.

From the wiki:

Some panels won’t work with the 3.3V levels output by the ESP32, and you’ll need 5V level shifting buffers like the SmartLED Shield designs use. Additionally, the shields have some other features that make them preferable to using just an ESP32 (and optionally level shifting buffers):

Take a look at the THT board design and BOM in the /extras/hardware/ESP32 folder for parts and a circuit.

You were righ regarding the C pin. It’s the same without it.

Strange. Now we have the same wiring and I’m still encountering the glitchy LEDs. I will try getting my hands on a level shift to try in the next days, but I doubt the 3.3v is a problem or that the matrix itself is defective. (isn’t the Raspberry Pi GPIO 3.3v too? This exact matrix runs without artifacts connected to a pi and controlled with hzeller’s rpi-rgb-led-matrix library.

Anyway, I’ll keep digging and update here if I somehow solve it.

Just to eliminate some potential hiccup, what sketch are you writing the Hello world with? Is it using Adafruit GFX or not? Could you share the code so that we run the exact same thing on the seemingly same hardware/wiring please?

It’s Adafruit_GFX with two lines changed:

const uint8_t kPanelType = SMARTMATRIX_HUB12_16ROW_32COL_MOD4SCAN;   // Choose the configuration that matches your panels.  See more details in MatrixCommonHub75.h and the docs:
const uint32_t kMatrixOptions = (SMARTMATRIX_OPTIONS_HUB12_MODE);        // see docs for options:

I agree with you if it’s working with a 3.3V RPi, then there’s likely no difference with level shifters.

Have you tried swapping wires? Sometimes those cheap jumper wires are faulty. You can also try swapping the pin numbers in case one of the pins on the ESP32 is bad.

What are the settings you’re using with the rpi-rgb-led-matrix library?

Sorry for the late reply but I had to consult with my colleagues that ran this panel under rpi-rgb-led-matrix. It seems like the basic settings are pretty standard (16 rows, 32 cols and led-inverse enabled I think), but the most involved part was using a custom pixel mapper that looks like this:

void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
	if (y / 4 == 0) {
		*matrix_y = y % 4;
		if (x / 8 == 0) {
			*matrix_x = x + 24;
		} else if (x / 8 == 1) {
			*matrix_x = x + 48;
		} else if (x / 8 == 2) {
			*matrix_x = x + 72;
		} else if (x / 8 == 3) {
			*matrix_x = x + 96;
	} else if (y / 4 == 1) {
		*matrix_y = y % 4;
		if (x / 8 == 0) {
			*matrix_x = x + 16;
		} else if (x / 8 == 1) {
			*matrix_x = x + 40;
		} else if (x / 8 == 2) {
			*matrix_x = x + 64;
		} else if (x / 8 == 3) {
			*matrix_x = x + 88;

	} else if (y / 4 == 2) {
		*matrix_y = y % 4;
		if (x / 8 == 0) {
			*matrix_x = x + 8;
		} else if (x / 8 == 1) {
			*matrix_x = x + 32;
		} else if (x / 8 == 2) {
			*matrix_x = x + 56;
		} else if (x / 8 == 3) {
			*matrix_x = x + 80;

	} else if (y / 4 == 3) {
		*matrix_y = y % 4;
		if (x / 8 == 0) {
			*matrix_x = x;
		} else if (x / 8 == 1) {
			*matrix_x = x + 24;
		} else if (x / 8 == 2) {
			*matrix_x = x + 48;
		} else if (x / 8 == 3) {
			*matrix_x = x + 72;

It is a custom implementation taken from this GitHub issue of the rpi-rgb-led-matrix project, as usually, like the name implies, this library doesn’t drive single-color panels -

But it works perfectly. Do you know of any way to port this kind of mapper into pixelmatix?

P.S.: regarding wiring and boards, multiple combinations were tried. Plus, the same ESP32 drives a HUB75 RGB without issues.

Take a look at the MultiRowRefreshMapping example sketch, and try it on your panel.

This is the mapping for the HUB12 panels I have:

At a glance the mapping looks the same as the one you posted.

SMARTMATRIX_OPTIONS_HUB12_MODE already inverts the data line, which I’m guessing is the same as “led-inverse enabled”

Have a nice day. I’m also trying to get the HUB12 display up and running. I have it connected to ESP32 directly in the mod forum. And the result looks like this. The first pixel is in a different location. Can you help me. Rene

I haven’t seen that behavior before. Can you please post a longer video where MultiRowRefreshMapping runs through all the pixels and starts repeating so I can see the full mapping?

I took a full video of mine doing the MultiRowRefreshMapping (it actually needed some modifications, to use the mono layer and display „only full red”, which for my panel is white, in order for the dots to show up). I think it’s the similar to the behavior illustrated above.

@BodoMinea and @renda71 can you share where you purchased your panels? I may want to get samples to test. Also can you show photos of the back of your panels just in case that’s useful?

Hi, I have 3 variants of displays at home. Versions 1 and 2 of the outer version 3 are the inner inverted. They all work well with the DMD3 library. The mapping you have right just is the wrong timing. I will try to put pullup or down resistors on the outputs for edge banding. The DMD3 library is slow and ESP32 with a web server is not enough to refresh the display. That’s why I want to use the smartmatrix library. You have an inverted implementation in your library for use in version 3. I bought the displays on aliexpress and ebay over the course of two years.

Otherwise, I’m glad you’re developing this library. I will support you.

Unfortunately, I only had two links to insert.

version 2

Hi René, thanks for your donation which motivated me to dig out my HUB75 panels and bare ESP32 to connect up the panels and see what’s going on. I was able to reproduce some of the issues here, and found a fix:


It looks like sometimes the clock needs to be inverted. I’m not sure if that’s the case on all hardware setups, but it helped with the panels I have here and a bare ESP32.

For your version 3, it looks like you don’t need the inversion on the data line. You can do a quick fix for now, just comment out the code that inverts R1. There’s two places in the code with inversion:

Hope that helps, LMK if you’re still seeing issues.

I have also tried using this:

And it changed this:

to this:

And also with that additional config it shows some kind of flicker, but not much in terms of different LEDs being lit up.

I assume that the other piece of advice with the editing of the files is just for the inverted panel and wouldn’t help in my case. So what you see is the result of just adding that to the config.