E1.31 sACN Ethernet DMX Performance help - 6 Universe Limit improvements?

crees

Well-known member
Hi Group

I am working on E1.31 DMX and needs some help getting it fine tuned. I currently have 6 universes working on it but trying to at least double that and more.
Here is the code so far (sloppy, hacked up, needs improvement, be kind :)) What I need help with is how to process the ethernet packet buffer better to get all desired universes. In my serial out inside the LED send loop I get 6 universes consistently. anything over is hit or miss. universe 7 is about once per second and 8 is every few seconds.

I have ethernet set to 1 socket at 24Mhz. I am using the wiz820io .

Code:
// E1.31 Receiver and pixel controller by Andrew Huxtable (andrew@hux.net.au)
// This code may be freely distributed and used as you see fit for non-profit
// purposes and as long as the original author is credited and it remains open
// source



#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#define USE_OCTOWS2811
#include<OctoWS2811.h>
#include<FastLED.h>


//*********************************************************************************


// enter desired universe and subnet  (sACN first universe is 1)
#define DMX_SUBNET 0
#define DMX_UNIVERSE 1 //**Start** universe


// Set a different MAC address for each...
byte mac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x15 };


// Uncomment if you want to use static IP
//*******************************************************
// ethernet interface ip address
IPAddress ip(192, 168, 2, 21);  //IP address of ethernet shield
//*******************************************************


EthernetUDP Udp;


// By sacrificing some of the Ethernet receive buffer, we can allocate more to the LED array
// but this is **technically** slower because 2 packets must be processed for all 240 pixels.


/// DONT CHANGE unless you know the consequences...
 #define ETHERNET_BUFFER 540 //540
 #define CHANNEL_COUNT 4080 //because it divides by 3 nicely
 #define NUM_LEDS 1360 // can not go higher than this - Runs out of SRAM
 #define NUM_LEDS_PER_STRIP 170
 #define NUM_STRIPS 8
 #define UNIVERSE_COUNT 7
 #define LEDS_PER_UNIVERSE 170
 //#define BRIGHTNESS 100





//********************************************************************************


// Define the array of leds
CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];

// Pin layouts on the teensy 3:
// OctoWS2811: 2,14,7,8,6,20,21,5


unsigned char packetBuffer[ETHERNET_BUFFER];
unsigned char unidrop[UNIVERSE_COUNT + 1];
int s = 0;
void setup() {

    pinMode(9, OUTPUT);
  digitalWrite(9, LOW);   // reset the WIZ820io
  delay(10);
   digitalWrite(9, HIGH);   // reset the WIZ820io
  //pinMode(10, OUTPUT);
 // digitalWrite(10, HIGH);  // de-select WIZ820io
  //pinMode(4, OUTPUT);
  //digitalWrite(4, HIGH);   // de-select the SD Card
    Serial.begin(115200);
    delay(10);
  // Using different LEDs or colour order? Change here...
  // ********************************************************
  LEDS.addLeds<OCTOWS2811>(leds, NUM_LEDS_PER_STRIP);
  LEDS.setBrightness(32);
  // ********************************************************


 
  // ********************************************************  
  Ethernet.begin(mac,ip);
  Udp.begin(5568);
  // ******************************************************** 
    Serial.print("server is at ");
    Serial.println(Ethernet.localIP());

  //Once the Ethernet is initialised, run a test on the LEDs
  //initTest();
}







void sacnDMXReceived(unsigned char* pbuff, int count) {
  if (count > CHANNEL_COUNT) count = CHANNEL_COUNT;
  byte b = pbuff[113]; //DMX Subnet
  if ( b == DMX_SUBNET) {
    b = pbuff[114];  //DMX Universe
   

    
    Serial.println(b );
    if ( b >= DMX_UNIVERSE && b <= DMX_UNIVERSE + UNIVERSE_COUNT ) {
    




    
      if ( pbuff[125] == 0 ) {  //start code must be 0
      int ledNumber = (b - DMX_UNIVERSE) * LEDS_PER_UNIVERSE;
       // sACN packets come in seperate RGB but we have to set each led's RGB value together
       // this 'reads ahead' for all 3 colours before moving to the next led.
       //Serial.println("*");
       for (int i = 126;i < 126+count;i = i + 3){
          byte charValueR = pbuff[i];
          byte charValueG = pbuff[i+1];
          byte charValueB = pbuff[i+2];
          leds[ledNumber] = CRGB(charValueR,charValueG,charValueB);
          //Serial.println(ledNumber);
          ledNumber++;
        }
  LEDS.show();

 
      }
          

      
    }
  }

}


