SmartMatrix Library ESP32 Port

Hey Louis, quick question. How did you get the sketch to work with the ESP8266Wifi.h file? I thought that was only available on the ESP8266.

I don’t know anything about that file, is it a part of Jason’s ESP32 FastLED Web Server sketch?

Yes, it’s one of the included libraries in your fork of Jason’s Webserver. It’s on line 36 in the esp32-fastled-webserver.ino file. Am I looking in the wrong place?

Check out the README that Jason wrote for the sketch. It says he uses GitHub - bbx10/WebServer_tng: ESP8266/ESP32 WebServer which has support for both ESP8266 and ESP32

Hi Louis! Thanks for the port to ESP32! Really helpful! Will you be releasing the ESP32 interface board or possibly the gerber files so we can have it fabed?

Hi Rich, the board design in Eagle and gerber files are available in the repo already:

Check out the “Hardware” section in the README as well. I’m not working on bringing the ESP32 shield to production at this point, so getting them made yourself is the only option.

Hi Louis,

Thanks for the quick response! I just see the brd file and schematics in the repo for the ESP32 board. Will you be releasing the gerbers or should I just generate them from the brd file? Been some time since I ordered PCBs so please forgive me if gerbers are easy to generate…

Oops, I just glanced at the folder before and assumed there were gerbers there. I suggest ordering from, and you can use the Eagle .brd file directly, plus they make quality boards. Google and a free copy of Eagle can help you make gerber files, but let me know if you need a hand.


I tried using a P2 64x128 matrix with the ESP32 and cannot get it working with 128x64 pixel because the DMA malloc fails. However it works fine with 64x64 pixel. Does anyone know how to solve this?

Actually I can get the 128x64 matrix working by changing the line 192 of SmartMatrixMultiplexedRefreshEsp32_Impl.h
matrixUpdateFrames[1] = (frameStruct *)heap_caps_malloc(sizeof(frameStruct), MALLOC_CAP_DMA);
matrixUpdateFrames[1] = matrixUpdateFrames[0];

Everything looks fine, does anyone know why we need the matrixUpdateFrames[1] at all?

You’re likely out of RAM. You can try to reduce RAM by using 24 instead of 36 bit color:

kRefreshDepth = 24;

If you get rid of the second frame buffer, you’ll be drawing and refreshing from the same buffer, and artifacts may show up on the screen while you are in the middle of drawing a new frame, or other weird stuff may happen. If it works for you and you don’t notice any issues, then may as well keep using it that way.

Also I just pushed a bugfix that had been sitting in my local git repo, that had to do with a malloc calculation that could fail when there’s small amounts of RAM free. Try with the latest code, and that may also fix the issue for you.

Ok, thank you @Louis

I have edited the code to show the single mallocs and it looks like there is no block large enough for the second matrixUpdateFrames malloc.

Starting SmartMatrix DMA Mallocs
Step 0: Heap Memory Available: 260076 bytes total, 113792 bytes largest free block: 
Step 0: 8-bit Accessible Memory Available: 167400 bytes total, 113792 bytes largest free block: 
Step 0: 32-bit Memory Available: 260076 bytes total, 113792 bytes largest free block: 
Try to allocate: 65536 bytes... Done.

Step 1: Heap Memory Available: 194524 bytes total, 92676 bytes largest free block: 
Step 1: 8-bit Accessible Memory Available: 101848 bytes total, 48240 bytes largest free block: 
Step 1: 32-bit Memory Available: 194524 bytes total, 92676 bytes largest free block: 
Try to allocate: 65536 bytes... 
assertion "matrixUpdateFrames[1] != NULL" failed: file "lib\SmartMatrix-teensylc\src/SmartMatrixMultiplexedRefreshEsp32_Impl.h"

It already uses kRefreshDepth = 24. 65536 bytes would be 8 bytes per pixel. Is that correct?

I will try it with the new code soon.

65536 bytes would be 8 bytes per pixel. Is that correct?

Yes, that’s correct. I believe on the ESP32 the way I implemented the code you need one byte of RAM per pixel times the number of bits of colordepth (kRefreshDepth/3).

