Fast red flashing light...what does that mean?

I am running a photon with neopixels and a Oled display.

After a day or so i get a flash red flashing light and a lockup. I added a isr timer to see if I could reset it but that doesn’t seem to run either

Any idea what the flashing error code means?

Does this look familiar?
Constant Fast flashing red LED fault after 24-48 hr uses

Try the suggestions there and check if any of that applies to your case

Forum search for “fast red would have brought this up

I did find that but it really didn’t have any solution. Still don’t know what conditions creates a fast red. I have added serial prints around each function to try to
narrow down where it dies.

This might be a starting point.
The OP nf the other thread never reported back so we could not help any further or some of the suggestions for his case did help and he just failed to tell the community which it was.

Since it's happening after a longish time, it's most likely some kind of overflow, mem-leak, connection loss issue or so.
The connection loss side you can test by cutting the connection from your router and the other things require a look at the code.

It is a communication error, but I was wondering why does it fall into that state when it can’t get to the internet. Granted it is some interaction with the Neopixel code in a thread that gets it to that state.

I can reproduce it by disabling my wifi, blocking the particle at the firewall and then enable the wifi.

But I was with the serial debugging able to get my ISR watchdog to work to reset it.

The program is here, I am throwing the kitchen sink at it because I wanted to see how stable it was before spending to much time on it, because arduino’s always seem to die at some point if there is any network code.

Is this the code I am getting? def_panic_codes(Faults,RGB_COLOR_RED,HardFault)

#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"

#include "neopixel.h"

#include "SparkTime.h"

#include "application.h"

#include "SparkIntervalTimer.h"

Thread* led1Thread;


// If using software SPI (the default case):
#define OLED_MOSI   D0
#define OLED_CLK    D1
#define OLED_DC     D2
#define OLED_CS     D3
#define OLED_RESET  D4
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

IntervalTimer myTimer;
IPAddress localIP;


 volatile unsigned long WatchDogCount = 0; // use volatile for variables shared with ISR


 SYSTEM_MODE(AUTOMATIC);


 // IMPORTANT: Set pixel COUNT, PIN and TYPE
 #define PIXEL_PIN D6
 #define PIXEL_COUNT 12
 #define PIXEL_TYPE WS2812

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);


UDP UDPClient;
SparkTime rtc;

TCPServer server = TCPServer(23);
TCPClient client;

char addr[32];
char incoming;

typedef struct {
    int pin;
    int delay;
} LED_PARAM;

// LED pins
int led1 = D5;
int led2 = D3;
int led3 = D1;

LED_PARAM ledParams[3] = {
    {led1, 20},
    {led2, 1000},
    {led3, 2000}
};

void rainbow_thread(void* param) {
  Serial.println("+rainbow_thread(void* param)");
  LED_PARAM *p = (LED_PARAM*)param;
  for(;;) {
    //Serial.println("Thread Parameters: ");
    //Serial.println(p->pin);
    //Serial.println(", ");
    //Serial.printlnln(p->delay);
    rainbow(20);
    delay(10);
  }
  //rainbow(20);
  Serial.println("-rainbow_thread(void* param)");
}


void rainbow(uint8_t wait) {
  Serial.println("+rainbow(uint8_t wait)");
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }

    // XXX DISABLE FOR NOW
    Serial.println("+strip.show();");
    strip.show();
    Serial.println("-strip.show();");

    delay(wait);
  }
  Serial.println("-rainbow(uint8_t wait)");
}

// 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) {
  //Serial.println("+Wheel(byte WheelPos)");
  if(WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  //Serial.println("-Wheel(byte WheelPos)");
}




void display_time(int aliveTicks) {
  Serial.println("+display_time()");

  unsigned long currentTime;
  char output[128];
  uint32_t freemem = System.freeMemory();

  currentTime = rtc.now();
  uint8_t min  = rtc.minute(currentTime);
  uint8_t hour = rtc.hour(currentTime);
  uint8_t sec = rtc.second(currentTime);


  display.clearDisplay();

  sprintf(output, "%02d:%02d:%02d", hour,min,sec);

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println(output);





  sprintf(output, "%d", aliveTicks);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,40);
  display.println(output);



  display.display();
  Serial.println("-display_time()");
}

void check_tcp() {
  Serial.println("+check_tcp()");


  client = server.available();


  if (client.connected()) {

    unsigned long currentTime;
    char output[128];

    currentTime = rtc.now();
    uint8_t min  = rtc.minute(currentTime);
    uint8_t hour = rtc.hour(currentTime);
    uint8_t sec = rtc.second(currentTime);

    sprintf(output, "%02d:%02d:%02d", hour,min,sec);

    client.println("Connected to Spark!");
    client.println(WiFi.localIP());
    client.println(WiFi.subnetMask());
    client.println(WiFi.gatewayIP());
    client.println(WiFi.SSID());
    client.println(output);
    client.stop();
    /*
    while (client.connected()) {
      while (client.available()) {

        incoming = client.read();
        client.write(incoming);  // great to show on telnet what has been printed
        //if (incoming == 'A'){   digitalWrite(D7, HIGH); }
        //if (incoming == 'B'){   digitalWrite(D7, LOW); }
      }

    }
    */

  }
  Serial.println("-check_tcp()");
}

