-
• #27
ok. Nevertheless with SPI you can only have one pin driving a LED strip, whereas the dedicated code can use any pin.
-
• #28
yup, but the dedicated code would not leave time to drive any other pin, so why have other pins? ;-)
-
• #29
I didn't mean that the dedicated code handles multiple strips at the same time. You can send data to one strip and then send data to another strip. Since this is quite fast, you won't notice the delay.
-
• #30
I'm wondering whether it wouldn't be more effective to use the uart to drive the LEDs due to the fact that there's a 128 character buffer. I suspect that one could encode 3 bits per character, that one buffer-full would drive 10 LEDs...
-
• #31
But the start and stopbits... don't they interfere with the desired bit stream? Also, the idle state for a NeoPixel data line is a low voltage, while the idle state for a serial line is a high voltage.
With major trickery it seems to be doable (see e.g. http://wp.josh.com/2014/09/03/inside-neouart-tricking-a-serial-port-into-being-a-signal-generator/), but it's probably not the way to go.
-
• #32
That's an interesting thought - I think you might have to negate the output because the idle state is high rather than low, but potentially you could use the UART - you'd just use the start bit as part of one of the pulses. You'd have to be able to run the UART pretty quick though...
Has HWSPI been tested for Neopixels? It looks to me from the code like it's unlikely to be fast enough. IMO the library really needs pulling apart in order to be able to send individual bytes with jshSPISend without having to poke a whole bunch of registers first.
I think realistically adding a software library specifically for neopixels is probably the best way to go for now :(
-
• #33
I just did some testing (see https://github.com/espruino/Espruino/issues/606#issuecomment-153983011), and currently it seems not to be possible to drive WS2812 LEDs.
-
• #34
Another possible line of thought is starting to be captured by this issue:
-
• #35
But the start and stopbits... don't they interfere with the desired bit stream? Also, the idle state for a NeoPixel data line is a low voltage, while the idle state for a serial line is a high voltage.
The UART output can be inverted and you just factor the start and stop bits into the "calculation" for the waveform.
-
• #36
If we want to go the custom code route maybe we could add a digitalVector that is similar to the digitalPulse, something like:
digitalVector(pin, duration, vector)
whereduration
is the duration of a bit on the gpiopin
and vector is an unsigned byte array that gets shifted out on the pin (need to agree which bit of every byte gets shifted out first). This could be done using DMA on processors that support it. -
• #37
An experimental build is now up at:
https://github.com/espruino/EspruinoBuilds/tree/master/ESP8266
This has the following extra function:
var esp = require("ESP8266"); var pin = new Pin(1); esp.neopixelWrite(pin, [255, 255, 255, 0, 0, 0, 128,128,128]);
The array can be as long as you like but must be multiple of 3 in size. The pin is the Pin id of the pin you are using for the data line. The timing is hard-coded for the neopixel speeds.
@tve ... I like the idea but am not yet seeing how it would work for NeoPixels which appear to be our focus de-jure. At the NeoPixel level we want a pixel to be 3 bytes/pixel ... with 8 bits for red, 8 bits for green and 8 bits for blue. Not yet sure how we would turn that into a digital vector ....
-
• #38
I guess
digitalPulse
could be tweaked so that it scanned over the pulses it was asked to make, and if any were in the microsecond region it just did them by checking the SysTick timer. Seems like quite a bit of effort though.neopixelWrite
sounds like a good solution really, and then on the WS2811 page we'll mention there's a specific function for ESP8266 (and on the neopixelWrite's docs it can link back to the WS2811 page for how to do it on other platforms).Potentially we could do a simple module that looked like:
exports.connect = function(pin) { if (process.env.BOARD.substr(0,7)=="ESP8266") return require("ESP8266").neopixelWrite.bind(null,pin); // otherwise use SPI var spi = SPI.find(pin); // can't quite remember if (!spi) throw "No SPI MOSI on this pin"; spi.setup({mosi:pin,baud:3200000); return function(data) { spi.send4bit(data, 0b0001, 0b0011); }; }
It's a small waste of memory, but it might make life easier.
-
• #39
I think I had to call
pinMode(pin, 'output')
additionally, before neopixelWrite() did anything. (I am using GPIO2 on an ESP-01 board.)
As for the test:
- Before the pulses start, there is a 100 µs high pulse followed by a 100 µs low pause, which should not be there.
- The data bit pulses are a bit long, especially those for 0. I measured 550 ns, which gets recognized by standard WS2812 LEDs as a 1, so I always get three white LEDs, as every pulse is interpreted as 1.
I have repeatedly pointed to this really excellent article which describes the needed timing: http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
Or, maybe just use the timings from the manuka/adafruit code, where you have taken the rest of the code from. I am going to add two screenshots...
- Before the pulses start, there is a 100 µs high pulse followed by a 100 µs low pause, which should not be there.
-
• #40
ad 1.
1 Attachment
-
• #41
ad 2.
1 Attachment
-
• #42
First I had the same problem with all three being white.
But now it works as expected, no idea why.
Only change I did was to add esp.debugLog(true).
From that moment on, it worked, even after setting esp.debugLog(false).var esp = require("ESP8266"); esp.logDebug(false); var p = new Pin(D4); pinMode(p, 'output'); esp.neopixelWrite(p, [0, 255, 255, 0, 0, 255, 0,255,0,255,0,0,128,128,0,255,255,0]);
-
• #43
Oh, everything back to ground ;-)
try this first : esp.neopixelWrite(p, [255,0,0,0,255,0,0,0,255]); //gives green, white, white
and next this: esp.neopixelWrite(p, [255,0,0,0,255,0,1,0,255]); // gives green, red, blue -
• #44
Thanks for the feedback ... the two 100us long pulses at the start are debug that I put in ... I'll remove them for sure. I have also been testing with PL9823s as opposed to WS2811s or WS2812s. I'll next dig out some WS2812s ... and see if those start to fail. I'm kicking myself for not having tested with those in the first place.
@MarkusGritsch ... everywhere I surf on the Internet I find your name related to these NeoPixel devices. You are certainly the most knowledgeable in that area. Folks like myself are acolytes in your footsteps here. I'll study the article you pointed at in great depth and see if I can't get the timings more accurate. If the WS2812 area for Espruino is something you yourself have particular interest in, I'll be delighted to work with you if you would be interested in getting a build environment for Espruino running at your work area. If not, your comments and timing results are EXTREMELY helpful ... thank you sir.
-
• #45
I tested with real WS2812s and exactly as you stated, the results were horrible. I examined my own timings and got exactly what y'all measured. The timing diagram for the PL9823s that I was using gives T0H as 0.35us and T1H as 1.36us ... while for real WS2812s ... T0H as 0.35us and T1H as 0.7us.
In the actual timings now ... I have T0H as ~0.4us and T1H as ~0.95us. My tests are showing no errors.
I have uploaded a new firmware ... can I ask y'all to try this build and see if we are getting closer?
-
• #46
Did a quick test. Seems to work fine :) The article I mentioned suggests 350 ns and 700 ns as the typical timings though.
-
• #47
May be, this is of help to define timing for several LED-strings.
Could it be used for something like "neopixel.init(...)" ?
https://github.com/FastLED/FastLED/blob/master/chipsets.h -
• #48
@JumJum ... well ... that idea of yours makes perfect sense. Instead of "neopixelWrite" being a static function, maybe we create a class called "NeoPixel" with methods on it like "write" to write a stream of data and "init" to identify the data pin as well as set the T0H, T1H, T0L and T0H values. Then, in principle, any and all devices would work and all we would have to do is publish the working values.
However ... at this point, given that the current neopixelWrite() method seems to be working for the majority of us ... I'm tempted to flag that as "future" and attack some of the higher priority items in Espruino land.
As it is, I'm not sure we ever reached consensus on whether or not to include NeoPixel support in native Espruino (ESP8266 specific or otherwise).
I'm assuming that you yourself are able to drive NeoPixels?
-
• #49
As it is, I'm not sure we ever reached consensus on whether or not to include NeoPixel support in native Espruino (ESP8266 specific or otherwise).
I think in comment #32 (http://forum.espruino.com/comments/12608810/) Gordon already gave his blessing:
"I think realistically adding a software library specifically for neopixels is probably the best way to go for now :(" -
• #50
Family part of weekend is gone, and I have some time again to play with my ESP8266 ;-)
@Kolban WS2812 is running now, there is only one problem, typed array (Uint8Array, Uint8ClampedArray etc) are not supported. This would be very helpful to save some memory.
To answer your question, I can run NeoPixel based on support in Espruino only. May be I misunderstood your question ?
@MarkusGritsch, @Kolban, on long term I would like to have an interface to upload binarys(compiled code) in addition to existing firmware, something like a plugin handling. This would end discussion of "does this belong to Espruino".
the 4 pins don't have to be wasted. the SPI could be taught to only switch 1 pin to SPI mode, or you could switch them back yourself to gpio after initializing the spi interface.