Go Down

Topic: ArtNet to WS2812 Pixel LED driver : Using Wemos D1 (arduino-esp8266) (Read 7738 times) previous topic - next topic

patdev

Nice work Bob. My panels will travel through europe this summer mounted on top of the car shown below.

Well thats if i manage to make it complete flickerfree (just 1 led left from the 1200 for one panel) on time and responsive in sync with the music (there is some delay when i stop the output in jinx :-()

Do you have an idea which direction in need to look. I think it is the reading of the universes.


mcnobby

The stop delay you are finding is due to buffering of packets, this means that your device cannot deal with packets fast enough. You need to trim the UDP RX routine right down using every possible trick in the book so that ALL universe can be read as fast as possible - this is what took me weeks to work out. Running at 160MHz is a major help, remove some of the characters from your 'A'r't'-'N'e't' checker, only read the size of the universe ONCE when the data starts streaming as it will always be the same after that

You need to get to a point where you can leave the device running for an hour or two, switch off and have NO stop delay at all, and also watch an animated display (like rain) and check that no packets are dropped, also if you see a green LED at first position every 54 seconds then this also has to do with inefficient universe reading
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

mcnobby

Also, are you using PCBs with just the ob board 'Reverse-F' PCB antenna ? or the boards with a Ceramic antenna ? or the ones where you can put an external one on ?

With the super cheap PCB antenna boards, it can be twitchy as to the angle of the PCB due to the way the antenna works and really should be in line radially with your router

With the ceramic antenna boards they can have an ex socket for antenna, dont bother with the ceramic as it isnt much of an improvement over the PCB one, but the external antenna works much much better - I found this a Huuuuuuge improvement in efficient reception
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

patdev

Bob, thanks for the tricks. I allready reduced the check on art-net of the first items in the packet as you proposed earlier in this discussion. The size is calculated once etc. It is running at 160Mhz. I use the standard on board antenna at the moment. But i ducktaped the esp on top of the wifi router ;-).



patdev

Well i removed every check on the header info, i check for universe size only once. And now i have a green blinkin led again ;-( not the first on of the strand, but the last of a strand of 4 strips.

I think i will solder the esp in the wifi router ;-). I think a take a little break or wait until youre finished.


mcnobby

Scope the NRZ signal and check your timing

I think you will find when the green appears you will see a long single first bit appear on the NRZ signal
What I guess is happening is even through the interrupts are turned off the ESP is still interrupting the data flow

Do an experiment systematically removing the ICACHE_FLASH_ATTR tags, I found that when I was running 32 universes I had to remove just about all of them, although I may have left one in the WSout routine

Post the slice of code of how you collect your universes and pack them into arrays and I will check it over
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

patdev

Well i managed it finally to drive a matrix of 2880 pixels. With many thanks to Bob and his example code and a hint. Next step is mounting it together. 

mcnobby

Well i managed it finally to drive a matrix of 2880 pixels. With many thanks to Bob and his example code and a hint. Next step is mounting it together. 
Very impressive !
Next step 5440 Pixels, and it IS possible ;)
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

patdev

For now 2880 pixels and a three channel firemachine will do. ;-)

camilozk

ey mcnobby!

with some delay, I tried your suggestion posted on #22, and I effectively got rid of the problem on the first pixel.

I am currently controlling my led strip from Resolume Arena.

Thank you so so so much for sharing this!

mcnobby

http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

camilozk

Hi mcnobby!

Let me ask you something. I am working on an Installation in which I am using 197 pixels of WS2812b. I am using your sketch to drive the strip via resolume, and I discovered today that with my current configuration, I can only drive 170 pixels (510 dmx channels), as the program I am using (copied below) supports only one universe.

Now, should I add another wemos between pixel 170 and 171 which will receive data from universe = 1 (the first wemos receives data from universe = 0), or is there a trick to control more than one universe with one wemos?

Thanks!





mcnobby

Hello Camilozk

(you forgot to copy your program below)

Yes, you will need to capture the first universe into an array, as you are currently doing
Then capture the very next universe into an additional array

Once you have both arrays, then send them one after another using the WS2812 output routine. This should work just fine as I have done this with four consecutive arrays/universes

Make sure that you capture the universe size of BOTH arrays and use that to send the length of the outputs

If you are using Jinx! you will need to make sure you set the size if the universes you are using so that that this information is sent over the UDP message and decoded correctly

Bob
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

camilozk

thanks for your answer!

Now I WILL copy the program.

Code: [Select]

/*
  SmartShow AirPixel ONE - Single Universe ArtNet to WS2812 Driver - For Wemos D1
  You can set the Device IP, and universe number below
  Works perfectly with Jinx LED software
*/

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

#define WSout 5  // Pin D1
#define WSbit (1<<WSout)

// ARTNET CODES
#define ARTNET_DATA 0x50
#define ARTNET_POLL 0x20
#define ARTNET_POLL_REPLY 0x21
#define ARTNET_PORT 6454
#define ARTNET_HEADER 17

WiFiUDP udp;

uint8_t uniData[514];
uint16_t uniSize;
uint8_t hData[ARTNET_HEADER + 1];
uint8_t net = 0;
uint8_t universe = 0;
uint8_t subnet = 0;

const char* ssid     = "leo-link";
const char* password = "supergeheim";

IPAddress local_ip(10, 0, 0, 22);
IPAddress gateway_ip(10, 0, 0, 1);
IPAddress subnet_ip(255, 0, 0, 0);

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  WiFi.config(local_ip, gateway_ip, subnet_ip);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  udp.begin(ARTNET_PORT); // Open ArtNet port

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(WSout, OUTPUT);
}