void UpISR(void) {
    Serial.println("+UpISR(void) 205");
     char output[128];

     Serial.println("+UpISR(void) 208");
     if(System.updatesPending()) {
         myTimer.interrupt_SIT(INT_DISABLE); // Stop
         System.enableUpdates();
         display.clearDisplay();
         sprintf(output, ".UPDATING.");
         display.setTextSize(2);
         display.setTextColor(WHITE);
         display.setCursor(0,20);
         display.println(output);
         display.display();
         //delay(2000);




         Serial.println("+UpISR(void) 2224");
         return;
     }
     Serial.println("+UpISR(void) 227");

     WatchDogCount++; // increase when LED turns changes
     Serial.println(WatchDogCount);
     Serial.println("+UpISR(void) 230");
     if (WatchDogCount>100) {
       Serial.println("-UpISR(void) LOCKUP");
       System.reset();
     } else {
       sprintf(output, "%u", WatchDogCount);
     }
     Serial.println("+UpISR(void) 236");
     display.setTextSize(2);
     display.setTextColor(WHITE);
     display.setCursor(0,20);
     display.println(output);
     Serial.println("-UpISR(void) 241");

}

void setup() {
  Serial.println("+setup()");

  Serial.begin(9600);
  Serial.println("NO FORMAT");

  rtc.begin(&UDPClient, "north-america.pool.ntp.org");
  rtc.setTimeZone(-5);

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'


    // init display
    display.begin(SSD1306_SWITCHCAPVCC);
    display.clearDisplay();

    myTimer.begin(UpISR, 1000, hmSec);



    //display.setTextSize(1);
    //display.setTextColor(WHITE);
    //display.setCursor(0,0);
    //display.println("...");
    //display.println(":");
    //display.setTextSize(2);
    //display.setCursor(128 / 2 -(12 * 6) / 2, 32);
    //display.println("");
    //display.display();
    unsigned long currentTime;


    currentTime = rtc.nowNoUpdate();


      server.begin();
      IPAddress localIP = WiFi.localIP();
      sprintf(addr, "%u.%u.%u.%u", localIP[0], localIP[1], localIP[2], localIP[3]);
      if (Particle.connected()) {
        Particle.variable("Address", addr, STRING);
      }


  led1Thread = new Thread("RainbowLed", rainbow_thread,&ledParams[0]);

  System.disableUpdates(); // Update in the ISR

  Serial.println("-setup()");
}

int aliveTicks = 0;

void loop() {
    Serial.println("+loop()");

    //
    //display_time();
    //rainbow(20);
    WatchDogCount=0;


    display_time(aliveTicks);
    delay(200);
    aliveTicks=aliveTicks+1;



    if (Particle.connected()) {
      check_tcp();
      localIP = WiFi.localIP();
      sprintf(addr, "%u.%u.%u.%u %u", localIP[0], localIP[1], localIP[2], localIP[3],aliveTicks);
      Particle.variable("Address", addr, STRING);
    }



    Serial.println("-loop()");
}

if (Particle.connected()) {
      check_tcp();
      localIP = WiFi.localIP();
      sprintf(addr, "%u.%u.%u.%u %u", localIP[0], localIP[1], localIP[2], localIP[3],aliveTicks);
      Particle.variable("Address", addr, STRING);
    }

This is definetly something that has nothing to do in loop().
You can (should) place Particle.variable("Address", addr); in setup() independent of Particle.connected().
You only expose a Particle.variable() once. The updating of that variable is only done on the base variable and not by “re-exposing”.

BTW: SparkTime should not be neccessary anymore since the framework object Time should work just as good.
Look at Time.format() too.

I’d also keep some of the functionality of your UpISR out of there. The ISR should return as quick as possible and not use other functions which employ interrupts too.

