Driving WS2811, WS2812 and other NeoPixel devices from ESP8266

Posted on
of 4
  • Yes, I'd just add what you have for now, a utility function. I replied to you earlier on this thread as well with some ideas.

    I actually added something useful to the AES branch called JSV_GET_AS_CHAR_ARRAY - it returns a char*, either by referencing a flat array (if possible) or by allocating on the stack and copying across.

    I'll merge in today, but that should really help to simplify your code.

  • Hi,

    Is this currently working? I'm trying to drive a single WS2811s (in particular this circuit: https://hackaday.io/project/4603-pixiflo­od).

    I've tried using the hardware SPI implementation on the ESP8266 too but I've had no joy with that either. The LED works fine on my Espruino Pico using hardware SPI so I know that's fine.

    My environment is:
    Espruino v81.780
    12V circuit running the LED, 3.3V in the NodeMCU, common ground

    Here's the code I've been using:

    var esp = require("ESP8266");
    var pin = new Pin(15);        // I've tried all available GPIOs
    esp.neopixelWrite(pin, [50, 50, 50]);

    Any help would be really appreciated as I'd like to use this for a demo of some of my research on Wednesday.


  • Try the following:

    var esp = require("ESP8266");
    var pin = new Pin(15);        // I've tried all available GPIOs
    pinMode(pin, "output");
    esp.neopixelWrite(pin, [50, 50, 50]);

    It may be that setting the pinMode explicitly to output is required.

  • Unfortunately that hasn't helped. I managed to get SPI1 working occasionally but only by putting a number as padding at the start of the array, but that still only seems to work some of the time.

    var r = 25;
    var g = 25;
    var b = 25;
    SPI1.send4bit([10, r, g, b], 0b0001, 0b0011);

    Edit: with more testing it seems almost random what colour comes out compared to the array that gets sent.

    Edit 2: The hardware SPI seems to give a different output even if I send the same command several times, it looks like a timing problem to me, but that's a guess from playing around with the baud rate. It looks like software SPI is the only option for me at the moment.

    Edit 3: This works, but don't ask me why. The timeout and the leading 0 in the array are essential for it to reliably output the correct colour.

      SPI1.send4bit([0,10,10,10], 0b0001, 0b0011);
  • By any chance do you have any raw NeoPixels to test with? I'm wondering if that circuit is giving us some problems?

  • Hi,

    I was surprised to see that the SPI approach actually worked for you, so I tried it too. The timing diagram with a logic analyzer shows, that it is barely working. The gap between the individual 4 bits is about 5,5 µs, which is on the margin of latching the sent data into the LEDs. The gap after the first byte is about 11 µs which explains the first dummy byte you had to send.

    In your code you specify mosi:D15 which is of no use and a bit misleading, as MOSI in the ESP8255 is hardwired to pin GPIO13. But as already said it is not evaluated anyways.

    Further, I saw no difference in the timings whether using the setTimeout call or not. Both produce the same output for me.

    Finally, I verified that esp.neopixelWrite() still works fine.

  • When using SPI send, you can probably get more performance by putting the data into a Uint8Array first.

    ... did you check the signal with an oscilloscope? Your problem could be electrical - WS2811s don't like running off 5v while being driven off a 3.3v signal. It works on Espruino boards because the 5v line comes off USB via a diode, so is actually nearer 4.5v.

    In the docs on the site it's suggested that you put the pin into open drain mode and then pull it up to 5v with a resistor, but I'm not sure if the ESP8266 is 5v tolerant?

  • @Kolban, I don't have any real NeoPixels here unfortunately. The circuit could well be the problem.

    @MarkusGritsch, I've taken out the D15 reference for anyone that looks at it later. The timing is definitely flakey and sometimes it doesn't quite work out, but what I'm doing isn't mission critical so I don't care too much if it sometimes goes wrong. I have no idea why I needed the setTimeout(), but it was a lot more flakey without it.

    @Gordon, it seems slightly contentious as to whether the ESP8266 is 5V tolerant, but I've not had any problems using a 5V signal yet. I have some logic level shifters I'll try out too. I can borrow a scope but it's going to be a few days before I have the time to do much with it.

    I'll report back what I find and hopefully somewhere in there will be something useful.

  • More results.

    I tried using the opendrain mode with a resistor pulling up to 5V but it stopped any visible output. I also tried a logic level converter but that made it less reliable.

    It seems the ESP8266 is pretty tolerant to 5V after all.

    Completely inexplicably the esp.neopixelWrite() started working for me! I wish I knew why but I can only assume something improved when I was swapping cables around. I think I'm going to use this and leave the hardware SPI to those of you that know more what you're doing, at least for now.

    Thanks for all the help :)

    Summary for anyone that comes in to this thread later:
    Software SPI works, but might take a few attempts to figure out.
    Hardware SPI is well on the way and works on and off, but isn't quite there yet.

  • I tried the code from the official Espruino WS2812 example: http://www.espruino.com/WS2811 replacing the calls to SPI by esp.neopixelWrite(), but I get the error

    >esp.neopixelWrite(pin, arr);
    Uncaught Error: Data must be an array.
     at line 1 col 27
    esp.neopixelWrite(pin, arr);

    It would be nice if neopixelWrite would also take an Uint8ClampedArray or Uint8Array.

  • I further tried the example as is (just replaced SPI2 by SPI1), and it roughly works (neglecting the first-byte delay problem), but it runs VERY slow: The LEDs are updated only every 120 ms.

    Calling require("ESP8266").logDebug(false); improved it a bit but still 108 ms. Is it really supposed to run that slow?

  • I don't think this is a good solution for Espruino, but this I2S DMA WS2812 driver is really neat: https://github.com/cnlohr/esp8266ws2812i­2s

  • Tip: My ESP-7 defaults to 160MHz when newly flashed - which runs neopixelWrite(..) at twice speed

    var esp8266 = require("ESP8266");

    fixed it..

  • Yeah, current builds default to 160mhz, which offers significantly better performance. It looks like the neopixel code needs to be updated to work at 160.

  • Ugh, I did forget to update the neopixel code! Apologies. I knew I was forgetting something but couldn't put my finger on it. Please run at 80Mhz in the meantime.

  • I've got a ton of different neopixels from Adafruit for testing (including the new GRBW variants). I can get them to work on my ESP8266 as long as I knock the CPU freq down to 80Mhz. As I helped with neopixel support on nodemcu and am adding support on my own platform for esp8266, I can help with updating the code here if someone would direct me to the right place.

    Also a suggestion. I bought one real espruino board (the pico) and using the SPI method I can mix GRB neopixels and GRBW neopixels just fine on the same pin. I just need need proper byte offsets in my logic. But using the esp.neopixelWrite command, I'm restricted to multiples of 3 bytes which is wrong once the 4-bytes-per-pixel GRBW hardware is introduced. We should remove that constraint.

  • Also I just noticed that the save() command doesn't preserve the CPU speed. As a workaround, I added an onInit function to set it on 80Mhz before saving my state.

  • don't miss this nice and cheap ones

  • One more option (even cheaper and delivery from GreatBritain) could be this:
    I have 2 of them, they work fine.

  • I definitely have to check more sides in the UK - thanks !

  • Why are we discussing neopixel hardware here?

    Shouldn't we be more concerned with the bugs reported by @creationix ? What version of the Espruino-for-ESP8266 firmware are you using? As noted above, this problem was known - but I thought it was fixed!

  • @creationix which firmware version are you using? espruino_1v84.tve_master_f35ac96_esp8266­.tgz is supposed to work with both cpu freq's. I tested both, but of course I may not have been thorough enough or not all neopixels are created equal...

  • @tve for the saving, I guess it's not such a big deal - but in jsiDumpState (iirc?) it can create an init string that is executed before onInit - it's also used when reconstructing using dump(). I guess we could add something to jshardware.h that appended custom initialisation strings on to that init string, so stuff like the clock speed could be saved in a nice simple way.

  • yup, that makes sense. it's also not that difficult to set the clock freq in the onInit()...

  • I'm trying again today. I've got what I think is the latest firmware (espruino_1v85.tve_master_66fde09_esp826­6) flashed onto my brand new Wio Link (esp-12-ish). The repl works great over serial (much nicer than nodemcu's raw repl).

    The wio link deluxe kit comes with a neopixel strip. It works great using their provided software (HTTP based interface), now I'm trying the same hardware using espruino.

    No matter what I do, the pixels don't light up.

    esp = require('ESP8266');
    pinMode(D14, 'output');
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

Driving WS2811, WS2812 and other NeoPixel devices from ESP8266

Posted by Avatar for Kolban @Kolban