12-12-2021 08:21 PM
Hi,
I've hit an issue I'm unable to solve whereby after deep sleeping my ESP32 and saving and loading state with RTC memory or after a manual reset using EEPROM as per the Arduino example basic_config_state.ino, my callback is not being invoked until I execute Bsec2::run() for a second time after deep sleeping. This means I have to I have to wait either 3s or 300s depending on BSEC_SAMPLE_RATE_* at full power or at least light sleep before getting a reading and returning to deep sleep.
It seems after deep sleeping even when loading in the previous state from EEPROM the next call time remains zero. Please see the image I've attached for detailed logging of this happening in my application.
All subsequent calls are fine and outputs look correct. Thus I can only assume there is a bug in the bsec_set_state() function that is not initialising the libraries state fully until a second call is made to Bsec2::run().
Furthermore, to actually get deep sleep working I've had to add back in missing functionality to the API from BSEC 1.0:
/**
* @brief Constructor
*/
Bsec::Bsec()
{
nextCall = 0;
...
That provided public access to when the "nextCall" is available. This is missing in both the downloadable and the github version of BSEC 2.0 library so I added a getter for it (in the downloaded version I'm using):
/**
* @brief Function to return the time when the algorithm has to be called next in ms
*/
int64_t Bsec::getNextTime(void)
{
return _bsec_bme_settings.next_call / INT64_C(1000000);
}
Any help with this issue would be greatly appreciated.
Thanks in advance.
Solved! Go to Solution.
12-13-2021 07:32 AM
Hello iamdjango,
Could you provide you source code to review?
12-13-2021 02:21 PM - edited 12-13-2021 03:03 PM
Hi BSTRobin,
You can run the basic_config_state.ino example and see the issue I describe. For your convenience I've edited the example and attached it in the context of my setup. Between the following:
...
BSEC next call time: 0ms
BSEC next call time: 3113ms
...
should be the output from the callback but there is nothing. The first invocation of bsecInst.run() does not invoke the callback thus deep sleeping, without wasting power until the first callback, is not possible as no values will every be returned from the sensor. Instead we have to wait for the LP or ULP interval from ESP_RST_POWERON, ESP_RST_DEEPSLEEP, etc. before we get the first output:
...
BSEC next call time: 3113ms
bsecInst.run() invocations:1
BSEC outputs:
timestamp = 3114
iaq = 27.09
iaq accuracy = 0
static iaq = 28.00
co2 eq = 512.01
voc eq = 0.52
temperature = 24.66
pressure = 101028.48
humidity = 42.93
gas resistance = 69584.13
compensated temperature = 24.66
compensated humidity = 38.93
Thank you again for looking at the issue.
12-14-2021 08:21 PM - edited 12-14-2021 08:25 PM
Hi again,
I've been doing further testing within bme68x.c and have further insight into my problem:
Bsec::run() [bsec.cpp] -> bme68x_get_data() [bme68x.c] -> read_field_data() [bme68x.c]
does not return any results and thus my callback is not called. I can only assume because the sensor is not ready. Looking through the code I can see that read_field_data() tries 5 times waiting 10ms each time before returning to bme68x_get_data() which sets the returned result to BME68X_W_NO_NEW_DATA. If I alter the number of retries to 25:
/* This internal API is used to read a single data of the sensor */
static int8_t read_field_data(uint8_t index, struct bme68x_data *data, struct bme68x_dev *dev)
...
uint8_t tries = 25; // Was 5
...
while ((tries) && (rslt == BME68X_OK))
{
...
if (rslt == BME68X_OK)
{
dev->delay_us(BME68X_PERIOD_POLL, dev->intf_ptr); // TODO: Increase period to ~240ms for this function only so less wakeups from light sleep?
}
tries--;
}
read_field_data() returns with BME68X_NEW_DATA_MSK and we get:
BSEC outputs:
timestamp = 114
iaq = 30.01
iaq accuracy = 0
static iaq = 33.45
co2 eq = 533.80
voc eq = 0.57
temperature = 24.58
pressure = 101232.21
humidity = 48.54
gas resistance = 13742.75
compensated temperature = 24.58
compensated humidity = 45.68
The timestamp is now at 114ms after 20 retries or ~240ms of waiting. I can thus get a single reading and go straight back to deep sleep without having to wait for one sample rate period (3/300s). I assume this is the sleep stipulation in the BME688 Integration Guide:
"Typical durations for the "Sleep until measurement is finished" are 0.190 seconds for LP mode and 2 seconds for ULP mode"
I think this is a bug in the BME68x-Sensor-API and wasn't account for in the interface before my change to the number of retries. The only problem in making this minor change is that ever subsequent call to read_field_data() also has to retry for ~240ms before getting a reading from the device, while previously no retries were needed if the first call to run() returned nothing. I'm not sure why that is, any ideas? Anyway, the power consumption of waiting can be mitigated by hard coding a period of 240ms in the call to dev->delay_us().
I hope others find this post useful as I've wasted a lot of time debugging this issue!
07-03-2022 08:05 PM