@peterpoetzi @Louis just curious: does ESP32 work with RGBpanels without level shifters, or level shifters are required? Never mind, I found the answer in the README I hadn’t seen (well I had been reading the wrong one that is). The answer is “it depends” (on the panel you’re talking to).

Now, I’m reading the correct README: GitHub - pixelmatix/SmartMatrix at teensylc (BTW, it’s a bit confusing to check out a teensylc branch to get ESP32 support, worth renaming?).
For pinout, I can’t use the teensy shield, so I’m direct wiring with level shifters I put on a proto board (is there a better way?)
I looked at ./src/MatrixHardware_ESP32_V0.h and I see 14 pins defined

#define R1_PIN  2
#define G1_PIN  15
#define B1_PIN  4
#define R2_PIN  16
#define G2_PIN  27
#define B2_PIN  17

#define A_PIN   5
#define B_PIN   18
#define C_PIN   19
#define D_PIN   21
#define E_PIN   12    // is that pin #8 on the 16 pin connector?
#define LAT_PIN 26
#define OE_PIN  25
#define CLK_PIN 22

Getting Started with the SmartLED Shield for Teensy - SparkFun Learn shows pin mapping and I think E_PIN is #8 labelled as GND there, correct?

I’m confused by this text in the README though:
“The 5x ADDX lines are output using the RGB data lines and stored using an external latch, freeing up more pins on the ESP32
With the addition of the external latch, there are only 8 bits of data to output via I2S, and so each clock cycle’s data fits into a uint8_t instead of uint16_t. With the I2S peripheral in 8-bit mode instead of 16-bit mode, the amount of RAM used to store refresh buffers is cut in half”

