Photon breaks if bad firmware is uploaded?

After uploading apparently bad firmware to a Photon, it appears to go into some broken state that I don’t see documented in the reference manual. It appears with a solid cyan (or white, can’t really tell) LED. I can recoup the Photon by performing a manual DFU update to the original firmware, but that is getting realllly tiresome while trying to develop new firmware. Also of note, there doesn’t appear to be anything wrong with the firmware according to the complier…it gives me the all-clear.

Is there another way around this? I’m afraid of sticking thousands of Photons/Electrons out and then having to manually fix every one of them if something goes wrong…

@hagandh, you can also recover a Photon by putting it in safe mode and then OTA new firmware to it.

Having a successful compilation does not guarantee your code will actually work correctly! Adding debugging Serial.print() lines and posting your code would allow us to help you a bit more. :wink:

1 Like

Ahh okay. Doesn’t safe mode have to be entered by pushing buttons though?

As for the code, the reason I’m having issues is because my C++ skills are roughly 500 times less than my python skills…

Mostly, using global variables in a way that I think should work, apparently doesn’t. i.e:

// Set up an instance of the OPCN2 class at CS
OPCN2 alpha(CS);

IntervalTimer runTimer;

int SAMPLE_FREQ = 10000 * 2;

// Set up an empty structure
PMData pm;

void setup(){
    Serial.begin(9600);
    while (alpha.on() != true){
        alpha.on();
        delay(1000);
    }

    if (alpha.firmware_version).toInt() >= 18){
        runTimer.begin(run_new_firmware, SAMPLE_FREQ, hmSec);
        }
}

void run_new_firmware(){
    pm = alpha.read_pm_data();
}

void loop(){

}

That’s the basic gist of the program…trying to use a timer to take 0.1 Hz measurements of a sensor…works great if the measurements are done in loop, but breaks if in the timing function. Ideas? I know it’s a simple c++ thing, but my googling skills have let me down.

@hagandh, can you point to code for the “OPCN2” class definition. Also, I believe you are using the (Arduino) IntervalTimer class which requires a call in loop() to refresh and operate correctly. You could possibly be using a Software Timer instead, depending on what alpah.read_pm_data() is doing. Can you post more of your code so I can look at your #include statements and the referred libraries?

Oh, and yes, safe mode requires that you push buttons.

Also, I’d consider using SYSTEM_THREAD(ENABLED). In the default system threading mode (disabled), anything in your code or libraries that you use that prevents the Particle cloud from being serviced will cause problems. The status LED will stop breathing cyan, cloud functions and variables will stop working, and over-the-air (OTA) firmware updates will fail. By enabling system thread mode, there’s less of a chance of interrupting cloud servicing, which makes it more likely you’ll be able to remotely flash new code.
https://docs.particle.io/reference/firmware/photon/#system-thread

1 Like

Here is the full code with libraries referenced. I believe I am using the correct library for the timer…

The read_pm_data method is reading from a hardware device that is connected to the photon/electron.
@rickkas7 I will try adding that now!

#include "opcn2/opcn2.h"
#include "SparkIntervalTimer/SparkIntervalTimer.h"

#define CS A2

// Set up the Instance of the OPC-N2
OPCN2 alpha(CS);

// Set up the timer
IntervalTimer runTimer;

// Set up the sampling frequency in ms
int SAMPLE_FREQ = 10000 * 2;

// Prepare the structure for gathering Data
PMData pm;
HistogramData hist;

void setup() {
    Serial.begin(9600);
    
    Serial.print("Firmware Version: "); Serial.println(alpha.firmware_version);
    
    delay(1000);
    
    while (alpha.on() != true){
        alpha.on();
        delay(1000);
    }
    
    // Set up the timer mechanism
    if ((alpha.firmware_version).toInt() >= 18){
        runTimer.begin(run_new_firmware, SAMPLE_FREQ, hmSec);
    }
    else {
        runTimer.begin(run_old_firmware, SAMPLE_FREQ, hmSec);
    }
}

void run_old_firmware() {
    // Read from the OPC
    Serial.println("Running old firmware...");
    //hist = alpha.histogram();
    
    //Serial.print("PM1: "); Serial.println(hist.pm1);
    //Serial.print("PM2.5: "); Serial.println(hist.pm25);
    //Serial.print("PM10: "); Serial.println(hist.pm10);

    //Particle.publish("PM1", String(hist.pm1), PRIVATE);
    //Particle.publish("PM2.5", String(hist.pm25), PRIVATE);
    //Particle.publish("PM10", String(hist.pm10), PRIVATE);
}

