Hi all,
I've been working on a project using some of these 32 x 32 RGB LED matrices from Adafruit. I am controlling each panel using an ESP8266 and the PxMatrix library- the ESP8266 is embedded into a board that fits into the LED panel's headers. My plan is to control each LED panel through MadMapper by sending wireless sACN to the ESP8266 using the AsyncE131 library.
So far everything works more-or-less just fine with 1 LED panel apart from the occasional freezing. However, when I add multiple panels I get considerable lag and some sACN universes will begin to drop out. When using multiple panels, the 2nd panel will consistently have it's last universe drop out- and when using more than 2 panels, the 3rd and 4th panels are so laggy that they all but freeze up entirely.
I'm assuming part of the issue is likely due to just how much sACN data I'm sending. Each LED panel/ESP8266 takes up 7 universes(with the last universe only being 12 of the 512 channels). With 4 panels, this already takes up 28 universes. However when I use serial monitor to look at an ESP8266 receiving the sACN data, I see no errors. I'm quite new to any sort of lighting setup involving this many universes and I've wondered if it also might be an issue with my router(Netgear R6230) and it's ability to handle 28 universes of UDP. I've also wondered if doing sACN wirelessly is the issue and if it'd be easier to just redo the project using an Uno or Nano with an Ethernet shield.
I've included the code below. Any suggestions on managing lag and universe dropouts with sACN are much appreciated!
Thanks,
Amina
#include <ESP8266WiFi.h>
#include <ESPAsyncE131.h>
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_I2CRegister.h>
#include <Adafruit_SPIDevice.h>
#include <PxMatrix.h>
#include <Ticker.h>
Ticker display_ticker;
#define P_LAT 16
#define P_A 5
#define P_B 4
#define P_C 15
#define P_D 12
#define P_E 0
#define P_OE 2
#define matrix_width 32
#define matrix_height 32 //Adjust as needed based on display size.
const uint8_t panelNumber = 1; //Number of LED matrix panel in array of panels. Added mostly for convenience to alter UNIVERSE and last octect of IP address with 1 variable.
uint8_t display_draw_time=30; //30-70 is usually fine
const uint8_t scan_rate = 16; //8 for 1/8, 16 for 1/16, 32 for 1/32.
//PxMATRIX display(32,16,P_LAT,P_OE,P_A,P_B,P_C); //Enable for 1/8 scan.
PxMATRIX display(32,32,P_LAT,P_OE,P_A,P_B,P_C,P_D); //Enable for 1/16 scan.
//PxMATRIX display(32,32,P_LAT,P_OE,P_A,P_B,P_C,P_D,P_E); //Enable for 1/32 scan.
#define UNIVERSE 50 + (7 * panelNumber) //Start universe
#define UNIVERSE_COUNT 7 //# of total Universes, starting from UNIVERSE. 7 Needed for 32 x 32 display, 4 for 32 x 16.
const int CHANNELS_PER_UNIVERSE = 510; //510 because 170 LEDS * 3 = 510. 512 causes an LED to overlap into multiple universes.
uint8_t CHANNEL_VAL[(matrix_width*matrix_height)*3];
uint8_t PAST_CHANNEL_VAL[(matrix_width*matrix_height)*3];
const uint8_t ipOctet = 110 + panelNumber; //Sets last octet of ip address based on panelNumber.
const char ssid[] = "network"; // Replace with your SSID
const char passphrase[] = "password"; // Replace with your WPA2 passphrase
IPAddress ip(10, 0, 0, ipOctet);
IPAddress gateway(10, 0, 0, 1);
IPAddress subnet(255, 255, 0, 0);
ESPAsyncE131 e131(UNIVERSE_COUNT);
void display_updater()
{
display.display(display_draw_time);
}
void display_update_enable(bool is_enable)
{
if (is_enable)
display_ticker.attach(0.004, display_updater);
else
display_ticker.detach();
}
bool newValue(uint8_t x, uint8_t y){ //Checks if each LED's RGB values have changed since previous packet.
uint16_t channel = ((x*3)*matrix_height)+(y*3);
if(CHANNEL_VAL[channel] != PAST_CHANNEL_VAL[channel] ||
CHANNEL_VAL[channel+1] != PAST_CHANNEL_VAL[channel+1] ||
CHANNEL_VAL[channel+2] != PAST_CHANNEL_VAL[channel+2])
{
PAST_CHANNEL_VAL[channel] = CHANNEL_VAL[channel];
PAST_CHANNEL_VAL[channel+1] = CHANNEL_VAL[channel+1];
PAST_CHANNEL_VAL[channel+2] = CHANNEL_VAL[channel+2];
return true;
}
else{return false;};
}
void drawPixels(){ //Draws all pixels that have changed values since last packet.
for(uint8_t x=0; x<matrix_width; x++){
for(uint8_t y=0; y<matrix_height; y++){
if(newValue(x,y)){
uint16_t channel = ((x*3)*matrix_height)+(y*3);
display.drawPixelRGB888(x,y,CHANNEL_VAL[channel],CHANNEL_VAL[channel+1],CHANNEL_VAL[channel+2]);
};
};
};
}
void e131PullPacket(){ //Pulls new sACN packet, records values into CHANNEL_VAL[] and then draws changed pixels.
if (!e131.isEmpty()) {
e131_packet_t packet;
e131.pull(&packet); //Pull packet from ring buffer.
uint16_t universePacket = htons(packet.universe);
uint16_t lastUniverse = universePacket == ((UNIVERSE + UNIVERSE_COUNT) ? CHANNELS_PER_UNIVERSE - (CHANNELS_PER_UNIVERSE - 12) : 0);
uint16_t numChannels = CHANNELS_PER_UNIVERSE - lastUniverse;
for(uint8_t universe=0; universe<UNIVERSE_COUNT; universe++){
if(universePacket == UNIVERSE+universe){
for(uint16_t channel=0; channel<numChannels; channel++){
CHANNEL_VAL[channel + (CHANNELS_PER_UNIVERSE * universe)] = packet.property_values[channel + 1];
};
drawPixels();
break;
};
};
};
}
void blinkTest(){
display.drawPixelRGB888(0,0,255,255,255);
delay(1000);
display.drawPixelRGB888(0,0,0,0,0);
delay(1000);
}
void setup() {
//Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.config(ip, gateway, subnet);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED) {delay(500);}
e131.begin(E131_MULTICAST, UNIVERSE, UNIVERSE_COUNT);
display.begin(scan_rate);
display.clearDisplay();
display_update_enable(true);
}
void loop() {
e131PullPacket();
//blinkTest();
}