XRAD'S Can someone explain to me why this program locks up?

Seems like an easy straightforward little program...I can get it to run a few loops but then it locks up after maybe 3 to 5 loops or sometimes not at all... not sure why?

hardware: adafruit trinket M0, 100 ohm resistor to piezo, adafruit neopixel jewel

Thank you for any tips!!

small jewel

#include <Adafruit_NeoPixel.h> // include the Neopixel Library in this Sketch

#define LED_PIN 2 // Data out to strip

#define LED_COUNT 7 // how many pixels in entire strip

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN);//num pixels , pin

int PXL1[] = {0, 1, 2, 3, 4, 5, 6};
int pixelRingPos = 1;
const int BuzzerPin =  4;

int BuzzerPinState = LOW;

unsigned long previousMillis = 0;


int interval = 200; // initial interval at which to sound

int Tone = 3400;
int toneCount = 0;

void Larson() {//classic Larson scanner!

  int pos = 0, dir = 1; // Position, direction of "eye"

  for (int i = 0; i < 250; i++) {
    int j;
    strip.setPixelColor(pos - 2, 0x100000); // Dark red
    strip.setPixelColor(pos - 1, 0x800000); // Medium red
    strip.setPixelColor(pos    , 0xFF3000); // Center pixel is brightest
    strip.setPixelColor(pos + 1, 0x800000); // Medium red
    strip.setPixelColor(pos + 2, 0x100000); // Dark red

    strip.show();
    delay(30);

    for (j = -2; j <= 2; j++) strip.setPixelColor(pos + j, 0);

    pos += dir;
    if (pos < 0) {
      pos = 1;
      dir = -dir;
    } else if (pos >= strip.numPixels()) {
      pos = strip.numPixels() - 2;
      dir = -dir;
    }
  }
}


void setup() {
  pinMode(BuzzerPin, OUTPUT);
  strip.begin();
  strip.clear();
  strip.show();
}

void loop() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (BuzzerPinState == LOW) {
      BuzzerPinState = HIGH;
      //Serial.println(Tone);
      tone(BuzzerPin, Tone);
      toneCount++;
      //Serial.println(toneCount);
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(255, 0, 0)); // set array pixel red
      strip.show();
    } else {
      BuzzerPinState = LOW;
      noTone(BuzzerPin);
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(0, 0, 0)); // set array pixel null
      strip.show();
      pixelRingPos++;
      if (pixelRingPos > 6) {
        pixelRingPos = 1;
      }
    }
  }

  if (toneCount >= 3) {
    toneCount = 0;
    interval = interval - 5;
    Tone = Tone + 100;
    if (Tone >= 5400) {
      delay(2000);
      noTone(BuzzerPin);
      Larson();
      strip.clear();
      strip.show();
      pixelRingPos = 0;
      interval = 200;
      Tone = 3500;
      //insert device state change here, and signal to pololu to OFF
      delay(5000);
    }
  }
}

Can you explain your indexing scheme? You seem to be ignoring the first element except here
pixelRingPos = 0;
Why?

The reason is I am only using the outside jewel pixels for the 'countdown' part of the code, and then for the 'larson scan' all the pixels. The 1st pixel {0} is the center pixel in the jewel.

For some reason ( i need to find in my code), the pixel count begins at +1 + 1 once the code cycles...and the 3rd jewel pixel lights up as the first...so I reset it to '0' at end of loop....

so currently, the ring cycles appropriately.

I tried it on teensy 3.2 with same pins and works fine....might be my pin choice for the trinket.....

edit: I tried piezo on different pins on trinket...still locks up.....

Solved: For some reason, it works on trinket M0 with piezo pin as pin 2, and pixel pin as pin 4. Maybe it was a conflict in the hardware registers/timers?

Does 'setPixelColor()' protect you from writing off the ends of your strip? If not, these function calls might be corrupting data when 'pos' is less than 2 or greater than 4.

1 Like

interesting thought. I thought the numpixels constrained the 'strip ends.' and all pixels within the strip are cleared and then rewritten...and only those in the strip are processed and written to....

But it never locks up while running the Larson scan..only during the 'around the ring' sequence , usually 3-4 pixels into the ring...

I have used this larson code I modified for several different programs and never had an issue......

and it is strange that the above code works using different pins on the M0.....that's why I think the way adafruit set up the M0 pins, there is a shared timer which i then corrupted....either by the pixel code or the piezo code....I did notice that sometimes, the piezo would make a weird sound, not a pure tone, on the M0, while it sounded very good on the teensy through all tones...

I checked the NeoPixel library and it DOES protect against setting the color of a pixel outside the limits of the strip. If the pixel number (as an unsigned int) is greater than or equal to the number of pixels the .setPixelColor() function does nothing. Small negative numbers will be very large unsigned numbers so they will be out of range.

Hi John, Thank you for the reply! That is very interesting and I have learned something again here on this forum. I figured out some of the issues as well. Looks like I had conflicting timers. I rewrote the code and it does not crash now.... here is the final version in case anyone else wants to see multiple timers in use....

