Can't control NeoPixels (WS2812B addressable LEDs) after sleep mode?

I have a bit of code which has been very reliable for running short strings of NeoPixels in various animation modes.

I store the current mode (an integer) in EEPROM, read it in the setup() function, then immediately increment that value and write it back to EEPROM (if it exceeds the maximum mode it resets back to 0).

This lets me cycle through the modes nust by tapping the reset button.

I've been building a very small self-contained version (for a illuminated collar) with an Arduino Pro Mini (3.3v/8MHz) and a 440mAh Lithium Polymer battery. It worked beautifully, and the first version ran for 12 hours and was still going strong on a single charge.

Because it's worn as a collar, and there isn't a good place for a traditional on/off switch, I thought I would experiment with putting the Pro Mini to sleep using the RocketScream library. My initial experiments just used an 8s timed power_down. It then resets the task to one of the animations so it won't get stuck in a power_down loop.

The problem is that since the first time I put it to sleep the NeoPixels won't activate. I added some Serial.print status messages, and I can confirm that the Pro Mini is starting, loading (and incrementing) the mode correctly, and calling the correct NeoPixel animation routines, and when the sleep mode is hit, it sleeps for 8 seconds and then goes back to animation mode 0.

The LED string, however, never lights. It is not damaged; if I run it from one of my other controllers with the previous code, it fires up just fine. I've checked and can confirm that the LiPo is delivering power to the string and the Pro Mini, and the VCC output on the board is 3.3V.

If I load the BLINK example code, the LED on pin 13 blinks just as expected.

I have tried changing output pins with no success : 2 (the original), 3, and 8 (since it is on the same port as pin 13, in case I blew out port D somehow).

If I reload my old sketch (without the sleep mode), still nothing.

Any suggestions?

Thanks!

Kevin

KPRoche: Any suggestions?

An EEPROM has limited write cycles.

How often may you have written to the same EEPROM cell?

If you've written the EEPROM to death, might it be possible that invalid values read from the EEPROM lead to malfunction of your sketch?

What happens if you try to control your Neopixels with another sketch that doesn't use the EEPROM?

mmmmm....

Where's your code?

Also - you can check whether your arduino is sending anything down the data pin by putting a LED + resistor between that and ground, and it will flicker when data is being sent (can do this w/leds disconnected) - that may be a useful debugging tool for you.

jurs: An EEPROM has limited write cycles.

How often may you have written to the same EEPROM cell?

If you've written the EEPROM to death, might it be possible that invalid values read from the EEPROM lead to malfunction of your sketch?

What happens if you try to control your Neopixels with another sketch that doesn't use the EEPROM?

This is a brand-new Pro Mini, and as I said, I can see from the debug data returned on the serial monitor that the eeprom is being read and written correctly.

I have tried removing the EEPROM code as you suggest and and it had no effect on the problem.

As I mentioned, the NeoPixels work fine if I plug them into a different Arduino.

