arduinoesp32ledcpu-coresneopixel

ESP32 Cores are freezing when controlling two LED strings


So for the last week, I have been dealing with an issue with my ESP32. For background information, I am working on a Music Meter project. My goal is to have the ESP32 sample two audio signals, and have two set of LED strings react to the two respective audio signals. The issue that I have been having when I'm using both cores at the same time (with the Arduino IDE), one of the cores often freezes when I'm sampling audio. I know the core is freezing and it isn't getting stuck in the loop since I placed a condition to where one of the LED's will change colors if there hasn't been any activity for a extended period of time, and it never changed color.

What's also strange is as a baseline test, I wanted to see if I could just control the LED's but having a simple for loop turn each strip on and off, and that worked just fine. It's only when I start to sample audio on multiple cores and have the LED's react is where it becomes a problem. If I do each core individually, then the core never freezes, and it works the way I want it to.

/* This is in Core 1 */
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
    middle_strip.setPixelColor(i, color);
    middle_strip.show();
}
for (int i = (MIDDLE_LED_COUNT - 1); i >= 0 ; i--) {
    middle_strip.setPixelColor(i, 0, 0, 0, 0);
    middle_strip.show();
}
/* This is in Core 0 */
for (int i = 0; i < LOWER_LED_COUNT; i++) {
    lower_strip.setPixelColor(i, color);
    lower_strip.show();
}
for (int i = (LOWER_LED_COUNT - 1); i >= 0 ; i--) {
    lower_strip.setPixelColor(i, 0, 0, 0, 0);
    lower_strip.show();
}

Other things to note: WiFi has been disconnected when the ESP is in "Music Visualizer" mode via WiFi.mode( WIFI_MODE_NULL ). I've set all of my variables that are subject to change as volatile just to see if that would make it better. It slightly improved it, but it didn't fix the issue.

At this point, I am running out of rope, and I have no idea how to fix the problem. My current code is included below:

    /* Core 1 */
void musicVisualizer(void) {
  middle_strip.clear();
  upper_strip.clear();

  middle_strip.show();
  upper_strip.show();
  WiFi.mode( WIFI_MODE_NULL );
  delay(100);
  // Add code to tell Core 0 to wait until LED's are cleared.
  while (vu_meter) {
    tweeter_prev = tweeter;
    if (analogRead(tweeter_sample) <= 490)
      tweeter_adc = 0;
    else {
      tweeter_adc = (analogRead(tweeter_sample) - 490);
      if (tweeter_adc < 0)
        tweeter_adc = 0; // Filter for changing reference voltage
    }
    tweeter_filter.Filter(tweeter_adc);
    tweeter = tweeter_filter.Current() * 4;  // 6 scaler is for when Alexa is at Volume Level 4

    /* LED's turning on and off in response to audio */
    if ((tweeter > tweeter_prev) && (tweeter < MIDDLE_LED_COUNT)) {
      for (int x = tweeter_prev; x <= tweeter; x++) {
        middle_strip.setPixelColor(x, 0, 0, middle_strip.gamma32(BRIGHTNESS));
      }
      middle_strip.setPixelColor(0, 0, 0, middle_strip.gamma32(BRIGHTNESS));  // Removes status LED if active
      tweeter_count = 0;
      middle_strip.show();
    }
    else if (tweeter_prev > tweeter) {
      for (int x = tweeter_prev; x >= tweeter; x--) {
        middle_strip.setPixelColor(x, 0, 0, 0);
      }
      middle_strip.setPixelColor(0, 0, 0, middle_strip.gamma32(BRIGHTNESS));  // Removes status LED if active
      tweeter_count = 0;
      middle_strip.show();
    }
    else {
      tweeter_count += 1;
      if (tweeter_count < 1000)
        middle_strip.setPixelColor(0, middle_strip.gamma32(BRIGHTNESS), 0, 0, 0);
      else
        middle_strip.setPixelColor(0, 0, 0, 0, middle_strip.gamma32(BRIGHTNESS));
      middle_strip.show();
    }
    //        Blynk.run();
  }

  /* Leaving VU Meter, returning to current lamp color set */
  if (led_on) {
    if (!color_white) {
      for (int i = 0; i < LOWER_LED_COUNT; i++) {
        lower_strip.setPixelColor(i, color);
        lower_strip.show();
      }
      for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
        middle_strip.setPixelColor(i, color);
        middle_strip.show();
      }
      for (int i = 0; i < UPPER_LED_COUNT; i++) {
        upper_strip.setPixelColor(i, color);
        upper_strip.show();
      }
    }
    else {
      for (int i = 0; i < LOWER_LED_COUNT; i++) {
        lower_strip.setPixelColor(i, 0, 0, 0, lower_strip.gamma32(BRIGHTNESS));
        lower_strip.show();
      }
      for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
        middle_strip.setPixelColor(i, 0, 0, 0, middle_strip.gamma32(BRIGHTNESS));
        middle_strip.show();
      }
      for (int i = 0; i < UPPER_LED_COUNT; i++) {
        upper_strip.setPixelColor(i, 0, 0, 0, upper_strip.gamma32(BRIGHTNESS));
        upper_strip.show();
      }
    }
  }
  else {
    upper_strip.clear();
    middle_strip.clear();
    lower_strip.clear();

    upper_strip.show();
    middle_strip.show();
    lower_strip.show();
  }
}


/* Core 0 */
void vu_meter_sub(void * parameter) {
  while (true) {
    esp_task_wdt_init(30, false);

    if (vu_meter) {
      lower_strip.clear();
      lower_strip.show();
      while (vu_meter) {
        sub_prev = sub;
        sub_adc = analogRead(sub_sample);
        sub_filter.Filter(sub_adc);
        sub = sub_filter.Current();
        if ((sub > sub_prev) && (sub < LOWER_LED_COUNT)) {
          for (int x = sub_prev; x <= sub; x++) {
            lower_strip.setPixelColor(x, 0, lower_strip.gamma32(BRIGHTNESS), 0);
          }
          lower_strip.setPixelColor(0, 0, lower_strip.gamma32(BRIGHTNESS), 0);
          sub_count = 0;
          lower_strip.show();
        }
        else if (sub_prev > sub) {
          for (int x = sub_prev; x >= sub; x--) {
            lower_strip.setPixelColor(x, 0, 0, 0);
          }
          lower_strip.setPixelColor(0, 0, lower_strip.gamma32(BRIGHTNESS), 0);
          sub_count = 0;
          lower_strip.show();
        }
        else {
          sub_count += 1;
          if (sub_count < 1000)
            lower_strip.setPixelColor(0, lower_strip.gamma32(BRIGHTNESS), 0, 0, 0);
          else
            lower_strip.setPixelColor(0, 0, 0, 0, lower_strip.gamma32(BRIGHTNESS));
          lower_strip.show();
        }
      }
    }
  }
}

Solution

  • After troubleshooting, I think I found the issue, and I want to post it for anyone that may come across this post in the future.

    In my program, I needed to add a 1ms delay to both music_visualizer functions in both cores to keep the CPU's from being starved of runtime (I believe this is what is happening). Doing this massively improved to success rate of the firmware. I noticed that if Blynk (the app that is controlling the lamp) is uncommented, and free to run as many times, the chance of one of the CPU's starving increases. To fix this, what I did was use the millis() timer to keep track of how much time passes before Blynk is called. After 1000ms, the Blynk function will be called once, and will wait another 1000ms. Since I proved this can work, WIFI_MODE_NULL is not needed since the WiFi does not need to be disabled.