Firmware causes Photon to go offline

I have a Photon sensor that’s working fine with existing firmware but when I try to update it to a new, simplified version it crashes. Pretty new to this (and to C) so I am guessing there’s something obvious I am doing wrong, possibly in my timer setup?

PRODUCT_ID(268)
PRODUCT_VERSION(7)

// pin assignments
#define TRIGGER_PIN D4  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN    D5  // Arduino pin tied to echo pin on ping sensor.

void ping_level()
{
    // built-in https://docs.particle.io/reference/firmware/photon/#atomic_block-
    ATOMIC_BLOCK() {
        digitalWrite(TRIGGER_PIN, LOW);
        delayMicroseconds(2);
    
        digitalWrite(TRIGGER_PIN, HIGH);
        delayMicroseconds(10);
    
        digitalWrite(TRIGGER_PIN, LOW);
    
        // built-in https://docs.particle.io/reference/firmware/photon/#pulsein-
        double pingTime = pulseIn(ECHO_PIN, HIGH);
        double inches = pingTime / 2.0 / 73.746;
        Particle.publish("my_event_name", String::format("%.2f", inches));
    }
}

Timer timer(60 * 1000, ping_level);

void setup()
{
    Serial.begin(9600);
    timer.start();
}

What do you mean by “it crashes”? What behavior are you seeing on the device? What color/pattern is the LED showing?

For one I don’t see a pinMode() being set.
Two, if you want to be fast you can use pinSetFast(pin)/pinResetFast(pin) instead of digitalWrite(pin, HIGH/LOW)
Three, I’d put the Particle.publish() into loop() or and just set a flag inside the timer callback or at least put it out of the ATOMIC_BLOCK { }

1 Like

I tested your code, and my Photon disconnects, then reconnects after a few seconds, and that is due to the PRODUCT_ID and PRODUCT_VERSION lines at the top. I really don’t know what those are there for, and why they cause this error, but interestingly, after it comes back online (and I restart the serial monitor) it prints out the device’s id number, and not the results of the sensor (I’m testing by printing out “inches” rather than publishing).

These are for product creators to maintain their product and do things like fleet update.
Since it’s not your product, I’d say this won’t work too good for you.
https://docs.particle.io/guide/how-to-build-a-product/dashboard/#your-product-id

And if you made your device become someone elses product you might find it getting updated by someone else :wink:

What do you mean by "it crashes"?

It comes back up, turns blue and then green and kicks off a "Came online" event but then throws a "Went offline" event.

For one I don't see a pinMode() being set.

Ok, I see that in the docs and will correct that.

Two, if you want to be fast

I don't, this is the explicit timing they want based on prior firmware and the ATOMIC_BLOCK is needed as well.

that is due to the PRODUCT_ID and PRODUCT_VERSION lines at the top. I really don't know what those are there for

That's my confusion then: when I flashed my device with a prior version without those lines I saw an error in the device list saying there was an unidentified firmware version. Should I not be including those?

I'd say you do, since digitalWrite() adds extra time on your action and delayMicroseconds(2) will not be the only delay you see due to the extra time.
If you use the fast pin IO, the impact from that will reduce considerably and the pulse width will be closer to ... well ... 2µs.

Yes, for the timing critical part but not for the publishing, I'd say.

Are you a product creater and had this PRODUCT_ID assigned to you and linked this to the Dashboard?

1 Like

Ah, thanks for that. I'm probably making the mistake of assuming the prior developer had everything figured out :smile:

Yes, for the timing critical part but not for the publishing, I'd say.

Got it, good point.

Are you a product creater and had this PRODUCT_ID assigned to you and linked this to the Dashboard?

Yes, thanks for checking on that.

Does this look better (and can I get away with dot releases in my PRODUCT_VERSION)?

PRODUCT_ID(268)
PRODUCT_VERSION(7.1)

// pin assignments
#define TRIGGER_PIN D4  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN    D5  // Arduino pin tied to echo pin on ping sensor.

void ping_level()
{
    // built-in https://docs.particle.io/reference/firmware/photon/#atomic_block-
    ATOMIC_BLOCK() {
        pinSetFast(TRIGGER_PIN);
        pinResetFast(TRIGGER_PIN);
    }
    // built-in https://docs.particle.io/reference/firmware/photon/#pulsein-
    double pingTime = pulseIn(ECHO_PIN, HIGH);
    double inches = pingTime / 2.0 / 73.746;
    Particle.publish("fuel_level_inches", String::format("%.2f", inches));
}

Timer timer(60 * 1000, ping_level);