youtube vid:

/* XRAD'S Mandalorian Grav Charge  9/19/2022
 * Hardware: adafruit trinket M0
 * adafruit TDK piezo PS1240
 * adafruit Jewel
 * Grav charge models from: https://www.etsy.com/listing/1247432778
 * 100maH Lipo..the tiny one!
 * pololu mini on off switch
 * Siemens 3SU10016AA200AA0, Indicator Light, Red, Smooth Lens (just using the red lens)
 * my youtube vid: https://https://www.youtube.com/watch?v=vbc7Ajk7PfQ
 * 
 * had to create a bit of non-blocking code to run the pixels and piezo at same time. 
 * I'm sure there is a better way, but this was straight-forward. feel free to use
 * or modify as you like!
  */


#include <Adafruit_NeoPixel.h> // include the Neopixel Library in this Sketch

#define LED_PIN 2 // Data out to strip
#define LED_COUNT 7 // how many pixels in entire strip

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN);//num pixels , pin


//piezo mini beep delay
int buzzer = 3;
int piezoTime = 100;//mini beep interval (well, minus the buzzer play time!)
unsigned long piezoTimer;
int timer = 0;
int freq = 3500;

//piezo main delay variables
unsigned long previousMillis2;
int piezoOffTime = 1000;  //interval no-tone gap (well, minus the buzzer play time!)
bool offTimerFlag = false;

//neopixel variables
unsigned long previousMillis1;
int intervalPixel = 100;// time between pixel position change
int pixelState = LOW;
int PXL1[] = {0, 1, 2, 3, 4, 5, 6};//array of ring pixels, 0 is center pixel
int pixelRingPos = 1;//1st position on outside of ring

void Larson() {//my modified Larson scanner!
  int pos = 0, dir = 1; // initial position, initial direction of "eye"
  for (int i = 0; i < 200; i++) {
    int j;
    strip.setPixelColor(pos - 3, 0x100000); // Dark red
    strip.setPixelColor(pos - 2, 0x100000); // Dark red
    strip.setPixelColor(pos - 1, 0x800000); // Medium red
    strip.setPixelColor(pos    , 0xFFFFFF); // Center pixel is brightest, the 'eye'
    strip.setPixelColor(pos + 1, 0x800000); // Medium red
    strip.setPixelColor(pos + 2, 0x100000); // Dark red
    strip.setPixelColor(pos + 3, 0x100000); // Dark red
    strip.show();
    
    for (j = -2; j <= 2; j++)
      strip.setPixelColor(pos + j, 0);
    pos += dir;
    if (pos < 0) {
      pos = random(1, 7);
      dir = -dir;
    } else if (pos >= strip.numPixels()) {
      pos = random(1, 7);
      dir = -dir;
    }
    delay(30);//delay pixel display a bit
  }
  strip.clear();
  strip.show();
}


void setup() {
  // Serial.begin(9600);
  pinMode(buzzer, OUTPUT);
  randomSeed(analogRead(20));//for the larson scanner random
  strip.setBrightness(150);//save my wee battery!
  strip.begin();
  strip.clear();
  strip.show();
  delay(100);//short power-up delay
  piezoTimer = millis();//don't put a delay after these timers begin!
  previousMillis2 = millis();
  previousMillis1 = millis();
}


void loop() {

  if ((offTimerFlag == true) && (millis() - previousMillis2 >= piezoOffTime)) {
    previousMillis2 = millis();
    offTimerFlag = false;
  }
  if ((offTimerFlag == false) && (millis() - piezoTimer >= piezoTime)) {
    tone(buzzer, freq, 60);
    //Serial.print("timer: ");
    //Serial.println(timer);
    piezoTimer = millis();
    timer++;
    if (timer > 3) {
      freq = freq + 100;
      timer = 0;
      offTimerFlag = true;
    }
    if (freq >= 4500) {
      strip.clear();
      strip.show();
      for (int x = 0; x < strip.numPixels(); x++) {
        strip.setPixelColor(x, strip.Color(255, 0, 0));
        strip.show();
      }
      tone(buzzer, 4500);
      delay(1500);//hold buzzer tone for this long
      noTone(buzzer);
      strip.clear();
      strip.show();
      delay(100);
      Larson();
      delay(5000);//temporary
      //insert device state change here, and signal to pololu to OFF
      freq = 3500;
      pixelRingPos = 1;
      timer = 0;
    }
  }


  //pixel
  if (millis() - previousMillis1 >= intervalPixel) {
    previousMillis1 = millis();
    if (pixelState == LOW) {
      pixelState = HIGH;
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(255, 0, 0));
      strip.show();
    } else {
      pixelState = LOW;
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(0, 0, 0));
      strip.show();
      pixelRingPos++;
      if (pixelRingPos > 6) {
        pixelRingPos = 1;
      }
    }
  }
}

good project

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.