int checkACNHeaders(unsigned char* messagein, int messagelength) {
  //Do some VERY basic checks to see if it's an E1.31 packet.
  //Bytes 4 to 12 of an E1.31 Packet contain "ACN-E1.17"
  //Only checking for the A and the 7 in the right places as well as 0x10 as the header.
  //Technically this is outside of spec and could cause problems but its enough checks for us
  //to determine if the packet should be tossed or used.
  //This improves the speed of packet processing as well as reducing the memory overhead.
  //On an Isolated network this should never be a problem....
  if ( messagein[1] == 0x10 && messagein[4] == 0x41 && messagein[12] == 0x37) {   
      int addresscount = (byte) messagein[123] * 256 + (byte) messagein[124]; // number of values plus start code
      return addresscount -1; //Return how many values are in the packet.
    }
  return 0;
}


void initTest() //runs at board boot to make sure pixels are working
{
  LEDS.showColor(CRGB(255, 0, 0)); //turn all pixels on red
   delay(1000);
   LEDS.showColor(CRGB(0, 255, 0)); //turn all pixels on green
   delay(1000);
   LEDS.showColor(CRGB(0, 0, 255)); //turn all pixels on blue
   delay(1000);
   LEDS.showColor(CRGB(0, 0, 0)); //turn all pixels off
}

void loop() {
   //Process packets
   int packetSize = Udp.parsePacket(); //Read UDP packet count
   if(packetSize){
    Udp.read(packetBuffer,ETHERNET_BUFFER); //read UDP packet
    
    int count = checkACNHeaders(packetBuffer, packetSize);
    if (count) {
     // Serial.println("packet");
      sacnDMXReceived(packetBuffer, count); //process data function
      
    }
  }


}
 
Last edited:
Found some success. I realized I am Excessively using LED.show. And my buffer was too small (My opinion needs to be at least the size of the UDP Parse count). Using LED.show too much (pretty much each loop) was causing the code to not read all of the universe data. So I changed how often I would use the LED.show and whalla.

I only have one short reel of ws2812's. I will have one of the guys here in the forum give it a shot on hist large matrix. I should know for sure if indeed the code is working as desired. But theoretically each of my octo pins is sending smooth pixel data AND at 24 Universes! I would try more but getting too late tonight and I don't want to reconfigure the code and jinx ......
 
Last edited:
Here is a video of some of the Success so far with the teensy 3.2 with octows2811 and w820io. The following link is a video of a 1600 pixel matrix. Its running Serial in this link.

https://drive.google.com/file/d/0B6w4dAvJM-_rXzlCQlA4QnhEZ0U/view

We just got e1.31 working on this same matrix. Its much smoother. I will get that video up shortly. I was able to increase the universes up to 32 without missing a beat.
 
Hello crees.
Could you post your correct last Code please?

https://gist.github.com/mrrees/d4ab83251ec6f9cd83d8b4f69d8105ec

It sounds like from reading the forum your running RGBW? I had the same / similar issues as you but running RGB. The code is far from perfect so mileage may vary. One thing I found out is each loop I was sending the LED array (ledshow). Doing this it would delay or miss universe data in the buffer causing the later universes to miss or get overwritten in the buffer. When using serial print I can see this happening.

Using the one socket library and I changed my code to only send LED array (ledshow) to the pixels after I looped through 10 universes of data. you will see the unicount == 10 statement that it checks before it sends the pixel array. After doing this I was able to get 32 Universes of data to send at 25FPS. The way I tested without having that many pixels is I connected what pixels I had on each pin at a time to check (and make sure I was getting full frames and no delay).
 
After some Troubleshooting Andrew was able to clear up most of the issues using The Ethernet module. The problem was some of the octo feeds or sections of the matrix would randomly flicker. After connecting all grounds and wiring the teensy to get its 5v from one of the matrix power supplies (instead of being powered over USB from another source) the display flicker went away! Now the ethernet module is being used and its more fluid and smooth and the colors appear to be richer.

Video Link

https://drive.google.com/file/d/0B6w4dAvJM-_rd0ZWUmFLcjVCMUk/view