I don’t have the external latch since I’m not using the shield (there is no premade shield for ESP32, is there? I see the reference to eagle files but I don’t have a shield that was actually made by someone and I think right now it’s fab your own?)
Does it mean that if I direct wire the 14 lines, the driver won’t work?
Or do I just need to
(no idea what shield/wiring #define GPIOPINOUT SMARTLED_SHIELD_V0_PINOUT refers to)


The schematic mentioned in the README shows you how to wire it up. If you don’t want to follow the schematic and use the latch, then change the pinout definition of GPIOPINOUT in the MatrixHardware_ESP32_V0.h header to ESP32_FORUM_PINOUT - this is also mentioned in the README.

I think E_PIN is #8 labelled as GND there, correct

Probably, check the schematic

I think right now it’s fab your own?

Yes, or breadboard your own

no idea what shield/wiring #define GPIOPINOUT SMARTLED_SHIELD_V0_PINOUT refers to

It’s the one described in the schematic and board files included in the hardware folder

@Louis just to make sure I’m looking at the right readme, I’m currently reading SmartMatrix/ at teensylc · pixelmatix/SmartMatrix · GitHub
I don’t see any schematics. Am I looking at the right file?

It mentions extras/hardware where I found SmartLEDShield_ESP32_V0_sch.pdf . Is that the one?
If so, it mentions 74373PW and 74S253D chips I don’t have and can’t order today (going in a plane tomorrow).

Stepping back, can I use that branch with direct wiring from ESP32 to the panel (through a couple of level shifters I do have)?
If so, do I indeed need to
and comment out
or is direct wiring untested/not working at this time?

Thanks, Marc

By the way, to explain a bit more, I’m planning on writing code during my vacation to run RGB panel at 96x64 + a neopixel strip (requires interrupts) + an infrared input (requires interrupts).
I have teensy 3.6 working now for display only but I was hoping to bring ESP32 as backup to see if it works better with those 2 extra devices.

You’re looking at the right README.

Yes, that’s the right schematic.

It’s been a while since I used direct wiring. I believe it should still be working. If I made a change that broke it intentionally, I probably would have updated the README. Yep, use #define GPIOPINOUT ESP32_FORUM_PINOUT

See I2S-parallel example: Drive a 64x32 display - ESP32 Forum for where the pinout is documented (probably in the example code provided by Sprite_TM)

Ok, thanks for the tips.
So, the good news is that I have it working somewhat. It looks mostly ok but there are issues.
First on wiring, I only used 2 level shifters, and shifted all 16 pins (the 2 that were ground I just put on ground on the level shifters input).
The most visible thing is that on layer demo, in
SMARTMATRIX_HUB75_32ROW_MOD16SCAN layer4 and layer5 don’t display at all. It’s not a problem with colors, if I change their colors it doesn’t matter.

SMARTMATRIX_HUB75_64ROW_MOD32SCAN strangely shows all 5 layers. but layer 4 and 5 are scrolling in the wrong direction (horizontal).

Now, I don’t actually need more than one layer so it doesn’t matter, but still weird. The regular demo has ghosting on fonts that scroll but it’s not visible on my phone video. It thankfully does not flash like it does here:

Edit: I just tried 64x64 panel on ESP32 and that demo looked pretty close to normal (I don’t know it by heart, so maybe I missed a detail or two). Strangely the refresh rate demo at the end shows only 16fps, however the background task takes care of a faster refresh, so I don’t see flickering. Aaah, I see a comment in the code that changing refresh rate is broken, so I’ll ignore that number. I don’t need to change it anyway as long as I can’t see flickering.

Is there a good way to validate what works and what’s off by a bit?
I’ll try and add some capacitors on the level shifters to see if it helps.

I used this:
const uint8_t kMatrixHeight = 64; // known working: 16, 32, 48, 64
const uint8_t kRefreshDepth = 36; // known working: 24, 36, 48
const uint8_t kDmaBufferRows = 4; // known working: 2-4, use 2 to save memory, more to keep from dropping frames and automatically lowering refresh rate
//const uint8_t kPanelType = SMARTMATRIX_HUB75_32ROW_MOD16SCAN;
const uint8_t kPanelType = SMARTMATRIX_HUB75_64ROW_MOD32SCAN;

In #if (GPIOPINOUT == ESP32_FORUM_PINOUT) I added this wiring comment which you’re welcome to copy/integrate if you’d like:

                ESP32 pin / comment
1	R1	2	Red Data (columns 1-16)
2	G1	15	Green Data (columns 1-16)
3	B1	4	Blue Data (columns 1-16)
4	GND	GND	Ground
5	R2	16/RX2	Red Data (columns 17-32)
6	G2	27	Green Data (columns 17-32)
7	B2	17/TX2	Blue Data (columns 17-32)
8	E	12	Demux Input E for 64x64 panels
9	A	5	Demux Input A0
10	B	18	Demux Input A1
11	C	19	Demux Input A2
12	D	21	Demux Input E1, E3 (32x32 panels only)
13	CLK	22	LED Drivers' Clock
14	STB	26	LED Drivers' Latch
15	OE	25	LED Drivers' Output Enable
16	GND	GND	Ground

I’ll make a separate comment on development questions between teensy and ESP32.
Because teensy patches my arduino install, I usually have 2 arduinos
arduino-teensy and arduino.
They launch as separate binaries with their own windows. Sadly they share the same preferences, so I have to re-set the compile target back and forth between teensy and ESP32.

Now my bigger problem/question is with the Smartmatrix ESP32 branch in teensylc. I now have this:

saruman:~/arduino/libraries$ l -d SmartMatrix* SM_ESP32*
lrwxrwxrwx 1 merlin merlin   8 Dec 22 13:42 SmartMatrix -> SM_ESP32/
drwxr-xr-x 1 merlin merlin 166 Dec 16 18:58 SmartMatrix.orig/
drwxr-xr-x 1 merlin merlin 166 Dec 21 18:27 SM_ESP32/

Currently I move the symlink back and forth because both libraries are called the same and I don’t have a good way to switch between them, and even then I have to invalidate the arduino cache which pretty much means restarting the IDE.
I think I already compiled for ESP32 once by mistake while using the master branch and it seemed to work anyway, so I’m not even sure what’s different between the branches.

That said, my method sucks and I’d like to do something easier. Any suggestions?