-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add HUB75 support #3777
base: main
Are you sure you want to change the base?
Add HUB75 support #3777
Changes from 11 commits
7ef84cf
7603b5a
755f91f
2bd1e81
07a1588
74f77a7
ecd46f2
aae9446
e94943d
e066b50
78fb9dc
e185f2e
f96acd6
e0d78d5
21c582e
ad402ad
23e578b
382d7e8
fc07397
713cbb8
b7aba15
e111b6e
8632a0a
0a8d86c
9a9c65a
fbeead0
e74eb7d
6ce6b95
5b86c67
4276671
f7b8828
c356846
6f03854
f1b9952
de8a366
d320c46
f447df9
1c146ba
d2f8f99
e6b1454
c203ef8
f51783f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -784,6 +784,200 @@ void BusNetwork::cleanup(void) { | |
freeData(); | ||
} | ||
|
||
// *************************************************************************** | ||
|
||
#ifdef WLED_ENABLE_HUB75MATRIX | ||
blazoncek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { | ||
|
||
mxconfig.double_buff = true; // <------------- Turn on double buffer | ||
|
||
switch(bc.type) { | ||
case TYPE_HUB75MATRIX_HS: | ||
mxconfig.mx_width = bc.pins[0]; | ||
mxconfig.mx_height = bc.pins[1]; | ||
break; | ||
} | ||
|
||
mxconfig.chain_length = max((u_int8_t) 1, min(bc.pins[2], (u_int8_t) 4)); // prevent bad data preventing boot due to low memory | ||
|
||
if(mxconfig.mx_height >= 64 && (mxconfig.chain_length > 1)) { | ||
DEBUG_PRINTLN("WARNING, only single panel can be used of 64 pixel boards due to memory"); | ||
mxconfig.chain_length = 1; | ||
} | ||
|
||
// mxconfig.driver = HUB75_I2S_CFG::SHIFTREG; | ||
mxconfig.clkphase = bc.reversed; | ||
|
||
#if defined(ARDUINO_ADAFRUIT_MATRIXPORTAL_ESP32S3) // MatrixPortal ESP32-S3 | ||
blazoncek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// https://www.adafruit.com/product/5778 | ||
|
||
DEBUG_PRINTLN("MatrixPanel_I2S_DMA - Matrix Portal S3 config"); | ||
|
||
mxconfig.gpio.r1 = 42; | ||
mxconfig.gpio.g1 = 41; | ||
mxconfig.gpio.b1 = 40; | ||
mxconfig.gpio.r2 = 38; | ||
mxconfig.gpio.g2 = 39; | ||
mxconfig.gpio.b2 = 37; | ||
|
||
mxconfig.gpio.lat = 47; | ||
mxconfig.gpio.oe = 14; | ||
mxconfig.gpio.clk = 2; | ||
|
||
mxconfig.gpio.a = 45; | ||
mxconfig.gpio.b = 36; | ||
mxconfig.gpio.c = 48; | ||
mxconfig.gpio.d = 35; | ||
mxconfig.gpio.e = 21; | ||
|
||
#elif defined(ESP32_FORUM_PINOUT) // Common format for boards designed for SmartMatrix | ||
|
||
DEBUG_PRINTLN("MatrixPanel_I2S_DMA - ESP32_FORUM_PINOUT"); | ||
|
||
/* | ||
ESP32 with SmartMatrix's default pinout - ESP32_FORUM_PINOUT | ||
|
||
https://github.com/pixelmatix/SmartMatrix/blob/teensylc/src/MatrixHardware_ESP32_V0.h | ||
|
||
Can use a board like https://github.com/rorosaurus/esp32-hub75-driver | ||
*/ | ||
|
||
mxconfig.gpio.r1 = 2; | ||
mxconfig.gpio.g1 = 15; | ||
mxconfig.gpio.b1 = 4; | ||
mxconfig.gpio.r2 = 16; | ||
mxconfig.gpio.g2 = 27; | ||
mxconfig.gpio.b2 = 17; | ||
|
||
mxconfig.gpio.lat = 26; | ||
mxconfig.gpio.oe = 25; | ||
mxconfig.gpio.clk = 22; | ||
|
||
mxconfig.gpio.a = 5; | ||
mxconfig.gpio.b = 18; | ||
mxconfig.gpio.c = 19; | ||
mxconfig.gpio.d = 21; | ||
mxconfig.gpio.e = 12; | ||
|
||
#else | ||
DEBUG_PRINTLN("MatrixPanel_I2S_DMA - Default pins"); | ||
/* | ||
https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA?tab=readme-ov-file | ||
|
||
Boards | ||
|
||
https://esp32trinity.com/ | ||
https://www.electrodragon.com/product/rgb-matrix-panel-drive-interface-board-for-esp32-dma/ | ||
|
||
*/ | ||
mxconfig.gpio.r1 = 25; | ||
mxconfig.gpio.g1 = 26; | ||
mxconfig.gpio.b1 = 27; | ||
mxconfig.gpio.r2 = 14; | ||
mxconfig.gpio.g2 = 12; | ||
mxconfig.gpio.b2 = 13; | ||
|
||
mxconfig.gpio.lat = 4; | ||
mxconfig.gpio.oe = 15; | ||
mxconfig.gpio.clk = 16; | ||
|
||
mxconfig.gpio.a = 23; | ||
mxconfig.gpio.b = 19; | ||
mxconfig.gpio.c = 5; | ||
mxconfig.gpio.d = 17; | ||
mxconfig.gpio.e = 18; | ||
|
||
#endif | ||
|
||
|
||
DEBUG_PRINTF("MatrixPanel_I2S_DMA config - %ux%u length: %u\n", mxconfig.mx_width, mxconfig.mx_height, mxconfig.chain_length); | ||
|
||
// OK, now we can create our matrix object | ||
display = new MatrixPanel_I2S_DMA(mxconfig); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (std::nothrow) |
||
|
||
this->_len = (display->width() * display->height()); | ||
|
||
pinManager.allocatePin(mxconfig.gpio.r1, true, PinOwner::HUB75); | ||
blazoncek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pinManager.allocatePin(mxconfig.gpio.g1, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.b1, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.r2, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.g2, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.b2, true, PinOwner::HUB75); | ||
|
||
pinManager.allocatePin(mxconfig.gpio.lat, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.oe, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.clk, true, PinOwner::HUB75); | ||
|
||
pinManager.allocatePin(mxconfig.gpio.a, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.b, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.c, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.d, true, PinOwner::HUB75); | ||
pinManager.allocatePin(mxconfig.gpio.e, true, PinOwner::HUB75); | ||
|
||
// display->setLatBlanking(4); | ||
|
||
DEBUG_PRINTLN("MatrixPanel_I2S_DMA created"); | ||
// let's adjust default brightness | ||
display->setBrightness8(25); // range is 0-255, 0 - 0%, 255 - 100% | ||
|
||
// Allocate memory and start DMA display | ||
if( not display->begin() ) { | ||
DEBUG_PRINTLN("****** MatrixPanel_I2S_DMA !KABOOM! I2S memory allocation failed ***********"); | ||
return; | ||
} | ||
else { | ||
_valid = true; | ||
} | ||
|
||
DEBUG_PRINTLN("MatrixPanel_I2S_DMA started"); | ||
} | ||
|
||
void BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { | ||
r = R(c); | ||
g = G(c); | ||
b = B(c); | ||
x = pix % display->width(); | ||
y = floor(pix / display->width()); | ||
display->drawPixelRGB888(x, y, r, g, b); | ||
} | ||
|
||
void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { | ||
this->display->setBrightness(b); | ||
} | ||
|
||
void BusHub75Matrix::deallocatePins() { | ||
|
||
pinManager.deallocatePin(mxconfig.gpio.r1, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.g1, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.b1, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.r2, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.g2, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.b2, PinOwner::HUB75); | ||
|
||
pinManager.deallocatePin(mxconfig.gpio.lat, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.oe, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.clk, PinOwner::HUB75); | ||
|
||
pinManager.deallocatePin(mxconfig.gpio.a, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.b, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.c, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.d, PinOwner::HUB75); | ||
pinManager.deallocatePin(mxconfig.gpio.e, PinOwner::HUB75); | ||
|
||
} | ||
|
||
std::vector<LEDType> BusHub75Matrix::getLEDTypes() { | ||
return { | ||
{TYPE_HUB75MATRIX_HS, "H", PSTR("HUB75 (Half Scan)")}, | ||
// {TYPE_HUB75MATRIX_QS, "H", PSTR("HUB75 (Quarter Scan)")}, | ||
}; | ||
} | ||
|
||
|
||
#endif | ||
// *************************************************************************** | ||
|
||
//utility to get the approx. memory usage of a given BusConfig | ||
uint32_t BusManager::memUsage(BusConfig &bc) { | ||
|
@@ -815,6 +1009,10 @@ int BusManager::add(BusConfig &bc) { | |
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; | ||
if (Bus::isVirtual(bc.type)) { | ||
busses[numBusses] = new BusNetwork(bc); | ||
#ifdef WLED_ENABLE_HUB75MATRIX | ||
} else if (Bus::isHub75(bc.type)) { | ||
busses[numBusses] = new BusHub75Matrix(bc); | ||
#endif | ||
} else if (Bus::isDigital(bc.type)) { | ||
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); | ||
} else if (Bus::isOnOff(bc.type)) { | ||
|
@@ -846,6 +1044,10 @@ String BusManager::getLEDTypesJSONString(void) { | |
json += LEDTypesToJson(BusPwm::getLEDTypes()); | ||
json += LEDTypesToJson(BusNetwork::getLEDTypes()); | ||
//json += LEDTypesToJson(BusVirtual::getLEDTypes()); | ||
#ifdef WLED_ENABLE_HUB75MATRIX | ||
json += LEDTypesToJson(BusHub75Matrix::getLEDTypes()); | ||
#endif | ||
|
||
json.setCharAt(json.length()-1, ']'); // replace last comma with bracket | ||
return json; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
#ifndef BusManager_h | ||
#define BusManager_h | ||
|
||
#ifdef WLED_ENABLE_HUB75MATRIX | ||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> | ||
#endif | ||
/* | ||
* Class for addressing various light types | ||
*/ | ||
|
@@ -140,6 +143,7 @@ class Bus { | |
static constexpr bool isOnOff(uint8_t type) { return (type == TYPE_ONOFF); } | ||
static constexpr bool isPWM(uint8_t type) { return (type >= TYPE_ANALOG_MIN && type <= TYPE_ANALOG_MAX); } | ||
static constexpr bool isVirtual(uint8_t type) { return (type >= TYPE_VIRTUAL_MIN && type <= TYPE_VIRTUAL_MAX); } | ||
static constexpr bool isHub75(uint8_t type) { return (type >= TYPE_HUB75MATRIX_MIN && type <= TYPE_HUB75MATRIX_MAX); } | ||
static constexpr bool is16bit(uint8_t type) { return type == TYPE_UCS8903 || type == TYPE_UCS8904 || type == TYPE_SM16825; } | ||
static constexpr int numPWMPins(uint8_t type) { return (type - 40); } | ||
|
||
|
@@ -310,6 +314,51 @@ class BusNetwork : public Bus { | |
bool _broadcastLock; | ||
}; | ||
|
||
#ifdef WLED_ENABLE_HUB75MATRIX | ||
class BusHub75Matrix : public Bus { | ||
public: | ||
BusHub75Matrix(BusConfig &bc); | ||
|
||
bool hasRGB() { return true; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't actually override as inline, bu that suggestion helped find and fix that bug |
||
bool hasWhite() { return false; } | ||
|
||
void setPixelColor(uint16_t pix, uint32_t c); | ||
|
||
void show() { | ||
if(mxconfig.double_buff) { | ||
display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) | ||
display->clearScreen(); // Now clear the back-buffer | ||
} | ||
} | ||
|
||
void setBrightness(uint8_t b, bool immediate); | ||
|
||
uint8_t getPins(uint8_t* pinArray) { | ||
pinArray[0] = mxconfig.chain_length; | ||
return 1; | ||
} // Fake value due to keep finaliseInit happy | ||
|
||
void deallocatePins(); | ||
|
||
void cleanup() { | ||
deallocatePins(); | ||
delete display; | ||
_valid = false; | ||
} | ||
|
||
~BusHub75Matrix() { | ||
cleanup(); | ||
} | ||
|
||
static std::vector<LEDType> getLEDTypes(void); | ||
|
||
private: | ||
MatrixPanel_I2S_DMA *display = nullptr; | ||
HUB75_I2S_CFG mxconfig; | ||
uint8_t r, g, b, x, y; | ||
|
||
}; | ||
#endif | ||
|
||
//temporary struct for passing bus configuration to bus | ||
struct BusConfig { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will require this to be moved into sample file. I want platformio.ini clean and only used for default official builds.