I want to thank many here who have helped us out (directly and indirectly). The Teensy platform is one of the best DIY solutions for driving large amounts of pixels.
 
any chance you can publish the final code on github?
I am looking to use a teensy to drive my lights over ethernet using E1.31.

One quick question, which teensy are you using and what do you think the max LEDs you can drive is? Im assuming you only tested to 32 universes (x512) assumes around 16,000 channels and 5,500 pixels. Was that with the v3.5?
 
Hi Tigga69.

Post 5 has my most recent code. My tests for 32 universes changed the following lines

around line 63
#define CHANNEL_COUNT 16320 //because it divides by 3 nicely
#define NUM_LEDS 5440 // can not go higher than this - Runs out of SRAM
#define NUM_LEDS_PER_STRIP 680
#define NUM_STRIPS 8
#define UNIVERSE_COUNT 32
#define LEDS_PER_UNIVERSE 170

and

line 163
if (unicount == 32){

As far as pixel count I do not use the full 512 universe. I use 510 because that is the exact number of RGB pixels I can use. When using controlling software like jinx I specify that I am only using 510 channels.

The code needs some cleanup and I will get that done. Its pieces of code from others with a sloppy mix of mine :) but one example to cleanup the code would be on line 163 by placing UNIVERSE_COUNT where 32 is. That way there would only be one place to change values.

The next set of code will be cleaned up and more specific to the board I just got in.

 
Last edited:
thanks that all makes sense; the limiting factor being the SRAM not the processor speed.
I should be comfortable as I am only planning to run around 3000 LEDs at the moment, so 9000 channels. Was more a curiosity thing on my side.
I saw also you were testing on the Windows version of Jinx... That's useful to know as I am using both Jinx and Xlights.


It looks like you are using a Teensy 3.2 but I dont recognise the Megapixel Controller, it doesnt appear on PJRC site. Is this something you have designed? Im guessing it is judging by the 'by CCR' printed on the board.
It looks a stage up from the OctoWS2811 adapter because you have the expansion slot for the Ethernet and you have the power with a fuse!
Looks cool... how do we get one! whats the cost???

thanks for the info and the code.
Rich.
 
thanks that all makes sense; the limiting factor being the SRAM not the processor speed.
I should be comfortable as I am only planning to run around 3000 LEDs at the moment, so 9000 channels. Was more a curiosity thing on my side.
I saw also you were testing on the Windows version of Jinx... That's useful to know as I am using both Jinx and Xlights.


It looks like you are using a Teensy 3.2 but I dont recognise the Megapixel Controller, it doesnt appear on PJRC site. Is this something you have designed? Im guessing it is judging by the 'by CCR' printed on the board.
It looks a stage up from the OctoWS2811 adapter because you have the expansion slot for the Ethernet and you have the power with a fuse!
Looks cool... how do we get one! whats the cost???

thanks for the info and the code.
Rich.

Yes teensy 3.2, Love the pixel power it packs for its small footprint! I designed the controller board that I can place all the components on it with the option of replacing the bus transceiver (adopted this idea from the Christmas lights controller) with some breakout pins for DMX, and two power regulators (3.3v, and 5v). The 5v regulator spot is only needed if you run a 12v power. 3.3v spot is added just in case you have a teensy3.1 or the 3.2 doesn't have enough to power additional 3.3v devices.

I need to make some changes on the board and move the mounting holes so the board can be stacked. I rushed this one to test but knowing it would be moved at some point. I did get about dozen of these to test with. if your interested in getting one PM me your contact info and I will get you more info.
 
@crees - i note that you are using FastLED rather than the native OctoWS2811 driver. Was that a conscious decision?

I ask, because the inclusion of FastLED incurs the cost of an additional Buffer, which means you then have three buffers or 3 * (3 * NUM_LEDS) bytes for LED array storage. The Teensy has 64K so if you need 20K for your LEDs, you will need 60K just for LED buffers, before you handle a single packet. Using the Teensy without FastLED will remove one of those buffers and I can't see anything in the code that is using any of the benefits of FastLED (built in math functions, palettes, or blending for example), so you could increase the number of LEDs by removing FastLED.

HSIBOY
 
Your correct about the triple buffer. One reason I am using fastLED is so I can use the color animation effects as presets so I can run it without the need of software elsewhere. I also understand by using both you benifit from a faster frame rate capability. But you bring up a good point and its worth running without fastLED to compare performance and see how many more LED's you can get
 