void run_new_firmware( void ) {
    // Read from the OPC
    pm = alpha.read_pm_data();
    
    Serial.println("\nNew Firmware");
    Serial.println(Time.timeStr());
    //Serial.print("PM1: "); Serial.println(pm.pm1);
    //Serial.print("PM2.5: "); Serial.println(pm.pm25);
    //Serial.print("PM10: "); Serial.println(pm.pm10);
    
    //Particle.publish("PM1", String(pm.pm1), PRIVATE);
    //Particle.publish("PM2.5", String(pm.pm25), PRIVATE);
    //Particle.publish("PM10", String(pm.pm10), PRIVATE);
}


void loop( void ) {

}

@hagandh, you are using SparkIntervalTimer to create you timed events I see. However, this library requires callback functions which are simple and quick since they are interrupt service routines. In your code, you call Particle.publish() ans Serial.print() which are not recommended for use in an ISR.

I suggest you consider using a non-blocking timer in loop() instead, which can then call the appropriate code without the constraints of an ISR. I would look like this:

//globals
// Set up the sampling frequency in ms
int SAMPLE_FREQ = 10000;

unsigned long runTimer;

setup() {
... other code
runTimer = millis() + SAMPLE_FREQ;
}

loop() {

  if (millis() >= runTimer) {
    // timer is up, run your sampling code here
    run_new_firmware();
    runTimer = millis() + SAMPLE_FREQ;  // reset timer
  }

  ... other loop code
}

Adding the code @rickkas7 recommended is also a great idea! :smiley:

Awesome. Thanks for the recommendations. Do you know of another library that would work like this? I used to use the SimpleTimer library on an Arduino that worked great. Otherwise, I could of course roll out my own solution…

@hagandh, I thought someone had ported the SimpleTimer library but it isn’t on the web IDE. I have another timer library you could use here. I’ll look at porting the SimpleTimer library later today.

Hey @peekay123 I was going to try to use the SimpleTimer library for the Photon. Since it has been a while since your last post, I wonder if there is something better more up to date for the Photon? Thanks for all your hard work and encouragement!!

@squeakywheel, you now have a choice of Software Timers (which use FreeRTOS timers), millis() timers (which is what SimpleTimer uses) or the SparkIntervalTimer library which uses hardware timers to generate timed interrupts. :wink:

Thanks for the :zap: fast response

Choices! I really just want to use something that will work out of the box with the least amount of configuration. Ideally, I could call it with a single line of code similar to timer.setInterval(100L, checkPhysicalButton);

What is your recommendation for something like that?

@squeakywheel, what do you want to do in the timer callback function(s)?

I want to check the physical state of the button and if it is high, then show that on my Blynk app and viceversa.

void checkPhysicalButton()
{
  if (digitalRead(btnPin) == LOW) {
  // btnState is used to avoid sequential toggles
  if (btnState != LOW) {

   // Toggle LED state
   ledState = !ledState;
   digitalWrite(ledPin, ledState);

   // Update Button Widget
   Blynk.virtualWrite(V2, ledState);
  }
   btnState = LOW;
  } 
  else {
   btnState = HIGH;
  }
}

How often do you want to call it?

Every 200 milliseconds to start.

You may be better served by:
a) Use a millis() timer in loop() which runs the sampling code every 200ms, or

b) Use SimpleTimer which is essentially a millis() timer with a callback, or

c) Use an interrupt to read/debounce your button and set a flag to read in loop() and do the Blynk stuff which shouldn’t go in the interrupt service routine.

1 Like

Hey @peekay123,
I found exactly what I was looking for! Check this out: https://docs.particle.io/reference/firmware/photon/#software-timers

This has a timer function built in! Perfect!!

@squeakywheel, SoftwareTimers may not be the best thing to use for the code you’ve posted above.
Since they are running on a FreeRTOS thread with very limited stack, the Blynk calls might cause issues.

Hence @peekay123 asked for your code after he mentioned them earlier but didn’t repeat this suggestion (I think)

But you may use his suggestion given for interrupts for SoftwareTimers just the same

1 Like