P2 - Occasional SOS 4 bus fault when using DS2482 to read temperature from DS18B20

Alright, I am a novice at lambda functions in C++ and I'm ashamed to admit it but I can't figure out how to get the DS2482 library to work the way I want it to in order to read a DS18B20 temperature sensor on the P2 without an occasional SOS 4 - bus fault from occurring. @rickkas7 - Since it's your library I thought I'd tag you here to see if you can reproduce.

I originally asked the question here but that topic is closed so I'll follow-up with this new thread.

In this sample code provided in the library all works perfectly. Both publishes the event and logs the data to the serial line every 30 seconds. Although I did not let it run for hours and hours to see if it every has an issue yet.

#include "DS2482-RK.h"

SerialLogHandler logHandler;

DS2482 ds(Wire, 0);

const unsigned long CHECK_PERIOD = 30000;
unsigned long lastCheck = 5000 - CHECK_PERIOD;

void setup() {
	Serial.begin(9600);
	ds.setup();

	DS2482DeviceReset::run(ds, [](DS2482DeviceReset&, int status) {
		Serial.printlnf("deviceReset=%d", status);
	});

	Serial.println("setup complete");
}



void loop() {

	ds.loop();

	if (millis() - lastCheck >= CHECK_PERIOD) {
		lastCheck = millis();

		// For single-drop you can pass an empty address to get the temperature of the only
		// sensor on the 1-wire bus
		DS24821WireAddress addr;

		DS2482GetTemperatureCommand::run(ds, addr, [](DS2482GetTemperatureCommand&, int status, float tempC) {
			if (status == DS2482Command::RESULT_DONE) {
				char buf[32];
				snprintf(buf, sizeof(buf), "%.4f", tempC);

				Serial.printlnf("temperature=%s deg C", buf);
				Particle.publish("temperature", buf, PRIVATE);
			}
			else {
				Serial.printlnf("DS2482GetTemperatureCommand failed status=%d", status);
			}
		});
	}
}

However, what I really want to do is encapsulate this code in a Particle.function() or really just a normal C++ function for all that matters. 95 times out of 100 this works just fine, but then 5 out of 100 times (especially if I call the function repeatedly, I get a SOS code 4 - Bus Fault.

Is it something I'm not doing right with lambda functions or an issue with the DS2482 library? Anyone else get this working properly on a P2? The very last thing that gets printed before SOS is: Log.info("Attempting to Read Temperature");

Here is the function that gets called.

/*******************************************************************************
 * Function Name  : ReadTemp()
 * Description    : Reads the current temperature in degrees F
 * Return         : Degrees F
 *******************************************************************************/
int sensors::ReadTemp(String args){
    digitalWrite(VacPwr, LOW);

    Log.info("Attempting to Read Temperature");

    // For single-drop you can pass an empty address to get the temperature of the only
		// sensor on the 1-wire bus
		DS24821WireAddress addr;

    DS2482GetTemperatureCommand::run(ds, addr, [this](DS2482GetTemperatureCommand&, int status, float tempC) {
        if (status == DS2482Command::RESULT_DONE) {
            this->fahrenheit = (tempC*1.8+32.0)*10;
        }
        else {
            Log.error("DS2482GetTemperatureCommand failed status=%d", status);
        }
    });
    return fahrenheit;
 }

As of now, I'm going to let the program run all night and see how many times the SOS fault occurs (if it occurs) when the readings are spaced 5 minutes apart vs hammering it every 2-3 seconds.

It's not clear why the panic is occurring, but that code will definitely not work properly.

A C++11 lamba is just a shortcut for callback function that's declared inline instead of a separate function, and has the ability to capture variables for use in the callback without adding them as parameters.

The DS2482GetTemperatureCommand::run() method queues a request to get the temperature, and the lamba or callback is called asynchronously later with the results. The call is non-blocking and returns almost immediately.

Thus when the function handler returns fahrenheit it returns the last value, not the current one, because it hasn't been updated yet. The easiest solution is to periodically obtain the temperature and not try to query the sensor from a function call. At that point, you could just use a variable instead of function as well.

2 Likes

Alright, that makes a lot more sense... seems obvious now that you explain it that way. :slight_smile: Also when I called that function every 5 minutes the last 7 hours or so, it never did the SOS so must be something when hammering it. I shouldn't need to do that anyhow if I schedule it periodically in the background. Like your library example, I just read temperature every 30 seconds in the background and now I can hammer the read temperature particle function and it doesn't SOS.

Does this seem reasonable?

void sensors::loop() {
    // Put your code to run during the application thread loop here
    ds.loop();

    if (millis() - lastCheck >= CHECK_PERIOD) {
      lastCheck = millis();
      updateTemp();
    }
}

 /*******************************************************************************
 * Function Name  : updateTemp()
 * Description    : Reads the current temperature in degrees F through the DS2482 non-blocking library. Lambda funciton updates the variable. 
 * Return         : nothing
 *******************************************************************************/
void sensors::updateTemp(){
    
    // For single-drop you can pass an empty address to get the temperature of the only sensor on the 1-wire bus
		DS24821WireAddress addr;

    DS2482GetTemperatureCommand::run(ds, addr, [this](DS2482GetTemperatureCommand&, int status, float tempC) {
        if (status == DS2482Command::RESULT_DONE) {
            this->fahrenheit = (tempC*1.8+32.0)*10;
        }
        else {
            Log.error("DS2482GetTemperatureCommand failed status=%d", status);
        }
    });
 }

/*******************************************************************************
 * Function Name  : ReadTemp()
 * Description    : Reads the current temperature in degrees F from the variable that was updated by the lambda function.
 * Return         : Degrees F
 *******************************************************************************/
int sensors::ReadTemp(String args){
    return fahrenheit;
 }