These are chat archives for Makuna/NeoPixelBus

19th
Aug 2018
Michael Miller
@Makuna
Aug 19 2018 16:08
@xonotron
Michael Miller
@Makuna
Aug 19 2018 16:14
@xonotron The first issues with your sketch is that you are not using safe practice with the timing.
if(millis()>interruptTime+200) {
you should always test deltas with unsinged, otherwise the math can fail, so this should become
if ((millis()-interruptTime) > 200)
I believe you did something similar in several areas.
Also, one of your variables used for timing is not unsigned long; int and long are not guaranteed to be the same number of bits; and since millis() returns unsinged long, you should stick with it.
Michael Miller
@Makuna
Aug 19 2018 16:30
@xonotron Bitbang is synchronous, so it wont return until it has sent all the data. i2s is async, so it returns almost immediately. This becomes an issue with the pixel hardware is using a slightly different protocol where it requires a longer "reset" time. Try the NeoWs2813Method and see if the issue gets resolved (of course, after you fix your timing stuff mentioned above).
Xonotron
@Xonotron
Aug 19 2018 17:43
Sorry for spamming issue 152, I'm new to Github. Thanks for the advice, I haven't been aware not using deltas could lead to a problem. Now when I think about it this makes sense. I edited my code accordingly, thank you. I also tried the NeoEsp32I2s1Ws2813Method but the problem remains. It seems as if some of the strip.Show() are being ignored if I don't call strip.Begin() before each time.
Michael Miller
@Makuna
Aug 19 2018 17:49
Try adding a delay(10) after the strip.Show().
What Esp32 are you using?
What version of the Esp32 Arduino board support are you using?
See the Wiki FAQs; the kinds of issues you are seeing are common with 3.3v Arduinos, and while it seems counter intuitive, often the bitbang will not exhibit the same issues. While most of the new NeoPixels haven't required a level shifter, just two years ago most of them did; and again, due to how "lazy" the signal was generated from bitbang it often just works.
Xonotron
@Xonotron
Aug 19 2018 18:07

I already tried adding a delay and just did it again to be sure, it doesn't help.

I board I use has the ESP-WROOM-32, it's called Geekcreit, ESP Devkit V1, www.doit.am. I bought it on Banggood
I use the latest espressif/arduino-esp32 1.0

I also just had a glance with my oscilloscope at it. If it skips a button press or gets stuck at yellow (the sketch sets the led back to yellow after 100ms) there's really missing the signal at pin 4. So it must be software related, right?

Michael Miller
@Makuna
Aug 19 2018 18:13
could you post your updated code here. Start with a line with single start quote, and ends with a line with a single start quote (to it marks it as code)
Also, increase the number of pixels to 10 (just the count passed to NeoPixelBus and leave everything else the same).
Xonotron
@Xonotron
Aug 19 2018 18:19
Increasing the pixel count to 10 also has no effect.
#include <NeoPixelBus.h>

NeoPixelBus<NeoGrbFeature, NeoEsp32I2s1Ws2813Method> strip(10, 4);

int brightness=32;
RgbColor yellow(brightness, brightness/4*3, 0);
RgbColor blue(0, 0, brightness);

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
unsigned long interruptTime=millis();
bool blinkNow=false;
unsigned long resetTimer=millis();
bool resetLed=false;


void IRAM_ATTR handleInterrupt() {
  portENTER_CRITICAL_ISR(&mux);
  if((millis()-interruptTime) > 200) {
    interruptTime=millis();
    blinkNow=true;
  }
  portEXIT_CRITICAL_ISR(&mux);
}

void setup() {
  pinMode(12, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(12), handleInterrupt, FALLING);

  strip.Begin();
  strip.Show();
}

void loop() {
  if(blinkNow) {
    portENTER_CRITICAL(&mux);
    blinkNow=false;
    portEXIT_CRITICAL(&mux);

    resetLed=true;
    resetTimer=millis();
    //strip.Begin();
    strip.SetPixelColor(0, yellow);
    strip.Show();
    delay(10);
  }
  if(resetLed) {
    if ((millis()-resetTimer) > 100) {
      //strip.Begin();
      strip.SetPixelColor(0, blue);
      strip.Show();
      delay(10);
      resetLed=false;
    }
  }
}
Michael Miller
@Makuna
Aug 19 2018 18:19
ALSO, what is the interrupt pin that triggers all this tied to? A Button? If so, you are not doing any sort of de-bounce, so you can get that interrupt trigger a lot when you press or release the button. There are hardware solutions for de-bounce, and software
p.s. blinkNow should be marked as volatile (as it is modified in an ISR and used outside the ISR)
Xonotron
@Xonotron
Aug 19 2018 18:23

There's a simple software debounce that ignores all interrupts within a window of 200ms after a button press.

It's the same when triggering it via software.

Michael Miller
@Makuna
Aug 19 2018 18:23
This code is acting like a debouce,
if((millis()-interruptTime) > 200) {
Michael Miller
@Makuna
Aug 19 2018 18:31
So what you are seeing is that sometimes when you press the button, the color never shows yellow?
Xonotron
@Xonotron
Aug 19 2018 18:34

Yes this and sometimes the led stays yellow.

To rule out any bouncing effects a programmed another ESP32 to set the input high/low every 500ms. Same thing.

Michael Miller
@Makuna
Aug 19 2018 18:35
some minor other timing things. Consider every loop as one discrete time, so capture the millis() at the top and use that value instead of calling millis() at arbitrary times in your code in the loop. This will decrease logic issues (although this isn't the problem I believe)
Does your scope have capture ability with an external trigger? If so, trigger off the button and capture for >600ms. If a problem happens, then we can examine the capture for problems.
Michael Miller
@Makuna
Aug 19 2018 18:41
Or a logic analyzer helps.
p.s. I will be putting your code into my test rig at some point today, I am cycling between gitter and other things at the moment ;-)
Xonotron
@Xonotron
Aug 19 2018 18:44

Thanks for all the advice! My coding appreciates it a lot :)
It's a Rigol DS1054Z and yes I think it has a trigger out. I'm not only new to github but also to my scope =D

I'll try to make that capture.

Xonotron
@Xonotron
Aug 19 2018 18:53
DS1Z_QuickPrint4.png
DS1Z_QuickPrint5.png
Michael Miller
@Makuna
Aug 19 2018 18:53
time to become intimate with your scope ;-)
Xonotron
@Xonotron
Aug 19 2018 18:54
First picture shows normal function. Second picture when nothing happens or the led stays yellow.
Michael Miller
@Makuna
Aug 19 2018 18:57
What channel is that blip on? The button? What channel do you have tied to the NeoPixelBus?
The scope need to be setup to capture the full time, you have it set to 400us, while that capture the details of the data out for the neopixels, you have timing delays to account for.
A single pixel data burst on the neopixel will be 24 pulses, of about 12.5us period and a pulse width of 0.3us to 0.9us.
Xonotron
@Xonotron
Aug 19 2018 19:00
It's more clear in this zoom mode:
DS1Z_QuickPrint6.png
The blip is channel one which is tied to pin 4 that goes to the led.
Channel 2 is tied to the button and triggers the scope.
The two blips are 100ms apart from each other, as expected by the code.
Michael Miller
@Makuna
Aug 19 2018 19:05
zoom into the second blip also.
Xonotron
@Xonotron
Aug 19 2018 19:08
DS1Z_QuickPrint7.png
But does that help? The problem is the missing blip if the error occurs.?
Michael Miller
@Makuna
Aug 19 2018 19:13
Yes, the first blip is a pulse train representing yellow (GRB, eight bits per channel, each blip is bit, narrow is zero, wide is one) and the second is blue. So the reset to blue is missing.
change this line
if(resetLed) {
to
else if(resetLed) {
Michael Miller
@Makuna
Aug 19 2018 19:22
Glanced at your circuit, are the grounds all connected together?
Xonotron
@Xonotron
Aug 19 2018 19:22

Yes and sometimes the yellow signal is missing.

else if(resetLed) {
doesn't do the trick

Yup, all grounds are connected.
Michael Miller
@Makuna
Aug 19 2018 19:23
And to be clear, by missing you mean, you captured it with scope, looked at the pulses, and confirmed that pulse train representing yellow was missing.
One last test before I go (I will put this on my bench latter today), instead of calling the neopixels, just toggle another pin (on, microdelay(100), off), connecting your scope to that pin and see if both pulses showup. This will confirm if its a NeoPixelBus issue versus some logic (although I can't see any logic myself).
delayMicroseconds()
Xonotron
@Xonotron
Aug 19 2018 19:30
Yes I can confirm that the pulse train is missing then. I just got one case where even both impluses were missing.
Xonotron
@Xonotron
Aug 19 2018 19:39

Good idea, I inserted (on, microdelay(100), off) for pin 2 which is the internal blue led of the board.
That way I can confirm that the logic is OK but nothing happens. The internal blue led blinks (very faintly) when the NeoPixel goes yellow and again when it returns to blue.

If there's pulse missing, the blue led (pin 2) does blink.

Code is now:

#include <NeoPixelBus.h>

NeoPixelBus<NeoGrbFeature, NeoEsp32I2s1Ws2813Method> strip(1, 4);

int brightness=32;
RgbColor yellow(brightness, brightness/4*3, 0);
RgbColor blue(0, 0, brightness);

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
unsigned long interruptTime=millis();
bool blinkNow=false;
unsigned long resetTimer=millis();
bool resetLed=false;


void IRAM_ATTR handleInterrupt() {
  portENTER_CRITICAL_ISR(&mux);
  unsigned long now=millis();
  if((now-interruptTime) > 200) {
    interruptTime=now;
    blinkNow=true;
  }
  portEXIT_CRITICAL_ISR(&mux);
}

void setup() {
  pinMode(12, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(12), handleInterrupt, FALLING);

  pinMode(2, OUTPUT);
  digitalWrite(2, LOW);

  strip.Begin();
  strip.Show();
}

void loop() {
  unsigned long now=millis();

  if(blinkNow) {
    portENTER_CRITICAL(&mux);
    blinkNow=false;
    portEXIT_CRITICAL(&mux);

    resetLed=true;
    resetTimer=now;
    //strip.Begin();
    strip.SetPixelColor(0, yellow);
    strip.Show();
    //delay(10);

    digitalWrite(2, HIGH);
    delayMicroseconds(100);
    digitalWrite(2, LOW);
  }
  else if(resetLed) {
    if ((now-resetTimer) > 500) {
      resetLed=false;

      //strip.Begin();
      strip.SetPixelColor(0, blue);
      strip.Show();
      //delay(10);

      digitalWrite(2, HIGH);
      delayMicroseconds(100);
      digitalWrite(2, LOW);
    }
  }
}
Michael Miller
@Makuna
Aug 19 2018 19:58
You could also set high when you set yellow, and set low when you set blue.
Did you spot any issues yet?
Oh, I forgot to ask, how often did it fail? One out three tries? One out 10 tries?
Xonotron
@Xonotron
Aug 19 2018 20:12

I just counted 7 errors in 50 attempts.

To make sure it's nothing fancy with the interrupt, I simplified it even more. The error remains the same.

#include <NeoPixelBus.h>

NeoPixelBus<NeoGrbFeature, NeoEsp32I2s1Ws2813Method> strip(1, 4);

int brightness=32;
RgbColor yellow(brightness, brightness/4*3, 0);
RgbColor blue(0, 0, brightness);

unsigned long resetTimer=millis();
bool resetLed=false;
bool blinkNow=false;

void setup() {
  pinMode(12, INPUT_PULLUP);

  pinMode(2, OUTPUT);
  digitalWrite(2, LOW);

  strip.Begin();
  strip.Show();
}

void loop() {
  unsigned long now=millis();

  if(digitalRead(12)==LOW && now-resetTimer>400) {
    resetTimer=now;
    blinkNow=true;
  }

  if(blinkNow) {
    blinkNow=false;
    resetLed=true;

    //strip.Begin();
    strip.SetPixelColor(0, yellow);
    strip.Show();

    digitalWrite(2, HIGH);
  }
  else if(resetLed && now-resetTimer>200) {
    resetLed=false;

    //strip.Begin();
    strip.SetPixelColor(0, blue);
    strip.Show();

    digitalWrite(2, LOW);
  }
}
Xonotron
@Xonotron
Aug 19 2018 20:18
Oh and still, as soon as I remove the // before the two strip.Begin(); it runs perfectly smooth.