Open mctrp opened 5 years ago
Unrelated to your specific problem, but if you can separate the first LED, you don’t need a level shifter, you can fudge things as shown in this hackaday: https://hackaday.com/2017/01/20/cheating-at-5v-ws2812-control-to-use-a-3-3v-data-line/
From: Marcel notifications@github.com Sent: Monday, December 24, 2018 8:28 AM To: adafruit/Adafruit_NeoPixel Adafruit_NeoPixel@noreply.github.com Cc: Subscribed subscribed@noreply.github.com Subject: [adafruit/Adafruit_NeoPixel] Neopixel Library is not processing the NEO_KHZ400 option for ESP8266 (Wemos D1 mini) (#186)
Hi,
For the holidays I was working on a WS2811 LED strip (5 meter, 3 LEDs per WS2811 chip) together with a Wemos D1 mini (ESP8266) as a controller.
The Neopixel library offers the NEO_KHZ400 option to drive WS2811 type strips, since these don't use a 800 KHz pulse freq like the WS2812x do.
For some reason however the NEO_KHZ400 option is ignored when I use a board based on the ESP8266 mcu. I've tried to run a simple script (just turn on 1 led based on serial input) with an Arduino UNO and the LED strip performs as expected. Using the same exact code on the Wemos got no response. (I'm aware the Wemos has a 3.3v output voltage so I used a logic level converter to turn it into 5v)
Minimal test script:
// Based on NeoPixel Ring simple sketch (c) 2013 Shae Erisson
// released under the GPLv3 license to match the rest of the AdaFruit NeoPixel library
//#define PIN 5 //For the Arduino UNO
// How many NeoPixels are attached to the Arduino?
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
// example for more information on possible values.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ400);
void setup() {
pinMode(PIN, OUTPUT);
Serial.begin(115200);
pixels.begin(); // This initializes the NeoPixel library.
pixels.setPixelColor(0, pixels.Color(0,0,0));
pixels.show();
}
void loop() {
// Tigger on serial input to synchronize UNO and Wemos sending the same Neopixel command.
if (Serial.available() > 0) {
Serial.println(1, BIN);
pixels.setPixelColor(0, pixels.Color(brightness,brightness,brightness));
pixels.show();
Serial.read(); // Read value to reset Serial.available
delay(1000); // Debounce delay
}
}
I started debugging and after (quite) some time found the following difference in signal output:
[normal_400khz]https://user-images.githubusercontent.com/19150076/50399955-68b03780-0783-11e9-99f8-75f0f6a65762.PNG
After zooming in a little bit you can clearly see a difference in the length of 1 bit between the UNO and the Wemos:
Arduino UNO: [normal_400khz_closeup_uno]https://user-images.githubusercontent.com/19150076/50399977-82ea1580-0783-11e9-898d-bb59e211fc54.PNG
Wemos: [normal_400khz_closeup_wemos]https://user-images.githubusercontent.com/19150076/50399981-8b425080-0783-11e9-8a62-bb644e4f4ca9.PNG
The UNO uses the expected frequency of 400KHz but the Wemos is using the 800KHz frequency.
After some digging around I found the following section in esp8266.c that is related to the timing of these signals. It should change the frequencies based on a boolean named "is800KHz".
uint8_t p, end, pix, mask;
uint32_t t, time0, time1, period, c, startTime, pinMask;
pinMask = _BV(pin);
p = pixels;
end = p + numBytes;
pix = *p++;
mask = 0x80;
startTime = 0;
if(is800KHz) {
time0 = CYCLES_800_T0H;
time1 = CYCLES_800_T1H;
period = CYCLES_800;
} else { // 400 KHz bitstream
time0 = CYCLES_400_T0H;
time1 = CYCLES_400_T1H;
period = CYCLES_400;
}
However it does not. If I force the use of the 400KHz timing scheme by changing the 800KHz to match the 400KHz ones like this:
It does work and I get the following output on my logic analyser:
Overview: [forced_400khz]https://user-images.githubusercontent.com/19150076/50399994-ab720f80-0783-11e9-8989-7217ffbd60e9.PNG
Arduio UNO: [forced_400khz_closeup_uno]https://user-images.githubusercontent.com/19150076/50399997-af059680-0783-11e9-830b-89ab9405bd2e.PNG
Wemos: [forced_400khz_closeup_wemos]https://user-images.githubusercontent.com/19150076/50399999-b167f080-0783-11e9-955e-bbe70a79d64c.PNG
Now the signals seem to match in terms of frequency. Both on 400KHz.
I have the feeling it has to do with this "is800KHz" boolean that is not being set correctly somewhere. But I cannot seem to find if the problem lies in the esp8266.c itself or in Adafruit_NeoPixel.cpp that calls it.
Does anyone know where to look for the cause? Or am I missing something?
Arduino board: Wemos D1 Mini (ESP8266), Arduino UNO (genuine) Arduino IDE version: 1.8.5 Neopixel library version: 2.4.2
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/adafruit/Adafruit_NeoPixel/issues/186, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AFI2Vf3gsBuoSuixERcHru2hytiQNra3ks5u8NZWgaJpZM4Zgcuz.
yeah we dont really support 400khz - if you can submit a PR we'll take a look but like, we dont even know where to get 400khz neopixels anymore :D
I don't see anything seriously out of whack. Additionally, I don't have any 400 KHz pixels handy to test with, so I'm flying on instruments here...but...
I notice the function declaration for espShow() in Adafruit_NeoPixel.cpp (line 115) doesn't exactly match what's in esp8266.c (line 20). Last argument is uint8_t in former, boolean in latter. IN PRINCIPLE they should compile to the same thing, but maybe the ESP8266 is a strange case.
Try changing the code so it's the same in both places...either both uint8_t, or both boolean...see if the behavior is any different.
Thank you for your responses! I seem to have found the last one in existence apparently :P
With your feedback I think I have found the culprit:
If I change this part of esp8266.c
#ifdef NEO_KHZ400
if(is800KHz) {
#endif
time0 = CYCLES_800_T0H;
time1 = CYCLES_800_T1H;
period = CYCLES_800;
#ifdef NEO_KHZ400
} else { // 400 KHz bitstream
time0 = CYCLES_400_T0H;
time1 = CYCLES_400_T1H;
period = CYCLES_400;
}
#endif
to
if(is800KHz) {
time0 = CYCLES_800_T0H;
time1 = CYCLES_800_T1H;
period = CYCLES_800;
} else { // 400 KHz bitstream
time0 = CYCLES_400_T0H;
time1 = CYCLES_400_T1H;
period = CYCLES_400;
}
The signal is correct. So it seems that the definition of NEO_KHZ400 does not carry over to the secondary c file. Is there a more elegant way of solving this? Otherwise I will submit a PR for the code change described above.
Oh snap! Good eye.
NEO_KHZ400 is ONLY not-defined on ATtiny devices. It's present on everything else, so I'm OK with the change as shown...feel free to PR, or I can make the change next time I'm in there.
Thanks for spotting it!
I'd like to get this change implemented. Should I reference this thread in the PR?
I just ran in to this today. I was working on an ATTiny85 and I grabbed a strip of neoPixels I had laying around. After some odd behavior of the LEDs (when plugged in to the ATTiny85 they flicker uncontrollably) I was able to identify a marking on the strip that said 2811, so I changed the setting to NEO_KHZ400 and received the compilation error. 'NEO_KHZ400' was not declared in this scope.
Seems like a trivial thing to fix, but also a very rare occurrence of anyone using these two combinations.
I also just ran into this issue today on an attiny85 and an older pololu addressable led.
Hi,
For the holidays I was working on a WS2811 LED strip (5 meter, 3 LEDs per WS2811 chip) together with a Wemos D1 mini (ESP8266) as a controller.
The Neopixel library offers the NEO_KHZ400 option to drive WS2811 type strips, since these don't use a 800 KHz pulse freq like the WS2812x do.
For some reason however the NEO_KHZ400 option is ignored when I use a board based on the ESP8266 mcu. I've tried to run a simple script (just turn on 1 led based on serial input) with an Arduino UNO and the LED strip performs as expected. Using the same exact code on the Wemos got no response. (I'm aware the Wemos has a 3.3v output voltage so I used a logic level converter to turn it into 5v)
Minimal test script:
I started debugging and after (quite) some time found the following difference in signal output:
After zooming in a little bit you can clearly see a difference in the length of 1 bit between the UNO and the Wemos:
Arduino UNO:
Wemos:
The UNO uses the expected frequency of 400KHz but the Wemos is using the 800KHz frequency.
After some digging around I found the following section in esp8266.c that is related to the timing of these signals. It should change the frequencies based on a boolean named "is800KHz".
However it does not. If I force the use of the 400KHz timing scheme by changing the 800KHz to match the 400KHz ones like this:
It does work and I get the following output on my logic analyser:
Overview:
Arduio UNO:
Wemos:
Now the signals seem to match in terms of frequency. Both on 400KHz.
I have the feeling it has to do with this "is800KHz" boolean that is not being set correctly somewhere. But I cannot seem to find if the problem lies in the esp8266.c itself or in Adafruit_NeoPixel.cpp that calls it.
Does anyone know where to look for the cause? Or am I missing something?
Arduino board: Wemos D1 Mini (ESP8266), Arduino UNO (genuine) Arduino IDE version: 1.8.5 Neopixel library version: 2.4.2