ESP32 SerialBT crashing on ASSERT_PARAM after streaming for a minute or two

Hello, my ESP32 device keeps resetting after streaming serial data over BT for a while.

Has anyone else had this issue?

Here's the errors and stacktrace decoding below:

ASSERT_PARAM(512 0), in rwbt.c at line 273
Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0)
Core 0 register dump:
PC : 0x40085844 PS : 0x00060034 A0 : 0x800892bc A1 : 0x3ffc05b0
A2 : 0x00000001 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x60008054
A6 : 0x3ffc1030 A7 : 0x60008050 A8 : 0x80085841 A9 : 0x3ffc0590
A10 : 0x00000004 A11 : 0x00000000 A12 : 0x6000804c A13 : 0xffffffff
A14 : 0x00000000 A15 : 0xfffffffc SAR : 0x00000004 EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x40085779 LEND : 0x40085780 LCOUNT : 0x00000000
Core 0 was running in ISR context:
EPC1 : 0x4017e24a EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40085844

Backtrace: 0x40085844:0x3ffc05b0 0x400892b9:0x3ffc05d0 0x4008994b:0x3ffc05f0 0x40081f45:0x3ffc0610 0x4017e247:0x00000000

Core 1 register dump:
PC : 0x4017e24a PS : 0x00060334 A0 : 0x8008e46a A1 : 0x3ffd1de0
A2 : 0x00000008 A3 : 0x00000001 A4 : 0x00000000 A5 : 0x3ffd1910
A6 : 0x00000000 A7 : 0x00000001 A8 : 0x3ffc829c A9 : 0x3ffc8260
A10 : 0x00000000 A11 : 0x00000001 A12 : 0x8008c8c8 A13 : 0x3ffd1ce0
A14 : 0x00000000 A15 : 0x3ffd1aa0 SAR : 0x00000000 EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000

Backtrace: 0x4017e24a:0x3ffd1de0 0x4008e467:0x3ffd1e00

Decoding 13 results
0x40085844: r_assert_param at ?? line ?
0x40085779: r_assert_param at ?? line ?
0x40085780: r_assert_param at ?? line ?
0x4017e24a: esp_vApplicationWaitiHook at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/freertos_hooks.c line 66
0x40085844: r_assert_param at ?? line ?
0x40085844: r_assert_param at ?? line ?
0x400892b9: r_rwbt_isr at ?? line ?
0x4008994b: r_rwbtdm_isr_wrapper at intc.c line ?
0x40081f45: _xt_lowint1 at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/xtensa_vectors.S line 1105
0x4017e247: esp_vApplicationWaitiHook at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/freertos_hooks.c line 66
0x4017e24a: esp_vApplicationWaitiHook at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/freertos_hooks.c line 66
0x4017e24a: esp_vApplicationWaitiHook at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/freertos_hooks.c line 66
0x4008e467: prvIdleTask at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/tasks.c line 3564

Turns out my heap gets reduced the slower I transmit, causing overflow. Must be something in my code eating up resources when I don't transmit for a few hundred ms or more for some reason. Anyone want to take a look and give me their 2 cents on what could be eating memory at slower transmit rates? At 100ms it is stable, kind of the opposite of what you'd expect huh?

#include "BluetoothSerial.h"

#include <Wire.h>
#include <Adafruit_ADS1015.h>
//#include <esp_bt.h>
//#include <ArduinoJson.h>
 
BluetoothSerial SerialBT;

GLOBAL VARIABLES HERE

void startADS() {
  // Begin ADS
  ads.begin();
  ads.setGain(GAIN_SIXTEEN);

  //ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV (default)
  //ads.setGain(GAIN_ONE);     // 1x gain   +/- 4.096V  1 bit = 2mV
  //ads.setGain(GAIN_TWO);     // 2x gain   +/- 2.048V  1 bit = 1mV
  //ads.setGain(GAIN_FOUR);    // 4x gain   +/- 1.024V  1 bit = 0.5mV
  //ads.setGain(GAIN_EIGHT);   // 8x gain   +/- 0.512V  1 bit = 0.25mV
  //ads.setGain(GAIN_SIXTEEN); // 16x gain  +/- 0.256V  1 bit = 0.125mV
  //Start timers
  startMillis = millis();
  ledMillis = millis();
}

void commandESP32(char received){
  if(received == 't'){
    sensorEnabled = true;
    digitalWrite(LED,LOW);
  }
  if(received == 'f'){
    sensorEnabled = false;
    digitalWrite(LED,HIGH); 
    digitalWrite(RED,LOW);
    digitalWrite(IR,LOW); 
  }
  /*
  if(received == 'u'){
    usbSerialEnabled = true;
  }
  if(received == 'b') {
    usbSerialEnabled = false;
  }
  */
  delay(2000);
}

void setup() {
  Serial.begin(115200);
  
  pinMode(IR, OUTPUT);
  pinMode(RED, OUTPUT);
  //LOLIN32 ONLY
  pinMode(LED,OUTPUT);
  digitalWrite(LED,HIGH);

  //esp_bt_sleep_disable(); // Disables sleep mode (debugging)
  SerialBT.begin("My_HEG");
  BLEMillis = millis();
}

