Xenon - panic, hard_fault on very simple app ... why?

I’ve got my first, extremely simple, app that I pushed to a new Xenon. It’s running, but it’s throwing a “panic, hard_fault” on almost all of the Timer events.

int led1 = D0;
int led2 = D7;

// a simple loop counter ...
unsigned long counter;

// monitor the battery ... found here:  https://github.com/kennethlimcp/particle-examples/blob/master/vbatt-argon-boron/vbatt-argon-boron.ino
// official docs: https://docs.particle.io/reference/device-os/firmware#battery-voltage
  double voltage;

  Timer timer(60000, publishData);

void setup() {

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);

  pinMode(BATT, INPUT);

  Particle.variable("counter", counter);
  Particle.variable("battery", voltage);

  // publish the data right away ...
  publishData();

  // start the timer ...
  timer.start();

}

void loop() {
  // turn on the LEDs with some delay ...
  digitalWrite(led1, HIGH);
  delay(500);
  digitalWrite(led2, HIGH);
  delay(500);

  // turn them off with some delay ...
  digitalWrite(led1, LOW);
  delay(500);
  digitalWrite(led2, LOW);
  delay(500);

}

void publishData()
{
    counter++;

    voltage = analogRead(BATT) * 0.0011224;
        
    String guid = System.deviceID();
    String payload = String::format("{\"guid\":\"%s\",\"counter\":%lu,\"battery\":%4.3f}", guid.c_str(), counter, voltage);
    Particle.publish("sensorHeartbeat", payload, PRIVATE);

}

The app runs, and seems to work. It publishes just fine, but it seems on the Timer event, it is throwing the panic.

From the event log:

| sensorHeartbeat | {"guid":"e00fce68519e59efdc5fe36d","counter":1,"battery":4.078} | Xenon-mey | 9/17/19 at 10:03:00 pm |
| spark/device/diagnostics/update | {"device":{"system":{"uptime":7,"memory":{"total":161364,"used":72668}},"cloud":{"connection":{"status":1,"error":0,"attempts":1,"disconnect":0},"disconnects":0,"publish":{"rate_limited":0},"coap":{"unack":0}}},"service":{"device":{"status":"ok"},"coap":{"round_trip":140},"cloud":{"uptime":5,"publish":{"sent":2}}}} | Xenon-mey | 9/17/19 at 10:02:59 pm |
| particle/device/updates/forced | false | Xenon-mey | 9/17/19 at 10:02:54 pm |
| particle/device/updates/enabled | true | Xenon-mey | 9/17/19 at 10:02:54 pm |
| spark/device/last_reset | panic, hard_fault | Xenon-mey | 9/17/19 at 10:02:54 pm |
| sensorHeartbeat | {"guid":"e00fce68519e59efdc5fe36d","counter":1,"battery":4.083} | Xenon-mey | 9/17/19 at 10:01:42 pm |
| spark/device/diagnostics/update | {"device":{"system":{"uptime":1,"memory":{"total":161364,"used":72476}},"cloud":{"connection":{"status":1,"error":0,"attempts":1,"disconnect":0},"disconnects":0,"publish":{"rate_limited":0},"coap":{"unack":0}}},"service":{"device":{"status":"ok"},"coap":{"round_trip":257},"cloud":{"uptime":0,"publish":{"sent":2}}}} | Xenon-mey | 9/17/19 at 10:01:42 pm |
| particle/device/updates/forced | false | Xenon-mey | 9/17/19 at 10:01:41 pm |
| particle/device/updates/enabled | true | Xenon-mey | 9/17/19 at 10:01:41 pm |
| spark/device/last_reset | panic, hard_fault | Xenon-mey | 9/17/19 at 10:01:41 pm |

I’m not clear on what I’ve done incorrectly here?

Thoughts?

UPDATE: It will sometimes go for 3-5 minutes publishing ok WITHOUT doing the panic … and then it starts doing it again.

Particle.publish() is not safe to be called from a timer callback.

1 Like

Take a look at the library from Rick - PublishQueueAsyncRK.

You can call this from a timer callback handler function because it is only storing the event data in retained memory. It then handles sending the events at no more than 1/second and avoid hangs due to loss of cloud connection.

Thank you for the insight!

I was basing my code on the documentation that states:

The timer callback is similar to an interrupt - it shouldn't block. However, it is less restrictive than an interrupt. If the code does block, the system will not crash - the only consequence is that other software timers that should have triggered will be delayed until the blocking timer callback function returns.

I was willing to deal with the possible delay of my timers firing. What is interesting is that it is working fine on my Photon without a panic ... so I figured it would work the same on the Xenon.

Thank you for this reference also! It looks like @rickkas7 already solved this in an effective way! I'll have to give his library a try!

The PublishQueueAsyncRK library solved the issues I experienced on Gen3 devices, I was already using my own publish queue mechanism on the Photon but couldn’t implement this using an ethernet featherwing and a xenon because of the SPI and pin use by the ethernet. I would go with ScruffR’s immense knowledge of the device OS - I think it is due to shared resources, also the documentation has been carried over from Gen2 and doesn’t always capture all the little issues and restrictions on Gen3!

1 Like

Yes ... in reading through the forums I noticed that he has quite a long history with the products, and a LOT of knowledge beyond the documentation. :slight_smile:

I appreciate your assistance also!

I’m not entirely sure, but I’d think the very limited stack space that’s dedicated for the system timers thread would get exhausted by the “heavy” Particle.publish() function call and its internal call depth - possibly differeing considerably between platforms.

Although that should result in an SOS+13 panic something on the way might cause a SOS+1 hard fault prior to that condition.

1 Like