i just stumbled across an issue on FastLED's github, where if NUM_LEDS_PER_STRIP is 864 or less, it works. if 865 or greater it crashes, because its using 60k for LED buffers.
However 864 LEDs with 8 strips, is a fair amount of LEDs.

I'll knocked up a native Octo2811 version and have a play.

HSIBOY
 
hsiboy brings up a good point on memory. But one of the reason I chose fastLED was to take advantage of faster timings. Quote from fastLED

512 leds on 8 pins, w/FastLED3.0: 15,360µs or 66fps max
512 leds on 8 pins, w/OctoWS2811 using setPixel: 2000µs or 500fps max
512 leds on 8 pins, w/FastLED3.1 parallel output: 1900µs or 526fps max
512 leds on 8 pins, w/FastLED3.1 feeding OctoWS2811: 500µs or 2000fps max (sadly, WS2811's get unhappy if you go above 400-500fps)

Thoughts?
 
Yeah, i saw that, and that's what got me onto the additional buffer that FastLED brings to the table. FastLED writes to the additional buffer, to allow the Teensy to do its DMA magic unhindered, hence the speed increase.

I guess, looking at those figures, the first thing that jumps out at me is that the "test" was conducted with just 64 leds per output (8*64=512). According to that page, if a WS2811 (or derivative) is running at 800KHz, then it needs 30µs to write out the data for a single pixel. Therefore the theoretical maximum speed (for this test) is 64*30µs = 1.92 milliseconds per strip (8 strips in parallel). The timing constraints of the LEDs is fixed @ 800KHz, so where does the 500µs (or 2KHz) figure come from? Pure CPU time? i.e the time to execute a "fill leds with colour, show.leds" loop (which hands off to the underlying Teensy buffers) and not the actual refresh speed of the LEDs? Because the WS2811 has onboard PWM with a free running clock, per pixel. The frequency of that is ~2mS per PWM cycle, therefore the fastest we could flash/refresh a WS2811 is ~2mS

I think I need to test this, pure output, without Art-Net or sACN packet handling and see just how fast it can go, with a long (1,000) string of LEDs, using the FastLED driving the OctoWS2811 driver.

Then i can find out how many LEDs it can handle before FastLED fails to malloc, and how fast it can refresh the LEDs as length will be a factor (i'll use a photo diode and the scope trigger to measure the update, rather than raw loop cycles). I should have that done by, let's say October!

HSIBOY
 
Just a very quick update.

I can get 16 universes (+2700 LEDs) of Art-Net out of 4 output pins, so that each output supports 4 universes and i think it can do twice that!

e.g
Output A - Universe 0,1,2,3
Output B - Universe 4,5,6,7
Output C - Universe 8,9,10,11
Output D - Universe 12,13,14,15

I'm reading the size of the universe from the data that arrives.

But i have only managed to do this by throwing away OctoWS2811 lib and FastLED lib. They add way too much bloat, all your RAM is gone before you even process a packet (i'm testing using 170 LEDs per universe, or 510 channels).

I read the universe into an array (the max size of an art-net packet is 576 bytes.), and throw it at the LEDs. Nothing more.

Downside. Timing is critical, and i have lots of glitches and flickering, I'm dropping the odd packet, and I see odd colourings now and then, so i need to work on it a lot more (and understand Teensy interrupts a bit better), but here is where the source for OctoWS2811 and FastLED have been invaluable; i will continue to chip away at it.

HSIBOY
 
Hi Crees, do you really managed to receive more then 2 universes on sACN at normal speeds. Whatever I try, if there is lots of traffic on universes lower than the ones I need, I have very slow refresh rate.
 
I just bought a wiz820io, it has the W5200 chipset. But for some reason nu UDP packets are recived anymore. I do have proper SPI communication. I get the IP ping from the Wiz820io. Here is the basics of my code. If you see any problem, please advice.
//PINOUT: WIZ820io :SCK=13 MISO=12 MOSI=11 CS=10 RST=9 PWDN=gnd

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>


byte Mac[] = {0x74,0x69,0x69,0x2D,0x30,0x15};
IPAddress ip(192, 168, 1, 179);

EthernetUDP Udp;


void setup() {
//reset the WIZ820io
pinMode(9, OUTPUT);
digitalWrite(9, LOW); // begin reset the WIZ820io
delay(50);
digitalWrite(9, HIGH); // end reset pulse
delay(5000);

Serial.begin(19200);
delay(10); // let UART settle

Ethernet.begin(Mac, ip );

// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.hardwareStatus() == EthernetW5200) {
Serial.println("W5200");
}
if (Ethernet.hardwareStatus() == EthernetW5100) {
Serial.println("W5100");
}
if (Ethernet.hardwareStatus() == EthernetW5500) {
Serial.println("W5500");
}
// Check for Ethernet cable connected
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}

Udp.begin(5568);

delay(10);
// Check if IP adress is set to WIZ820io
Serial.print("ip adress : ");
Serial.println(Ethernet.localIP());
delay(1000);
}



void loop() {

//Process packets
int packetSize = Udp.parsePacket(); //Read UDP packet count

if (packetSize) {
Serial.print("Packet received with size = ");
Serial.println(packetSize);

}
}
 
Hi all, I am trying to replicate the success of people here to create Ethernet attached e1.31 controller.
I have multiple ESPixelSticks, but wifi is not always reliable enough and I am building 1 or 2 wired controllers for Christmas decorations.

I got the Crees code from svn (there seems to be a bracket in wrong position after latest commit) and tried also code seen in the thread.

The problem I am facing is that it seems not all universes or the last universe is not received/detected and "Leds.show();" is not called frequent enough.
Because of thes LEDs are updated every 0.5..1sec only.
Please see code bellow. If I change to trigger on 1st universe instead of the last, refresh rate is as expected and LED's updated properly.

Code:
//      if (b == 1 - DMX_UNIVERSE + UNIVERSE_COUNT){
        if (b == DMX_UNIVERSE){
        //Turn Framing LED ON
        digitalWrite(4, LOW);
        LEDS.show();
        //Frames Per Second Function fps(every_seconds)
        fps2(10);
        }

also whe I print 'b' what is received universe to serial port I see only 7 universes - 1,2,3,7,12,17,23 . Tried lowering the frame rate to 10fps - get the same results.

I am using xLights to send the data. There are 32 universes defined 510 channels each, unicast, then a panel made out of them.
Mind that currently I have only 1st output of OctoWS connected LED strip, so cannot physically verify that all universes are received.

Forgot to mention that ethernet module used is W5500 based.

Am I sending the data wrong? What could be the possible cause of this.

Cheers,
Kaspars
 
Last edited:
Hi all, I am trying to replicate the success of people here to create Ethernet attached e1.31 controller.
I have multiple ESPixelSticks, but wifi is not always reliable enough and I am building 1 or 2 wired controllers for Christmas decorations.

I got the Crees code from svn (there seems to be a bracket in wrong position after latest commit) and tried also code seen in the thread.

The problem I am facing is that it seems not all universes or the last universe is not received/detected and "Leds.show();" is not called frequent enough.
Because of thes LEDs are updated every 0.5..1sec only.
Please see code bellow. If I change to trigger on 1st universe instead of the last, refresh rate is as expected and LED's updated properly.

Code:
//      if (b == 1 - DMX_UNIVERSE + UNIVERSE_COUNT){
        if (b == DMX_UNIVERSE){
        //Turn Framing LED ON
        digitalWrite(4, LOW);
        LEDS.show();
        //Frames Per Second Function fps(every_seconds)
        fps2(10);
        }

also whe I print 'b' what is received universe to serial port I see only 7 universes - 1,2,3,7,12,17,23 . Tried lowering the frame rate to 10fps - get the same results.

I am using xLights to send the data. There are 32 universes defined 510 channels each, unicast, then a panel made out of them.
Mind that currently I have only 1st output of OctoWS connected LED strip, so cannot physically verify that all universes are received.

Forgot to mention that ethernet module used is W5500 based.

Am I sending the data wrong? What could be the possible cause of this.

Cheers,
Kaspars

OK, I see I need to use wiz820io module which is W5200 based. Can something be done to make this work on W5500?
 
OK, I see I need to use wiz820io module which is W5200 based. Can something be done to make this work on W5500?

I have a few updates I need to post (I will get that up today somtime) . I also have a hacked one socket library that works for the w5500. However the TX buffers are incorrect or wrong and will corrupt any outbound data(still working on it)

crees
 
Back
Top