void core_program() {
  if(sensorEnabled == true) {
    if(adcEnabled == false) {
      startADS();
      adcEnabled = true;
    }
    
    if(SEND_DUMMY_VALUE != true) {
      currentMillis = millis();
          
      if(currentMillis - startMillis >= sampleRate) {
    
        // read the analog in value:
        adc0 = ads.readADC_SingleEnded(0);
        //Voltage = (adc0 * bits2mv);
        
        // print the results to the Serial Monitor:
        if (VIEW_ADC_VALUE == true) {
          //Serial.println("ADC Value: ");
          //Serial.println(adc0);
          //Serial.println("\tVoltage: "); 
          //Serial.println(Voltage,7);
        }
        if (DEBUG_ADC == false) {
          if(adc0 >= 7000) { // The gain is high but anything over 7000 is most likely not a valid signal, anything more than 2000 is not likely your body's signal.
            //Serial.println("\nBad Read ");
            badSignal = true;
      
            //Temp: reset baseline on bad read
            signalDetermined = false;
            baseline = 0;
      
            ticks0 = 0; // Reset counter
            ticks1 = 0;
            ticks2 = 0;
            redValue = 0; // Reset values
            irValue = 0;
          }
          else {
            badSignal = false;
            if(signalDetermined == false){
              ticks0++;
              if(ticks0 > 500) { // Wait for 500 samples of good signal before getting baseline
                // IR IN 12, RED IN 13
                if((ticks1 < 500) && (ticks2 < 500)) { // Accumulate samples for baseline
                  if(first_led == true) { // RED
                    redValue += adc0;
                    ticks1++;
                  }
                  else { // IR
                    irValue += adc0;
                    ticks2++;
                  }
                  //Serial.println("\nGetting Baseline. . .");
                }
                else {
                  signalDetermined = true;
                  redavg = redValue / ticks1;
                  iravg = irValue / ticks2;
      
                  baseline = redavg / iravg; // Set baseline ratio
                  ticks0 = 0; // Reset counters
                  ticks1 = 0;
                  ticks2 = 0;
                  redValue = 0; // Reset values
                  irValue = 0;
                  
                  //Uncomment this
                  //Serial.println("\tBaseline R: ");
                  //Serial.print(baseline,4);
                }
              }
            }
            else {
              ticks0++;
              if(first_led == true) { // RED
                redValue += adc0;
                ticks1++;
              }
              else { // IR
                irValue += adc0;
                ticks2++;
              }
              if((ticks2 > samplesPerRatio) && (ticks1 > samplesPerRatio)) { // Accumulate 50 samples per LED before taking reading
                redavg = redValue / ticks1; // Divide value by number of samples accumulated
                //redavg = redAvg * 200 // Scalar multiplier to make changes more apparent
                iravg = irValue / ticks2;
                ratio = redavg / iravg; // Get ratio
                ratioAvg += ratio;
                
                p1 = p2;
                p2 = ratio - baseline; // Position
                posAvg += p2;
                
                //v1 = v2;
                //v2 = (p2 - p1) * ticks0 * 0.001; // Velocity in ms
                //velAvg += v2;
                
                //accel = (v2 - v1) * ticks0 * 0.001; // Acceleration in ms^2
                //accelAvg += accel;
                
                //score += ratio-baseline; // Simple scoring method
                //scoreAvg += score;
                
                ticks0 = 0; //Reset Counters
                ticks1 = 0;
                ticks2 = 0;
                ticks3++;
                redValue = 0; //Reset values to get next average
                irValue = 0;
                
              }
            }
          }
          
          startMillis = currentMillis;
        }
      }
    
      // Switch LEDs back and forth.
      // PUT IR IN 13, AND RED IN 12
      if(currentMillis - ledMillis >= ledRate) {
        if(first_led == false) {
          digitalWrite(RED,HIGH);
          digitalWrite(IR,LOW);
          first_led = true;
        }
        else {
          digitalWrite(RED,LOW);
          digitalWrite(IR,HIGH);
          first_led = false;
        }
        ledMillis = currentMillis;
      }
      
      adcAvg += adc0;
      ticks4++;
      
    }
  }
 //DEBUG
 if(DEBUG == true){
  Serial.println("Heap after core_program cycle: ");
  Serial.println(ESP.getFreeHeap());
 }
}

void bluetooth() {
  if(SerialBT.available()){
    received = SerialBT.read();
    Serial.println(received);
    SerialBT.println(received);
    commandESP32(received);
  }
  
  if(currentMillis - BLEMillis >= BTRate) { //SerialBT bitrate: ?/s. 100ms works, 50ms does cause hangups (which the LED flashes will reflect) - need better buffering.
      SerialBT.flush();
      if(SEND_DUMMY_VALUE != true) {
        if(ticks4 > 0) {
          adcAvg = adcAvg / ticks4;
          
          if(ticks3 > 0) {
            ratioAvg = ratioAvg / ticks3;
            posAvg = posAvg / ticks3;
            SerialBT.print(String(adcAvg,0) + "," + String(ratioAvg,4) + "," + String(posAvg,4)+"\r\n"); 
          }
          else {
            SerialBT.print(String(adcAvg,0) + ",WAIT\r\n");
          }
          
          ratioAvg = 0;
          posAvg = 0;
          adcAvg = 0;
          adc0 = 0;
          ticks3 = 0;
          ticks4 = 0;
          
          BLEMillis = currentMillis;
        }
      }
      else { 
        int rando = random(0,1000);
        SerialBT.print("DUMMY,"+String(rando)+"\r\n");   
        }
  }
  if(DEBUG == true){
    Serial.println("Heap after bluetooth() cycle: ");
    Serial.println(ESP.getFreeHeap());
  }
}

void loop() {
  if(SerialBT.hasClient() == true) {
    core_program();
    bluetooth();
    delay(1); //1 ms delay.
  }
}

Your wdt is triggered, that means it is not reset for about 2.5s it will halt your program, you can reset it using yield() which will also trigger any background processes that the ESP needs to run, Put that within any of you millis() timed loops, just before or after currentMilis=millis() should fix the issue.