ArtNet to WS2812 (directly via SPI) - Multiple Universes

Hello all,

I’m currently designing a matrix grid which consists out of two halves. The two halves each have 27 columns and 17 rows = 459 pixels.
So, the two halves together consists out of 54 columns and 17 rows, making a total of 918 pixels. (WS2812 pixels.)
These pixels all have 3 channels (Red, Green, Blue) making a respectable 918*3=2754 channels.

With 512 channels in a single universe, this makes that the entire matrix uses 6 universes (5.37890625 to be precise ).

In the end, the matrix(/matrices) will be controlled by software like Jinx! and/or a lighting controller like a GrandMa2, all via ArtNet.

Now, the actual question:

For the sake of being able to use the halves independent of each other, i’d like to give each halve a individual node (node/artnet controller, you name it). With the above mentioned calculations, this node should be able to control 459 pixels ( = 1377 channels, = 3 universes).

I’ve tried to do this with an arduino but find it to be a bit laggy. Some advices on other threads i’ve read advised people to use a Teensy instead.

Well, that’s where the actual question comes in, does any of you have any experience or willing to help with designing the code for this to work?
Also, i’d prefer to use a ethernet cable over wireless as the device is going to be used in some public events.

Can anyone advice me in where to start, or point to any working code to be able to do this?

Also about hardware, how to make the ethernet connection, 3.3v // 5v problems, etc.

Thanks in advance!

A.

Crossposted on: ArtNet to WS2812 (directly via SPI)

Why are you re-inventing the wheel? ? ? ?

Are you that great of a programmer that you wanted a new challenge? ? ?

Someone has already done this with the Teensy.

https://www.pjrc.com/teensy/td_libs_OctoWS2811.html#videodisplay

.

Well, the link you mentioned doesn't use Art-Net for sending/receiving the data info..

Anybody with any ideas?

Thanks in advance!

I´m currently using this code with an Arduino Uno and a W5100, but unfortunately, the device isn´t receiving more than 1 universe.

With <170 LEDs the code/setup works great with Jinx!, no problems at all, however:

When i set the num_Leds to a value above 170, the device won’t even run the inittest() anymore.
To eliminate any problems in the inittest void which would prevent the arduino to complete initialization/setup, i’ve also tried with the inittest commented out but unfortunately this doesn’t work.

I’m driving the Leds with Jinx! with the device settings as seen in the attached image.

Does any of you see any problems/errors in the code? The original code comes from:

The code i’m currently using is:

/*
This example will receive multiple universes via Artnet and control a strip of ws2811 leds via 
Adafruit's NeoPixel library: https://github.com/adafruit/Adafruit_NeoPixel
This example may be copied under the terms of the MIT license, see the LICENSE file for details
*/

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

// Neopixel settings
const int numLeds = 170; // change for your setup
const int numberOfChannels = numLeds * 3; // Total number of channels you want to receive (1 led = 3 channels)
const byte dataPin = 2;
Adafruit_NeoPixel leds = Adafruit_NeoPixel(numLeds, dataPin, NEO_RGB + NEO_KHZ800);

const int dtS = 12; //750/numLeds; // Short delay time (used for test/boot program)
const int dtL = 750; // Long delay time (used for test/boot program)
const int delayLeds = 10; // Amount of leds to be on simultaniously in last step of inittest()

// Artnet settings
Artnet artnet;
const int startUniverse = 0; // CHANGE FOR YOUR SETUP most software this is 1, some software send out artnet first universe as 0.

// Check if we got all universes
const int maxUniverses = numberOfChannels / 512 + ((numberOfChannels % 512) ? 1 : 0);
bool universesReceived[maxUniverses];
bool sendFrame = 1;
int previousDataLength = 0;

// Change ip and mac address for your setup
byte ip[] = {192,168,178,77};
byte mac[] = {0x04, 0xE9, 0xE5, 0x00, 0x69, 0xEC};
byte broadcast[] = {10, 0, 1, 255};
void setup()
{
  //Serial.begin(115200);
  artnet.begin(mac, ip);
  leds.begin();
  artnet.setBroadcast(broadcast);
  initTest();

  // this will be called for each packet received
  artnet.setArtDmxCallback(onDmxFrame);
}

void loop()
{
  // we call the read function inside the loop
  artnet.read();
}

void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
  sendFrame = 1;
  // set brightness of the whole strip 
  if (universe == 15)
  {
    leds.setBrightness(data[0]);
    leds.show();
  }

  // Store which universe has got in
  if ((universe - startUniverse) < maxUniverses)
    universesReceived[universe - startUniverse] = 1;

  for (int i = 0 ; i < maxUniverses ; i++)
  {
    if (universesReceived[i] == 0)
    {
      //Serial.println("Broke");
      sendFrame = 0;
      break;
    }
  }

  // read universe and put into the right part of the display buffer
  for (int i = 0; i < length / 3; i++)
  {
    int led = i + (universe - startUniverse) * (previousDataLength / 3);
    if (led < numLeds)
      leds.setPixelColor(led, data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
  }
  previousDataLength = length;     
  
  if (sendFrame)
  {
    leds.show();
    // Reset universeReceived to 0
    memset(universesReceived, 0, maxUniverses);
  }
}