Oops… here is the code (my original post was done from my tablet rather than the laptop where my sketches are stored. This has chunks elided to make it fit in the post.
If you want the complete sketch you can download it from my Google Drive

#include <LowPower.h>
#include <Adafruit_NeoPixel.h>
#include "WS2812_Definitions.h"
#include <EEPROM.h>

#define PIN 9
#define LED_COUNT 17

// Create an instance of the Adafruit_NeoPixel class called "collar".
// That'll be what we refer to from here on...
Adafruit_NeoPixel collar = Adafruit_NeoPixel(LED_COUNT, PIN, NEO_GRB + NEO_KHZ800);
byte ScannerTask = 0;
byte MaxTask = 5;

unsigned long elapsed_time;
void clearLEDS();
void multi_cylon(unsigned long color, byte wait, int num_eyes = 3, unsigned long endcue = 0, boolean legs_on = true, boolean lapels_on = true);
void theaterChaseRainbow(uint8_t wait, unsigned long endcue = 0, boolean legs_on = true, boolean lapels_on = true);
void multi_meteor(unsigned long color, byte wait, int num_eyes, unsigned long endcue = 0, boolean legs_on = true, boolean lapels_on = true);
void AllScans();
void MusicalNumber();

void setup()
{
  pinMode(13,OUTPUT);
  Serial.begin(9600);
  // Read the stored task from last time and modulo it
  ScannerTask = 0;
  ScannerTask = EEPROM.read(0);
  Serial.println(F("Flashy Collar with sleep mode"));
  Serial.print(F("Stored ScannerTask: "));
  Serial.println(ScannerTask);
  ScannerTask++;
  if (ScannerTask > MaxTask) {
    ScannerTask = 0;
  }
  // store it to eeprom
  EEPROM.write(0, ScannerTask);

  collar.begin();  
  clearLEDS();  
  collar.show();
}

void loop()
{

  collar.setBrightness(256);
  digitalWrite(13,HIGH);
  delay(50);
  digitalWrite(13,LOW);

  switch (ScannerTask) {
    case 0:
      Serial.println(F("mode 0: allscans"));
      AllScans();
      break;
    case 1:
      Serial.println(F("mode 1: rainbow"));
      for (int i = LED_COUNT * 10; i >= 0; i--)
      {
        rainbow(i);
        delay(10);  // Delay between rainbow slides
      }
      break;
    case 2:
      // cylon function: first param is color, second is time (in ms) between cycles
      Serial.println(F("mode 2: multicylon"));
      multi_cylon(INDIGO, 20, 1); // Indigo cylon eye!
      multi_cylon(BLUE, 20, 1); // Indigo  multi_cylon eye!
      multi_cylon(GREEN, 20, 1); // Indigo  multi_cylon eye!
      multi_cylon(YELLOW, 20, 1); // Indigo  multi_cylon eye!
      multi_cylon(ORANGERED, 20, 1); // Indigo  multi_cylon eye!
      multi_cylon(DARKRED, 20, 1); // Indigo cylon eye!
      break;
    case 3:
      Serial.println(F("mode 3: theater chase"));
      theaterChaseRainbow(40);
      break;
    case 4:
      Serial.println(F("mode 4: meteor"));
      multi_meteor(INDIGO, 20, 2); // Indigo cylon eye!
      multi_meteor(BLUE, 20, 2); // Indigo  multi_meteor eye!
      multi_meteor(GREEN, 20, 2); // Indigo  multi_meteor eye!
      multi_meteor(YELLOW, 20, 2); // Indigo  multi_meteor eye!
      multi_meteor(ORANGERED, 20, 2); // Indigo  multi_meteor eye!
      multi_meteor(DARKRED, 20, 2); // Indigo cylon eye!
      break;
    case 5: //put the collar into "off" mode
      Serial.println(F("mode 5: sleep for 8s"));
      delay(1000);
      LowPower.powerDown(SLEEP_8S, ADC_ON, BOD_ON);

      ScannerTask = 0;
      break;
    default:
      AllScans();
  }
}

//*********************  multi_cylon ************************
// Implements a  multiple "eye" Larson "cylon" sanner.
// This'll run one full cycle, down one way and back the other
void multi_cylon(unsigned long color, byte wait, int num_eyes, unsigned long endcue, boolean legs_on, boolean lapels_on)
{
  // Code elided for brevity. This function is unchanged from my working code
}



//*********************  multi_meteor ************************
// Implements a little meteor cascade with mutliple eyes that "drips" down the line

void multi_meteor(unsigned long color, byte wait, int num_eyes, unsigned long endcue, boolean legs_on, boolean lapels_on)
{
  // Code elided for brevity. This function is unchanged from my working code
}


//*****************  clearLEDs ************************
// Sets all collar to off, but DOES NOT update the display;
// call collar.show() to actually turn them off after this.
void clearLEDS()
{
  int i_clear = LED_COUNT;
  for (int i = 0; i < i_clear; i++)
  {
    collar.setPixelColor(i, 0);
  }

}

//*********************  rainbow ************************
//
// Prints a rainbow on the ENTIRE LED strip.
//  The rainbow begins at a specified position.
// ROY G BIV!
void rainbow(byte startPosition)
{
  // Code elided for brevity. This function is unchanged from my working code
}

//*********************  rainbowOrder ************************
//
// Input a value 0 to 191 to get a color value.
// The colors are a transition red->yellow->green->aqua->blue->fuchsia->red...
//  Adapted from Wheel function in the Adafruit_NeoPixel library example sketch
uint32_t rainbowOrder(byte position)
{
  // 6 total zones of color change:
  if (position < 31)  // Red -> Yellow (Red = FF, blue = 0, green goes 00-FF)
  {
    return collar.Color(0xFF, position * 8, 0);
  }
  else if (position < 63)  // Yellow -> Green (Green = FF, blue = 0, red goes FF->00)
  {
    position -= 31;
    return collar.Color(0xFF - position * 8, 0xFF, 0);
  }
  else if (position < 95)  // Green->Aqua (Green = FF, red = 0, blue goes 00->FF)
  {
    position -= 63;
    return collar.Color(0, 0xFF, position * 8);
  }
  else if (position < 127)  // Aqua->Blue (Blue = FF, red = 0, green goes FF->00)
  {
    position -= 95;
    return collar.Color(0, 0xFF - position * 8, 0xFF);
  }
  else if (position < 159)  // Blue->Fuchsia (Blue = FF, green = 0, red goes 00->FF)
  {
    position -= 127;
    return collar.Color(position * 8, 0, 0xFF);
  }
  else  //160 <position< 191   Fuchsia->Red (Red = FF, green = 0, blue goes FF->00)
  {
    position -= 159;
    return collar.Color(0xFF, 0x00, 0xFF - position * 8);
  }
}

//*********************  TehaterChaseRainbow ************************

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait, unsigned long endcue, boolean legs_on, boolean lapels_on) {
  // Code elided for brevity. This function is unchanged from my working code
}