I was just bit by this too. I have a photon that has a ping sensor to try to measure the water depth of a sump pump and a duel float switch (one to count each time the pump runs and the other to send alerts that the pump may have failed. I also threw on a DHT22 because…why not :smile: This was running non-stop for almost a month straight but this morning started doing the fast red flash. Could I get a code review :sweat: to see if I am doing something dumb or ways to optimize it?

Thanks for any help!

// This #include statement was automatically added by the Particle IDE.
#include "PietteTech_DHT/PietteTech_DHT.h"

double temp                         = 0;
double humidity                     = 0;

#define DHTTYPE  DHT22       // Sensor type DHT11/21/22/AM2301/AM2302
#define DHTPIN   5           // Digital pin for communications

void dht_wrapper(); // must be declared before the lib initialization

PietteTech_DHT DHT(DHTPIN, DHTTYPE, dht_wrapper);

#include "application.h"

double rssi = 0;

int well_depth = 20;
int water_depth = 0;

int pump_count_pin = 2;
int pump_warning_pin = 0;

int pump_count_status = 1;
int pump_warning_status = 1;

int pump_count_status_old = 1;
int pump_warning_status_old = 1;    

const int numReadings = 10;

int total = 0;                  // the running total
int average = 0;                // the average

Timer timer(600000, environmentPublish);

void setup() {

    Particle.variable("pe_temp", temp);
    Particle.variable("pe_humidity", humidity);
    Particle.variable("pe_depth", water_depth);

	pinMode(pump_count_pin, INPUT);
	pinMode(pump_warning_pin, INPUT);

    delay(1000);
    
    environmentPublish();

    delay(1000);

    timer.start();

    Particle.publish("eac_device", "Started", 60, PRIVATE);

    Particle.publish("End of setup");

}

void dht_wrapper() {
    DHT.isrCallback();
}

void loop() {

    pump_count_status = digitalRead(pump_count_pin);
    pump_warning_status = digitalRead(pump_warning_pin);

	/* Log When Pump Runs */ 

    if(pump_count_status != pump_count_status_old){
     
	   pump_count_status_old = pump_count_status;
       
       if(pump_count_status == 1){
 
            Particle.publish("librato_pump_e_run", String(pump_count_status), 60, PRIVATE);

            Particle.publish("eac_pump_e", "Pump Run", 60, PRIVATE);

	
       }
      
    } 


	/* Log When Pump Fails */ 
    if(pump_warning_status != pump_warning_status_old){
     
       pump_warning_status_old = pump_warning_status;
       
       if(pump_warning_status == 0){

            Particle.publish("eac_pump_e", "Pump Warning", 60, PRIVATE);
	
       }
    }

    delay(1000);
    
    
}

void ping(pin_t trig_pin, pin_t echo_pin, uint32_t wait, bool info) {

    total = 0;

    for(int i = 0;i < numReadings; i++){

        uint32_t duration, inches, cm;
        static bool init = false;
        if (!init) {
            pinMode(trig_pin, OUTPUT);
            digitalWriteFast(trig_pin, LOW);
            pinMode(echo_pin, INPUT);
            delay(50);
            init = true;
        }
    
        /* Trigger the sensor by sending a HIGH pulse of 10 or more microseconds */
        digitalWriteFast(trig_pin, HIGH);
        delayMicroseconds(10);
        digitalWriteFast(trig_pin, LOW);
      
        duration = pulseIn(echo_pin, HIGH);
        
        /* Convert the time into a distance */
        // Sound travels at 1130 ft/s (73.746 us/inch)
        // or 340 m/s (29 us/cm), out and back so divide by 2
        // Ref: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
        inches = duration / 74 / 2;
        cm = duration / 29 / 2;
        
        if(inches > well_depth){
            water_depth = 0;
        } else {
            water_depth = well_depth - inches;
        }    
    
        total = total + water_depth;
        
        delay(wait); // slow down the output
    }

    // calculate the average:
    average = total / numReadings;

    Particle.publish("pump_e_total_reading", String(total), 60, PRIVATE);

    Particle.publish("librato_pump_e_depth", String(average), 60, PRIVATE);
    
}

void environmentPublish(){
    
    DHT.acquireAndWait();

    delay(500);

    temp = DHT.getFahrenheit();
    humidity = DHT.getHumidity();
    
    if(temp == -4 && humidity == -4){
        delay(5000);
        
        DHT.acquireAndWait();
        
        delay(500);

        temp = DHT.getFahrenheit();
        humidity = DHT.getHumidity();
        
    }
    
    temp = round(temp*10)/10.0;
    humidity = round(humidity*10)/10.0;

    Particle.publish("librato_pump_e_temp", String(temp), 60, PRIVATE);
    Particle.publish("librato_pump_e_humidity", String(humidity), 60, PRIVATE);

    delay(1000);

    ping(D1, D6, 20, true);

    if(WiFi.ready()){
        rssi = WiFi.RSSI();
        Particle.publish("librato_pump_e_wifi_strength", String(rssi), 60, PRIVATE);
    }

}

Just a few side notes that might not address your problem but should be kept in mind non-the-less

  • #include "application.h" (or better it successor #include "Particle.h") should be put at the top of your sketch (e.g. #define DHTPIN D5 would give you grief in DHT(DHTPIN, DHTTYPE, dht_wrapper); - although using D# instead of just 5 would be recommended)
  • switches with one open state (as I assume your dual float switches are) should always get their pull-up/-down resistors (either via INPUT_PULLUP/INPUT_PULLDOWN) or external (which I don’t know if you have anyway)
  • in long running programs like yours I’d use a C string instead of String() wherever possible
  • instead of doing two divisions (e.g. duration / 74 / 2 use duration / 148) just do one, reduces time and increaces precision
  • wheneve doing divisions make sure the divisor never becomes zero (in your case due to const int no risk ;-))