3

Stumbled upon this weirdest behavior, from time to time, my Arduino (UNO) runs gode really slow.

Searching this issue didn't clarify anything, most people have problems with IDE itself. My issue is related to actual board.

Heres a sample of my flow:

  • I compile & upload my sketch, all good
  • first initiation of program on the board seems to be "fast"
  • when I start to "animate" the neopixels it goes 3-4 times slower than it should
  • I'll touch the board, and animation goes fast again.

Here's a clip of that, at the end you'll see the "slowness"

  • Test environment: enter image description here

  • Live environment: enter image description here

The Touching part, is almost like if I "add" static electricity from my finger to the board, it wakes up and behaves normally.

For you who are curious about (non related) what animation I'm doing on neopixels, I'm turning on 15 pixels from 0 to 54. Like a "slide effect". (I'm not using delay, only a delay(30) in the loop, rest of the delays are based on millis())

Is there any general info / explanation that would explain this behavior, like in electronics, arduino boards specifically ?

EDIT: I should also add, when printing logs into serial monitor, that slowness also affects the outputs... they appear as "slow" as the pixels flow. When all works normally, I see pixels change and logs 50 times per second (roughly), but in this slow motion, I see pixels change and logs around 20 times per second. Taking out the Serial entirely from the code doesn't seem to have effect.

Code:

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#define LEFT_BLINK_IN 2
#define RIGHT_BLINK_IN 3
#define PIN           6
#define NUMPIXELS     54
Adafruit_NeoPixel     leftLight = Adafruit_NeoPixel(NUMPIXELS, 6, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel     rightLight = Adafruit_NeoPixel(NUMPIXELS, 10, NEO_GRB + NEO_KHZ800);
int leftBlinkCount   = 0;
int rightBlinkCount  = 0;
int PIXELTOSHOW      = 20;
bool OEM_RIGHT_ON    = false;
bool OEM_LEFT_ON     = false;
int R_PIXEL          = -1;
int L_PIXEL          = -1;
int G_PIXEL          = -1;
int D_PIXEL          = -1;
char LAST_COMMAND;
bool DRL_ON         = false;
int DRL_STARTPIXEL  = 35;
uint32_t COLOR_YEL = rightLight.Color(240, 120, 0);
uint32_t COLOR_RED = rightLight.Color(255, 0, 0);
uint32_t COLOR_BLU = rightLight.Color(0, 0, 255);
uint32_t COLOR_NON = rightLight.Color(0, 0, 0);
uint32_t COLOR_WHI = rightLight.Color(255, 255, 255);

unsigned long rightPrevMillis = 0;
unsigned long leftPrevMillis = 0;
unsigned long generalPrevMillis = 0;
const long PIXEL_SWITCH_INTERVAL = 5;

int DRL_RESETER_LEFT = 0;
int DRL_RESETER_RIGHT = 0;

void welcome()
{
  int totalPixels = (NUMPIXELS + PIXELTOSHOW);
  while (G_PIXEL < totalPixels) {
    unsigned long leftCurrentMillis = millis();
    if (leftCurrentMillis - leftPrevMillis >= 12) {
      leftLight.setPixelColor(totalPixels - G_PIXEL, COLOR_WHI);
      rightLight.setPixelColor(totalPixels - G_PIXEL, COLOR_WHI);
      if (G_PIXEL >= 10) {
        leftLight.setPixelColor(totalPixels - G_PIXEL + PIXELTOSHOW , COLOR_NON);
        rightLight.setPixelColor(totalPixels - G_PIXEL + PIXELTOSHOW , COLOR_NON);
      }
      leftLight.show();
      rightLight.show();
      G_PIXEL++;
      leftPrevMillis = leftCurrentMillis;
    }
  }
  G_PIXEL = 0;
  while (G_PIXEL < totalPixels) {
    unsigned long leftCurrentMillis = millis();
    if (leftCurrentMillis - leftPrevMillis >= 12) {
      leftLight.setPixelColor(G_PIXEL, COLOR_WHI);
      rightLight.setPixelColor(G_PIXEL, COLOR_WHI);
      if (G_PIXEL >= 10) {
        leftLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
        rightLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
      }
      leftLight.show();
      rightLight.show();
      G_PIXEL++;
      leftPrevMillis = leftCurrentMillis;
    }
  }
}

void blinkRight()
{

  //slidePixels(rightBlinkCount, R_PIXEL, rightLight);
  if (rightBlinkCount > 0 && R_PIXEL > -1)
  {
      //Serial.println("RIGHT "+String(rightBlinkCount));
    LAST_COMMAND = ' ';
    unsigned long rightCurrentMillis = millis();
    if (rightCurrentMillis - rightPrevMillis >= PIXEL_SWITCH_INTERVAL) {
      rightLight.setPixelColor(R_PIXEL, COLOR_YEL);
      if (R_PIXEL >= PIXELTOSHOW)
      {
        rightLight.setPixelColor(R_PIXEL - PIXELTOSHOW, COLOR_NON);
        if (G_PIXEL > -1 && DRL_ON == false) {
          leftLight.setPixelColor(R_PIXEL - PIXELTOSHOW, COLOR_NON);
        }
      }
      leftLight.show();
      rightLight.show();
      R_PIXEL++;
      rightPrevMillis = rightCurrentMillis;
    }
    if ( R_PIXEL >= (NUMPIXELS + PIXELTOSHOW)) {
      rightBlinkCount--;
      if ( rightBlinkCount > -1 ) {
        R_PIXEL = DRL_RESETER_RIGHT = 0;
      } else {
        L_PIXEL = G_PIXEL = -1;
      }
      if(DRL_ON){
        D_PIXEL=DRL_STARTPIXEL;
      }
    }
  }

  }

  void blinkLeft() {
  //  slidePixels(leftBlinkCount, L_PIXEL, leftLight);

    if (leftBlinkCount > 0 && L_PIXEL > -1)
  {
          //Serial.println("left  "+String(rightBlinkCount));
    LAST_COMMAND = ' ';
    unsigned long leftCurrentMillis = millis();
    if (leftCurrentMillis - leftPrevMillis >= PIXEL_SWITCH_INTERVAL) {
      leftLight.setPixelColor(L_PIXEL, COLOR_YEL);
      if (L_PIXEL >= PIXELTOSHOW)
      {
        Serial.print(" "+String(L_PIXEL));
        leftLight.setPixelColor(L_PIXEL - PIXELTOSHOW, COLOR_NON);
        if (G_PIXEL > -1 && DRL_ON == false) {
          rightLight.setPixelColor(L_PIXEL - PIXELTOSHOW, COLOR_NON);

        }
      }
      rightLight.show();
      leftLight.show();
      L_PIXEL++;
      leftPrevMillis = leftCurrentMillis;
    }
    if ( L_PIXEL >= (NUMPIXELS + PIXELTOSHOW) ) {
      leftBlinkCount--;
      Serial.println("Count "+leftBlinkCount);
      if ( leftBlinkCount > -1 ) {
        L_PIXEL = DRL_RESETER_LEFT = 0;
      } else {
        L_PIXEL = G_PIXEL = -1;
      }
      if(DRL_ON){
        D_PIXEL=DRL_STARTPIXEL;
      }
    }
  }

}

/*void slidePixels(int &blinkCount, int &blinkPixel, Adafruit_NeoPixel &sideLight){
  if (blinkCount > 0 && blinkPixel > -1)
  {
    LAST_COMMAND = ' ';
    unsigned long leftCurrentMillis = millis();
    if (leftCurrentMillis - leftPrevMillis >= PIXEL_SWITCH_INTERVAL) {
      sideLight.setPixelColor(blinkPixel, COLOR_YEL);
      if (blinkPixel >= PIXELTOSHOW)
      {
        if(G_PIXEL>-1){
          rightLight.setPixelColor(blinkPixel - PIXELTOSHOW, COLOR_NON);
          leftLight.setPixelColor(blinkPixel - PIXELTOSHOW, COLOR_NON);
        }
      }
      rightLight.show();
      leftLight.show();
      blinkPixel++;
      leftPrevMillis = leftCurrentMillis;
    }
    if ( blinkPixel >= (NUMPIXELS + PIXELTOSHOW) ) {
      blinkCount--;
      if ( blinkCount > -1 ) {
        blinkPixel = 0;
      } else {
        blinkPixel = -1;
        if(DRL_ON){
          G_PIXEL = -1;
        }
      }
    }
  }
}*/

int switchRB = 0; // 0 = red, 1 = blue
void slideBlueRed() {
  unsigned long currentMillis = millis();
  if (currentMillis - generalPrevMillis >= 100) {
    if (switchRB == 0) {
      leftLight.setPixelColor(G_PIXEL, COLOR_RED);
      rightLight.setPixelColor(G_PIXEL, COLOR_RED);
    } else {
      leftLight.setPixelColor(G_PIXEL, COLOR_BLU);
      rightLight.setPixelColor(G_PIXEL, COLOR_BLU);
    }
    if (G_PIXEL >= 10) {
      leftLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
      rightLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
    }
    leftLight.show();
    rightLight.show();
    G_PIXEL++;
    generalPrevMillis = currentMillis;
  }
}


void drlLight(){

  unsigned long currentMillis = millis();
  if (D_PIXEL < NUMPIXELS) {
    leftLight.setPixelColor(NUMPIXELS-DRL_RESETER_LEFT, DRL_ON == true ? COLOR_WHI : COLOR_NON);
    rightLight.setPixelColor(NUMPIXELS-DRL_RESETER_RIGHT, DRL_ON == true ? COLOR_WHI : COLOR_NON);
    rightLight.setBrightness(128);
    leftLight.setBrightness(128);
    rightLight.show();
    leftLight.show();
    D_PIXEL++;
   //x //Serial.println(String(DRL_RESETER_LEFT) + " "+ String(NUMPIXELS - DRL_STARTPIXEL));
    if(DRL_RESETER_LEFT+1 < (NUMPIXELS - DRL_STARTPIXEL)){
      DRL_RESETER_LEFT++;
    }
    if(DRL_RESETER_RIGHT+1 < (NUMPIXELS - DRL_STARTPIXEL)){
      DRL_RESETER_RIGHT++;
    }
    generalPrevMillis = currentMillis;
  }


}

void setup() {
  Serial.begin(115200);
  leftLight.begin();
  rightLight.begin();
  pinMode(LEFT_BLINK_IN, INPUT);
  pinMode(RIGHT_BLINK_IN, INPUT);
  delay(50);
  welcome();
}

void loop() {

  if (digitalRead(LEFT_BLINK_IN) == HIGH) {
    if ( OEM_LEFT_ON == false ) {
      OEM_LEFT_ON = true;
      leftBlinkCount++;
      //Serial.println("LEFT "+String(leftBlinkCount));
      if (leftBlinkCount == 1) {
        L_PIXEL = 0;
      }
    }
  } else {
    OEM_LEFT_ON = false;
  }

  if (digitalRead(RIGHT_BLINK_IN) == HIGH) {
    if ( OEM_RIGHT_ON == false ) {
      OEM_RIGHT_ON = true;
      rightBlinkCount++;

      if (rightBlinkCount == 1) {
        R_PIXEL = 0;
      }
    }
  } else {
    OEM_RIGHT_ON = false;
  }

  if(DRL_ON && leftBlinkCount < 1 && rightBlinkCount < 1){
    drlLight();
  }

  blinkRight();
  blinkLeft();
  if(rightBlinkCount < 1 || leftBlinkCount < 1){
    delay(30);
    switch (LAST_COMMAND) {
      case 'q':
      case '?': {
        for ( int gp = 0; gp < NUMPIXELS + PIXELTOSHOW; gp++) {
          leftLight.setPixelColor(gp, COLOR_NON);
          rightLight.setPixelColor(gp, COLOR_NON);
        }
        leftLight.show();
        rightLight.show();
        G_PIXEL = -1;
        break;
      }
      case 's': {
        slideBlueRed();
        //Serial.println("bluuu");
        if (G_PIXEL >= NUMPIXELS ) {
          G_PIXEL = -1;
          switchRB = switchRB == 0 ? 1 : 0;
        }
        break;
      }
      case 'w': {
        welcome();
        if (G_PIXEL >= NUMPIXELS + PIXELTOSHOW) {
          G_PIXEL = -1;
        }
        break;
      }
      case 'd': {
        if(DRL_ON==false){
          D_PIXEL = DRL_STARTPIXEL;
          DRL_ON = true;
          LAST_COMMAND = '-';
        }else{
          D_PIXEL = 0;
          DRL_ON = false;
        }
        break;
      }
    }
    if (Serial.available()) {
      LAST_COMMAND = '-';
      while (Serial.available()) {
        char command = Serial.read();
        G_PIXEL=-1;
        LAST_COMMAND = command;
      }
    }
  }
}
9
  • Btw, ignore the case where 12V and 3.3V are tied together, The button can be used for only testing and transistor was ment to be used in live connections.
    – Deko
    Commented Sep 15, 2015 at 17:38
  • Is that schematic completely accurate? Especially the bit where you have the - of a 3.3V source connected to the +3.3V pin of the Arduino?
    – Majenko
    Commented Sep 15, 2015 at 17:42
  • Actually, sorry thought the prev scheme was messy, heres is what had as live and (one of the) test ENV. d.pr/i/BTxm I ran out of trial time in circuit lab and couldnt add the dirty test env. That is connecting the v3.3 directly to D2 with jumper wire.
    – Deko
    Commented Sep 15, 2015 at 18:11
  • Is R3 really 220Ω or is it bigger?
    – Majenko
    Commented Sep 15, 2015 at 18:26
  • 1
    You need to hold your unused input in a known state (pull it to ground) otherwise it will be floating and will be randomly triggering and picking up noise from the surrounding - from things like your hand when it's near.
    – Majenko
    Commented Sep 15, 2015 at 20:34

2 Answers 2

4

This kind of behavior is almost always caused by floating digital input pins. "floating" means not connected to either power or ground, so their voltage is free to float. These input puts have very high impedance (typically less than 1uA of leakage current), so bringing a charged object near them is more enough to change their state.

Probably the easiest way to nail down (and sometimes fix) this problem is to enable the pull-up resistors on the digital inputs.

In you program, this could be as easy changing the mode on the digital input pins from INPUT to INPUT-PULLUP...

void setup() {
  Serial.begin(115200);
  leftLight.begin();
  rightLight.begin();
  pinMode(LEFT_BLINK_IN, INPUT_PULLUP );
  pinMode(RIGHT_BLINK_IN, INPUT_PULLUP );
  delay(50);
  welcome();
}

This will almost certainly eliminate the intermittent behavior you are seeing.

What you end up with might not be what you want (you might want the pin to dault to 0 when not connected), in which case you can add an external pull-down resistor or change the software to work with default pull-up.

1
  • Yah, seems the floating input was causing this behavior.
    – Deko
    Commented Sep 16, 2015 at 11:45
3

Now, 3 years later, I found the actual source of your problem. I had a similar problem so I'm posting here for others to find this solution.

The problem is that the NeoPixel library disables ALL interrupts during the time it spends sending the pixel data. The millis() function is dependent on interrupts. It works by incrementing a counter once every millisecond, based on a interrupt, called from a hardware timer. If you disable all interrupts then the counter will not be incremented for the duration.

The NeoPixel library needs to disable them because NeoPixels need very accurate timing of the signals, and you'd suffer from visible intermittent glitches if not.

The millis() counter drops about 30 microseconds per a RGB pixel, or 40 microseconds for a RGBW pixel. You have 54 RGB pixels in your led strip. 54*0,030 = 1,62 ms. Which means that there's 1,62 milliseconds between each of your millis() updates. I.e. it updates too slow.

Your unstable button must've simply caused nonstop neopixel updates, due to some logic in your code.

There's no easy fix for this, but a few specialized alternative or companion libraries exist that use very device-specific peripherals to work around it. For example, you could use one of the hardware timers to measure the time spent sending NeoPixel data, and then manually go in and update the millis() counter accordingly when done. This requires hacking the NeoPixel library and reading the datasheets for your specific Arduino processor.

1
  • Thanks for getting back with update, definitely good research you've done! Kudos!
    – Deko
    Commented Jul 22, 2019 at 15:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.