void initTest()
{
  for (int i = 0 ; i < numLeds ; i++)
    leds.setPixelColor(i, 127, 0, 0);
  leds.show();
  delay(dtL);
  for (int i = 0 ; i < numLeds ; i++)
    leds.setPixelColor(i, 0, 127, 0);
  leds.show();
  delay(dtL);
  for (int i = 0 ; i < numLeds ; i++)
    leds.setPixelColor(i, 0, 0, 127);
  leds.show();
  delay(dtL);

    for (int i = 0 ; i < numLeds ; i++)
    leds.setPixelColor(i, 0, 0, 0);
  leds.show();
  
  for (int i = 0 ; i < numLeds+delayLeds ;){
    leds.setPixelColor(i-delayLeds, 0, 0, 0);
    leds.setPixelColor(i, 100, 0, 0);
    leds.show();
    delay(dtS);
    i++;
  }

  for (int i = 0 ; i < numLeds+delayLeds ;){
    leds.setPixelColor(i-delayLeds, 0, 0, 0);
    leds.setPixelColor(i, 0, 100, 0);
    leds.show();
    delay(dtS);
    i++;
  }

    for (int i = 0 ; i < numLeds+delayLeds ;){
    leds.setPixelColor(i-delayLeds, 0, 0, 0);
    leds.setPixelColor(i, 0, 0, 100);
    leds.show();
    delay(dtS);
    i++;
  }

    for (int i = 0 ; i < numLeds+delayLeds ;){
//    leds.setPixelColor(i-delayLeds, 0, 0, 0);
    leds.setPixelColor(i, 255, 255, 255);
    leds.show();
    delay(dtS);
    i++;
  }
  delay(2000);
//      for (int i = 0 ; i < numLeds+delayLeds ;){
//    leds.setPixelColor(i-delayLeds, 0, 0, 0);
//    leds.setPixelColor(i, 0, 0, 100);
//    leds.show();
//    delay(dtS);
//    i++;
//  }


  for (int i = 0 ; i < numLeds ; i++)
    leds.setPixelColor(i, 0, 25, 0);
  leds.show();
  
}

Just before the weekend my Octows2811 SD/Ethernet adaptor board arrived so I immediately went to assemble them to my Teensy 3.2 and tested it.

Currently, also with the OctoWS2811, i’m still abled to only let 170 leds be controlled simultaniously.
I’ve uploaded the ‘BasisTest’ example from ‘PaulStoffRegen’, and adapted it a bit (number of leds, etc.) to fit my setup.

When entering more than 170 LEDs and uploading the code, nothing happens on the LEDs, they all stay ‘black’.
When entering 170 LEDs or less, the code runs fine and the correct amount of LEDs light up according to the test loop.

The same thing happen with the ArtNet example.

To eliminate any minor mistakes or typos in my used code, i’ll copy-paste the code from the IDE below.

Does any of you have any clue on how to get more than 170 LEDs driven/controlled?

For information, all LEDs (currently 204 pcs) are in series (regarding the data line), fed from the orange+orangewhite cable from the RJ45 connector in the OctoWS2811 as mentioned in this page.
Power is supplied to each column of 17 LEDs separately from common + and - rails.

Thanks in advance.
A.

/*  OctoWS2811 BasicTest.ino - Basic RGB LED Test
    http://www.pjrc.com/teensy/td_libs_OctoWS2811.html
    Copyright (c) 2013 Paul Stoffregen, PJRC.COM, LLC

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.

  Required Connections
  --------------------
    pin 2:  LED Strip #1    OctoWS2811 drives 8 LED Strips.
    pin 14: LED strip #2    All 8 are the same length.
    pin 7:  LED strip #3
    pin 8:  LED strip #4    A 100 ohm resistor should used
    pin 6:  LED strip #5    between each Teensy pin and the
    pin 20: LED strip #6    wire to the LED strip, to minimize
    pin 21: LED strip #7    high frequency ringining & noise.
    pin 5:  LED strip #8
    pin 15 & 16 - Connect together, but do not use
    pin 4 - Do not use
    pin 3 - Do not use as PWM.  Normal use is ok.

  This test is useful for checking if your LED strips work, and which
  color config (WS2811_RGB, WS2811_GRB, etc) they require.
*/

#include <OctoWS2811.h>

const int ledsPerStrip = 204;

DMAMEM int displayMemory[ledsPerStrip*6];
int drawingMemory[ledsPerStrip*6];

const int config = WS2811_GRB | WS2811_800kHz;

OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);

void setup() {
  leds.begin();
  leds.show();
}

#define RED    0xFF0000
#define GREEN  0x00FF00
#define BLUE   0x0000FF
#define YELLOW 0xFFFF00
#define PINK   0xFF1088
#define ORANGE 0xE05800
#define WHITE  0xFFFFFF

// Less intense...
/*
#define RED    0x160000
#define GREEN  0x001600
#define BLUE   0x000016
#define YELLOW 0x101400
#define PINK   0x120009
#define ORANGE 0x100400
#define WHITE  0x101010
*/