//*********************  Wheel ************************
//   Color wheel calculator
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return collar.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  else if (WheelPos < 170) {
    WheelPos -= 85;
    return collar.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  else {
    WheelPos -= 170;
    return collar.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}


//*************** AllScans (demo mode) ***************
//            shows off all the animations
void AllScans()
{
  // Ride the Rainbow Road
  for (int i = LED_COUNT * 10; i >= 0; i--)
  {
    rainbow(i);
    delay(10);  // Delay between rainbow slides
  }

  // cylon function: first param is color, second is time (in ms) between cycles, third is # of "eyes"
  multi_cylon(INDIGO, 20, 2); // Indigo cylon eye!
  multi_cylon(BLUE, 20, 2); // Indigo  multi_cylon eye!
  multi_cylon(GREEN, 20, 2); // Indigo  multi_cylon eye!
  multi_cylon(YELLOW, 20, 2); // Indigo  multi_cylon eye!
  multi_cylon(ORANGERED, 20, 2); // Indigo  multi_cylon eye!
  multi_cylon(DARKRED, 20, 2); // Indigo cylon eye!

  theaterChaseRainbow(40);

  multi_meteor(INDIGO, 20, 4); // Indigo cylon eye!
  multi_meteor(BLUE, 20, 4); // Indigo  multi_meteor eye!
  multi_meteor(GREEN, 20, 4); // Indigo  multi_meteor eye!
  multi_meteor(YELLOW, 20, 4); // Indigo  multi_meteor eye!
  multi_meteor(ORANGERED, 20, 4); // Indigo  multi_meteor eye!
  multi_meteor(DARKRED, 20, 4); // Indigo cylon eye!
}

The output from the serial monitor looks like this:

Flashy Collar with sleep mode
Stored ScannerTask: 3
mode 4: meteor
mode 4: meteor
mode 4: meteor

So it clearly is starting up and running the loop ok.

I did discover that I’d actually wired to pin 9, not 8, on my last rewire attempt, but changing the code to reflect that still doesn’t get me lights.

The suggestion to try an LED with load resistor as an indicator is a good one. I can try that when I get back to my studio tonight. I did put in a “ping” to pin13 so I can watch for signs the loop is actually running, and the pin 13 LED on the board flashes on schedule.

I can also try wiring up another new board and trying it; maybe I’ve actually damaged this one somehow.

This continued to baffle me for much of the last two days. I tried my code on a second, new 3.3V Pro Mini and it also failed; I then tried using a 5V/16MHz Pro Mini in case I wasn't quite getting enough voltage and nothing.

I then thought to go all the way back to the basic AdaFruit "teststrand" example from their Neopixel libary, and voila! The strand lit.

I then worked my way backward through my code and sure enough, once I got to a version that had not been "cleaned up" to make it tidier for the mini, everything started working again.

I even added in the PowerDown task and it executes properly. I can set it to the sleep_forever mode and wake the collar back up by hitting the reset button the appropriate number of times.

I suspect (but have not been able to find it yet) a misplaced brace in an IF structure. The later versions of the code had the ability to count time (for timing cues to match changes in animation for three LED strands to a match song and dance number), and I think in stripping the code down to the single strand I messed it up. It compiled properly, but even though my functions were being called they were never lighting the strand.

Now I can more carefully clean up this working copy and package it.

The new code works just as I want; the problem was definitely a mis-enclosure in the code for an if clause.

This will cycle through 5 NeoPixel animations (the zeroth is a “demo” mode that calls each of the others in a loop) then goes into PowerDown mode just by pushing the reset button on the Pro Mini board.

The code is too long to embed so I’m attaching the sketch.

It needs the AdaFruit_NeoPixel library and the Rocket Scream LowPower library.

FlashyCollarMiniSLEEP2b.ino (10.8 KB)

WS2812_Definitions.h (4.21 KB)