void ICACHE_FLASH_ATTR sendWS() {
  uint32_t writeBits;
  uint8_t  bitMask, time;
  os_intr_lock();
  for (uint16_t t = 0; t < uniSize; t++) { // outer loop counting bytes
    bitMask = 0x80;
    while (bitMask) {
      // time=0ns : start by setting bit on
      time = 4;
      while (time--) {
        WRITE_PERI_REG( 0x60000304, WSbit );  // do ON bits // T=0
      }
      if ( uniData[t] & bitMask ) {
        writeBits = 0;  // if this is a '1' keep the on time on for longer, so dont write an off bit
      }
      else {
        writeBits = WSbit;  // else it must be a zero, so write the off bit !
      }
      time = 4;
      while (time--) {
        WRITE_PERI_REG( 0x60000308, writeBits );  // do OFF bits // T='0' time 350ns
      }
      time = 6;
      while (time--) {
        WRITE_PERI_REG( 0x60000308, WSbit );  // switch all bits off  T='1' time 700ns
      }
      // end of bite write time=1250ns
      bitMask >>= 1;
    }
  }
  os_intr_unlock();
}

void loop() {
  if (udp.parsePacket()) {
    udp.read(hData, ARTNET_HEADER + 1);
    if ( hData[0] == 'A' && hData[1] == 'r' && hData[2] == 't' && hData[3] == '-' && hData[4] == 'N' && hData[5] == 'e' && hData[6] == 't') {
      if ( hData[8] == 0x00 && hData[9] == ARTNET_DATA && hData[15] == net ) {
        if ( hData[14] == (subnet << 4) + universe ) { // UNIVERSE
          if (!uniSize) {
            uniSize = (hData[16] << 8) + (hData[17]);
          }
          udp.read(uniData, uniSize);
          //Serial.print("ArtNet packet RX Uni 0 - size:");
          //Serial.println(uniSize);
          sendWS();
        }
      } // if Artnet Data
    }
  }
}


I am pretty new to artner/dmx and I am no arduino expert. I say this because I really appreciate your answer, but I dont really understand it, or know how to proceed. If you have the will and time to guide me, I would really appreciate it.

camilozk

I did some modifications on the code posted above, based on your comentaries on #20. The resulting code is as follows:

Code: [Select]
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

#define WSout 5  // Pin D1
#define WSbit (1<<WSout)

// ARTNET CODES
#define ARTNET_DATA 0x50
#define ARTNET_POLL 0x20
#define ARTNET_POLL_REPLY 0x21
#define ARTNET_PORT 6454
#define ARTNET_HEADER 17

WiFiUDP udp;

uint8_t uniData[514];
uint16_t uniSize;
uint8_t hData[ARTNET_HEADER + 1];
uint8_t net = 0;
uint8_t universe = 0;
uint8_t subnet = 0;

const char* ssid     = "leo-link";
const char* password = "supergeheim";

IPAddress local_ip(10, 0, 0, 22);
IPAddress gateway_ip(10, 0, 0, 1);
IPAddress subnet_ip(255, 0, 0, 0);

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  WiFi.config(local_ip, gateway_ip, subnet_ip);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  udp.begin(ARTNET_PORT); // Open ArtNet port

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(WSout, OUTPUT);
}


void sendWS() {
  uint32_t writeBits;
  uint8_t  bitMask, time;
  os_intr_lock();
  for (uint16_t t = 0; t < uniSize; t++) { // outer loop counting bytes
    bitMask = 0x80;
    while (bitMask) {
      // time=0ns : start by setting bit on
      time = 6;
      while (time--) {
        WRITE_PERI_REG( 0x60000304, WSbit );  // do ON bits // T=0
      }
      if ( uniData[t] & bitMask ) {
        writeBits = 0;  // if this is a '1' keep the on time on for longer, so dont write an off bit
      }
      else {
        writeBits = WSbit;  // else it must be a zero, so write the off bit !
      }
      time = 6;
      while (time--) {
        WRITE_PERI_REG( 0x60000308, writeBits );  // do OFF bits // T='0' time 350ns
      }
      time = 6;
      while (time--) {
        WRITE_PERI_REG( 0x60000308, WSbit );  // switch all bits off  T='1' time 700ns
      }
      // end of bite write time=1250ns
      bitMask >>= 1;
    }
  }
  os_intr_unlock();
}


void loop() {
  if (udp.parsePacket()) {
    udp.read(hData, ARTNET_HEADER + 1);
    if ( hData[0] == 'A' && hData[1] == 'r' && hData[2] == 't' && hData[3] == '-' && hData[4] == 'N' && hData[5] == 'e' && hData[6] == 't') {
      if ( hData[8] == 0x00 && hData[9] == ARTNET_DATA && hData[15] == net ) {
        if ( hData[14] == (subnet << 4) + universe ) { // UNIVERSE
          if (!uniSize) {
            uniSize = (hData[16] << 8) + (hData[17]);
          }
          udp.read(uniData, uniSize);
          //Serial.print("ArtNet packet RX Uni 0 - size:");
          //Serial.println(uniSize);
          sendWS();
        }
      } // if Artnet Data
    }
  }
}


It compiles but I didnt see it working because my set up is currently in my atelier and I am home now.

-I removed ICACHE_FLASH_ATTR from sendWS()
-I adjusted the time= values within sendWS() to 6 in all cases
-I replaced
Code: [Select]
uniSize = (hData[16] << 8) + (hData[17]);
 with
Code: [Select]
if (!uniSize) {
  uniSize = (hData[16] << 8) + (hData[17]);}


About uint8_t uniData[512]; I wanted to ask you about the value 512, because in the first code you posted the value was 514. so 512 or 514?


And regarding having more than one universe, I have been checking out the whole thread for clues to be able to adapt the code, but I am really unable to understand it, so I am blind here. Let me know if you would be able to guide me on this.

thanks!

Go Up