Adafruit_NeoPixel + SoftTimer Issues

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
drlight
 
Posts: 4
Joined: Mon Sep 15, 2008 12:56 am

Adafruit_NeoPixel + SoftTimer Issues

Post by drlight »

Hi Forum -


Seems like when using the SoftTimer in conjunction with the NeoPixel library an issue arises.

this code should sequentially light all of the 12 pixels on my board, 5 seconds apart. in red

issue is: it only lights the first one, in red.

I have debugged and i can see that both a) the task is being successfully triggered b) the counter variable is incrementing as expected

it is as if the strip.show() is not being processed after the first time the task is being called.

my gut tells me there is some timer (as in AVR timer) conflict. but then again, i have no idea whats actually going on under the hood of the NeoPixel library.

edit: ther SoftTimer library is basically constantly calling micros() - not sure if that helps/points in the right direction




Code: Select all

#include <Adafruit_NeoPixel.h>
#include <SoftTimer.h>

#define PIN 6



// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);


//variable dec
Task tColorWipeRed(1000,cColorWipeRed);

int counter=0;



void setup() {
  
  //serial init
 Serial.begin(19200);
 
 //strip stuff init
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'


  //add the task to the timer manager
  
   SoftTimer.add(&tColorWipeRed);


  
}



  
   
  //this is the calback function that is executed by the timer manager at the user defined interval 

  void cColorWipeRed(Task* me){
   
 //run the actual function
    ColorWipe(strip, strip.Color(10,0,0));
    
  }
  

  
  
 //this is the actual function 
void ColorWipe(Adafruit_NeoPixel sT, uint32_t c) {

  
   //this is here as a debug blinky to make sure that this thread/task is running
 
   digitalWrite(13, digitalRead( 13 ) ^ 1);
   
    //if the current step in the effect is less than total number of pixels  
   if( counter < sT.numPixels()){
    
       //print current step to double check the step# is actually incrementing.
     Serial.print(counter);
      
      //set that pixel in the strip to the inbound color     
      strip.setPixelColor(counter, c);

        //counter seems to incrememnt (when i read it from the serial debug line), but does not result in the next LED turning on.  
       //increment next step
      counter++;
      
      //turn on dem pixelsss
      strip.show();
     
    }
   

    strip.show();
  
      //if we're at the end of the strip, start over. 
   if( tColorWipeRed.rcS() == sT.numPixels()){tColorWipeRed.rcSt(0);}//reset the counter to zero
   
}//end colorWipe

User avatar
adafruit_support_bill
 
Posts: 88092
Joined: Sat Feb 07, 2009 10:11 am

Re: Adafruit_NeoPixel + SoftTimer Issues

Post by adafruit_support_bill »

The neopixel library does not use timers. However, it does disable interrupts during strip.show() operations due to the critical timing requirements of the neopixel led controllers. This has been known to mess up timers and other interrupt-driven code.

drlight
 
Posts: 4
Joined: Mon Sep 15, 2008 12:56 am

Re: Adafruit_NeoPixel + SoftTimer Issues

Post by drlight »

apparently, the SoftTimer library does not use timers either - BUT it does constantly check millis().

The timer library isnt affected when the issue occurs. It still runs at regularly scheduled intervals,as it should.No unexpected behaviour there.

The code is essentially doing everything but actually illuminating the NeoPixel, after the first time the Task/subroutine/function/thread whatever you want to call it, is executed. the task itself continues to iterate, and increment its 'count' variable. the status LED blinks on and off.

you mention that strip.show() disables timers, which would make millis() break. Is there any way the fact that the Timer library is checking/comparing this function every loop would cause an issue.

Am i screwing up the neopixel timing somehow now, and the signal is garbled?

User avatar
adafruit_support_bill
 
Posts: 88092
Joined: Sat Feb 07, 2009 10:11 am

Re: Adafruit_NeoPixel + SoftTimer Issues

Post by adafruit_support_bill »

you mention that strip.show() disables timers, which would make millis() break.
It doesn't necessarily 'break' millis(). But it can cause missed interrupts which would skew the time. strip.show() will disable interrupts for as long as it takes to update all your pixels. For 12 pixels every 5 seconds, that shouldn't be too long. You might miss a millis() tick here and there, but I wouldn't expect it to fail completely. There must be something else at work here. I'm not familiar with SoftTimer, so I don't know what other interactions there might be.

User avatar
sausage
 
Posts: 23
Joined: Thu Sep 12, 2013 5:37 pm

Re: Adafruit_NeoPixel + SoftTimer Issues

Post by sausage »

How accurate does it have to be? Why not just make your own timer like this:

Code: Select all

#include <Adafruit_NeoPixel.h>

#define PIN 6
#define NUM_LED 12

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LED, PIN, NEO_GRB + NEO_KHZ800);
const uint32_t RED = strip.Color(255, 0, 0);
const uint32_t OFF = strip.Color(0, 0, 0);
unsigned long startTime = millis();
boolean isFiveSecondsElapsed = false; 
uint8_t index = 0;
  
void setup() {
  strip.begin();
  strip.setBrightness(64);
  SetAllPixelsToOff();
  strip.show(); // Initialize all pixels to 'off'
  
}

void loop() {
  if (millis() - startTime >= 5000)
  {
    isFiveSecondsElapsed = true;
  }
  
  if (isFiveSecondsElapsed)
  {
    strip.setPixelColor(index, RED);
    strip.show();
    
    index++;
    if (index >12) 
    {
      index = 0;
      SetAllPixelsToOff();
    } 
    
    isFiveSecondsElapsed = false;
    startTime = millis();
  }
}

void SetAllPixelsToOff()
{
  for (uint8_t i = 0; i < NUM_LED; i++)
  {
    strip.setPixelColor(i, OFF);
  }
  strip.show();
}

magmatrix
 
Posts: 1
Joined: Thu Jul 10, 2014 4:57 pm

Re: Adafruit_NeoPixel + SoftTimer Issues

Post by magmatrix »

I have 756 pixels and the disabled interrupts are screwing up millis() really bad. A 45 second run is reported as 13 seconds, and as i use millis() to control the timing of the animation it slows down *a lot*. What can i do about this?

Thx
/M

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Adafruit_NeoPixel + SoftTimer Issues

Post by pburgess »

strip.show() does in fact break millis() and micros() by temporarily disabling interrupts. If my math is right, it looks like you'll lose track of about 23 milliseconds every time you call show().

This is just an unfortunate cake-and-eat-it reality. AVR interrupts can't be enabled when issuing data to NeoPixels; the signal will get corrupted. Something's gotta give, and it's the current millis()/micros() values.

Some possible workarounds:

1. Try to incorporate the "lost" ~23 ms into your animation timing.

2. Set up an alternate timer (Timer1 or Timer2 -- Timer0 is used for millis() etc.) to cycle at your desired frame rate, polling the corresponding overflow flag to know when to update the strip (and clear the flag). As long as your combined frame-calculation and strip-writing times are less than this, there will be no appreciable latency. You can also use a timer overflow interrupt for this.

3. Use a DMA-capable microcontroller and library such as the Teensy 3.1 and OctoWS2811, which can walk and chew gum at the same time.

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”