void loop() {
  int microsec = 2000000 / leds.numPixels();  // change them all in 2 seconds

  // uncomment for voltage controlled speed
  // millisec = analogRead(A9) / 40;

  colorWipe(RED, microsec);
  colorWipe(GREEN, microsec);
  colorWipe(BLUE, microsec);
  colorWipe(YELLOW, microsec);
  colorWipe(PINK, microsec);
  colorWipe(ORANGE, microsec);
  colorWipe(WHITE, microsec);
}

void colorWipe(int color, int wait)
{
  for (int i=0; i < leds.numPixels(); i++) {
    leds.setPixel(i, color);
    leds.show();
    delayMicroseconds(wait);
  }
}

Hi, How are you powering all the LEDs? Have you monitored the voltage level as you increase the number of LEDs ON? Have you at anytime had more than 170 LEDS alight?

Have you swapped your strips around to make sure you do not have a faulty 2811 LED somewhere?

Can you post a diagram of how you have the LEDs connected to the power supply. Are you feeding each strip directly back to the suppy or are you daisy chaining the power lead.

Don't forget that apart from the signal input line being essential, a good gnd return is also important as the signal reference needs to be stable, this gnd is also conducting the LED current.

If this gnd is not good, you will have a changing volt drop down the strip, this changing drop will effect your signal transmission.

Tom... :)

Thanks for your reply!

I’m pretty sure powering isn’t the problem over here as each column of 17 LEDs has its own power line to a main power rail. I’m gonna double check when i’m home with changing some around the columns (which is an easy task as every column has its own nice JST connector, this is done for easy replacement of faulty strips/columns during usage).

As far as i’ve done before all connections were really good powered with at least 4.8V at the worst points.
Power is coming from a bench lab power supply rated for 30A, currently using only ~6,5A with 170 pixels on full bright white.

I’ve attached a photo of the wiring setup, keep in mind this is an old photo with just several columns done yet. I’ll upload a new and clearer image when i’m home this evening.

On the other forum i mentioned, one proposed to run a basic fastled sketch to eliminate any connection problems, i’m gonna do that this evening.

Thanks in advance for any other thoughts!

A.

Hi,
OPs picture;
54e6f4bd0f1051ce19e6e51c1d50ca715c4cb8b9.png
A schematic would be better, where is your gnd connection between the UNO and the gnd of the strips?

Thanks… Tom… :slight_smile:

I know this is late comment and you may have found a solution. The key to handling multiple universes is to have a fast mcu, parallel and or DMA methods of driving your pixels and a decent size buffer on the Ethernet module. fastLED running on a teensy 3.2 with a wiznet W5200 is what I have experimented with . I used 16k on socket for the buffer on a modified Ethernet2 library. The new Arduinos are getting faster and the new one with the fpga is very interesting and would possibly be a great solution for smart pixels .

Here is one of my projects

For more info on the project visit http://Megapixel.lighting

Hello!

I feel a bit of relief when i read that i am not the only one with this problem.

It is almost the same problem like "fietstasss" had. when i enter a number above 158 nothing happens anymore. The thing is it can´t depend on the number of universes, because there are three channels per led and 157*3=471 and there would be 512 at all.

my setup is an Arduino Uno + Ethernet shield + the adapted Art-Net Neopixel code from GitHub, as "fietstasss"

used.

I know there is an answer from "Cree" but aktually i don´t know how to realize your tipps.

Maybe anyone here can help me due i a have no more ideas how to solve this by myself.

Thanks a lot!!!

Hi,

I’ve had the same problem, using Nactl’s Artnet Library, and my take is that the ratio of defined pixels and amount of incoming universes/channels are messing with the original code of the Library.

If you look in the original code, you see a segment:

   if ((universe - startUniverse) < maxUniverses)
     universesReceived[universe - startUniverse] = 1;

   for (int i = 0 ; i < maxUniverses ; i++)
   {
     if (universesReceived[i] == 0)
     {
       //Serial.println("Broke");
       sendFrame = 0;
       break;
     }
   }

…and I think amount of universes is somehow messing this up so that “sendFrame = 0” all the time. When this happens, further down in the code, you will see that “leds.show()” is never called because of it, and this stops the pixels from being drawn.

My solution was to simply comment out the above code segment, and then it worked! Honestly, I have no idea what this portion of code is actually doing. The only explainer given is: “Store which universe has got in”. I haven’t tried it in enough cases to see if this code is actually needed or not, but so far so good!

have you guys found a solution for this ????? if you want to use only jinx! [not other ] then there might be some alternatives like you dont even need an ethernet shield. you just need an arduino connected thru USB.. these terms universes/ channels are big headache and for matrix type setup you would face difficulty in pixel mapping in patch setup in jinx if you have irregular number of channels than matrix dimensions ...

so better way could be tpm2.net mode ore glediator mode in Jinx!.. so now no banging with universes just add correct number of channels and patch pixels correctly ...

you said you wanted wired control but if you wished wireless control you could use ESP8266or Esp32..those are far better than Arduino .