void setup()
{
    Serial.begin(9600);
    pinMode(TRIGGER_PIN, INPUT);
    pinMode(ECHO_PIN, OUTPUT);
    timer.start();
}

I assume you’re using an HC-SR04. You don’t really need that 2 us delay in your code. You might want to put a digitalWrite(TRIGGER_PIN, LOW) in setup, just to make sure it’s low at startup, but after that, the pin is already low after your high pulse (so it’s actually low for one minute given your current timer setup). The HIGH pulse needs to be at lest 10 microseconds, so that timing is noncritical either (I usually use 15 in my code).

The code you just posted won’t work, because you need the high pulse to be at least 10 us. This code works fine,

#define TRIGGER_PIN D4  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN    D5  // Arduino pin tied to echo pin on ping sensor.

Timer timer(2 * 1000, ping_level);

void setup() {
    pinMode(ECHO_PIN, INPUT);
    pinMode(TRIGGER_PIN, OUTPUT);
    digitalWrite(TRIGGER_PIN, LOW);
    Serial.begin(9600);
    timer.start();
}


void ping_level() {
    // built-in https://docs.particle.io/reference/firmware/photon/#atomic_block-
    ATOMIC_BLOCK() {
        digitalWrite(TRIGGER_PIN, HIGH);
        delayMicroseconds(10);
    
        digitalWrite(TRIGGER_PIN, LOW);
    
        // built-in https://docs.particle.io/reference/firmware/photon/#pulsein-
        double pingTime = pulseIn(ECHO_PIN, HIGH);
        double inches = pingTime / 2.0 / 73.746;
        //Particle.publish("my_event_name", String::format("%.2f", inches));
        Serial.println(inches);
    }
}
2 Likes

I actually rather thought of something like that

// pin assignments
const int TRIGGER_PIN D4  // Arduino pin tied to trigger pin on ping sensor.
const int ECHO_PIN    D5  // Arduino pin tied to echo pin on ping sensor.

void ping_level()
{
    // built-in https://docs.particle.io/reference/firmware/photon/#atomic_block-
    ATOMIC_BLOCK() {
        pinSetFast(TRIGGER_PIN);   // get as close as you can to 4µs periode
        delayMicroseconds(2); 
        pinResetFast(TRIGGER_PIN);
        delayMicroseconds(2); 
        pinResetFast(TRIGGER_PIN);
        
        // built-in https://docs.particle.io/reference/firmware/photon/#pulsein-
        double pingTime = pulseIn(ECHO_PIN, HIGH);  // pulseIn is also time critical (if you need the precision)
    }
    double inches = pingTime / 147.492;             // while this isn't (but one div is quicker than two)
    Particle.publish("fuel_level_inches", String::format("%.2f", inches));
}


Timer timer(60 * 1000, ping_level);

void setup()
{
    Serial.begin(9600);
    pinMode(TRIGGER_PIN, OUTPUT);  // why did you have this as INPUT???
    pinMode(ECHO_PIN, INPUT);      // and OUTPUT here
    timer.start();
}

I’d say PRODUCT_VERSION is supposed to be an integer and if you want releases you’d do something like 007001.


@Ric’s input is good value too, if you are using the sensor he’s mentioned.

1 Like

Great, thanks so much guys!

Looks basically the same as what we are using, so thanks for the updated code.

I’ve updated the code per the suggestions here but am still having a similar problem: I never see my event. The Photon now restarts properly and shows the updated firmware version in the device list but it never publishes. I think my main problem is a bad assumption: I thought my small bit of code would piggy-back on the Tinker firmware but it looks like it replaces it. The prior dev (who is no longer available) had written a much larger set of files in the desktop IDE that looked like total overkill but I’m now wondering if that was down to my misunderstanding.

Possibly related: I’ve since flashed the device to reset it to our current firmware. That firmware is running on another device which is happily publishing the old event but though my device shows as online and locked to the same firmware as the healthy device, mine is not publishing the event from the old firmware either.

When you flash an “app” or user firmware to your device, it completely replaces the previous “app”/user firmware. So Tinker is gone when you flash your code.

On a modern devices like Photon and Electron, the system firmware remains the same when flashing user firmware unless you choose to upgrade. On the older Core device, the entire firmware, system and user, is replaced when flashing.

Is there an easy way to extend the Tinker firmware by including it or do I need to build from scratch?

Hi @tclancy

You can grab the source for Tinker from the Particle/Spark github and modify it to meet your needs.

Be sure to remove these two lines:

PRODUCT_ID(PLATFORM_ID);
PRODUCT_VERSION(2);
2 Likes

Awesome, thanks so much. I’m sure that was obvious but I was missing it.