Troubleshooting sACN-controlled RGB LED Matrix

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();
}

Well, I'm just going to leave notes here for myself for the sake of documentation. :slight_smile:

Things I've tried and/or discovered in the past week of troubleshooting:

  • Tried setting all 4 RGB LED panels to the same DMX universe/address to test if the issue was being caused specifically by each panel taking up 7 separate universes; all the panels still had the same behavior where 1 or 2 panels will begin to lag or freeze up- which seems to suggest that the issue isn't necessarily due to the large number of universes being transmitted.

  • Tried controlling the RGB LED panels from my fastest laptop(Acer Predator Helios 300 w/ i7 processor) as opposed to a slightly more dated MacBook Pro; dropouts and freezing seemed to noticeably decrease(even when each panel had unique DMX universes/addresses), but was still an issue.

  • Tried disconnecting my router from the internet while running sACN(I already knew from the start that running internet on the same network as sACN is a bad idea); dropouts and freezing seemed to noticeably decrease but only if I had been doing something bandwidth-heavy on the internet apart from the sACN.

My theory at this point is that perhaps it is just due to my router/modem not being able to handle the necessary bandwidth for sACN. I've been considering getting a dedicated wireless access point and read in a few different DMX lighting forums that the Ubiquity Nanostation LocoM2 is a particularly good one for wireless sACN or Artnet. It'd be a shame to buy it only to find out that it doesn't actually make any difference in the freezing/lag in my RGB LED panels, though.

Hi, I'm very new to ESP8266 module and with P6 RGB matrix. Actually I'm struggling to get going with 32x32 matrix using PxMatrix library. I was trying to follow your code for reference, but it seems not working. Can you please help me with few lines to code to make this 32x32 display get working.

I used this as you mentioned, but may be some other thing I'm missing.
PxMATRIX display(32, 32, P_LAT, P_OE, P_A, P_B, P_C, P_D);

Hi- if you're just getting started with using ESP8266 and with RGB matrices, you might have better luck by just reading through the instructions on the PxMatrix library. My code is for controlling RGB matrices with DMX lighting software- so it is a bit more involved than just getting the RGB matrix working on it's own.

Adafruit also has some great resources for getting started with RGB matrices. Here is an instruction page on getting started using RGB matrices with an Arduino Uno and an Adafruit RGB matrix shield. The Adafruit instruction page also has steps for connecting an Uno directly to an RGB matrix with jumper wires. The PxMatrix library has instructions for doing similarly with an ESP-12E.

Hopefully that helps.

:slight_smile: Amina

Thank you for your response. Actually I started with Uno board only, but Adafruit library doesn't seem to support 32x32 matrix. So I bought an ESP8266 node MCU and tried the PxMatrix library. But I now realise that I did not follow the pin connection properly as mentioned in GIT page. I spent last full weekend trying it and failed. Next weekend I would try their instructions. Once again thank you for guiding here. I'm not a professional, I do this just for my interest.