I’m using the Boron LTE-M Cat1 variant with an external sim card (deviceOS 2.2.0). Following the firmware code of AN028 and AN029, I’m putting the Boron in ULTRA_LOW_POWER mode. Upon wake-up from a timer alarm, I do a reset to the device.
The problem I’m facing is that the current consumption is too high in sleep mode. I’m measuring around 97 mA. For me that probably means that a high consumer is on, such as the modem. However, as you can see in the code below, I’m disconnecting from the network and turning-off the modem before going to sleep.
Nothing is connected to the Boron, except an external power supply at 3.3V to the Li+ pin.
Any suggestions of what to try or any ideas about why is it happening?
/*
* Project DHI_WRM_PoCDemo_VegetationCamera
* Description:
* Author: NIAG
* Date: 27-10-2021
*/
#include <Particle.h>
// Don't wait for cloud connection to run the code
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);
// This is the maximum amount of time to wait for the cloud to be connected in
// milliseconds. This should be at least 5 minutes. If you set this limit shorter,
// on Gen 2 devices the modem may not get power cycled which may help with reconnection.
const std::chrono::milliseconds connectMaxTime = 6min;
// This is the minimum amount of time to stay connected to the cloud. You can set this
// to zero and the device will sleep as fast as possible, however you may not get
// firmware updates and device diagnostics won't go out all of the time. Setting this
// to 10 seconds is typically a good value to use for getting updates.
const std::chrono::milliseconds cloudMinTime = 10s;
// How long to sleep
const std::chrono::seconds sleepTimeNormal = 1min;//24h;
// How long to sleep (short duration, after error)
const std::chrono::seconds sleepTimeShort = 5min;
// Maximum amount of time to wait for a user firmware download in milliseconds
// before giving up and just going back to sleep
const std::chrono::milliseconds firmwareUpdateMaxTime = 5min;
// How often to publish device diagnostics (vitals). If you set this
// equal to the sleep period they'll be sent on every connection, or you can set
// it higher to save data. For example, if you set it to 24 * 60 * 60 it would
// only publish once per day.
const std::chrono::seconds diagnosticPublishTime = 24h;
// These are the states in the finite state machine, handled in loop()
enum State {
STATE_WAIT_CONNECTED = 0,
STATE_MQTT_WAIT_CONNECTED,
STATE_CAPTURE_PHOTO,
STATE_PUBLISH,
STATE_PRE_SLEEP,
STATE_SLEEP,
STATE_WAIT_DISCONNECTED,
STATE_FIRMWARE_UPDATE
};
State state = STATE_SLEEP;
unsigned long stateTime;
bool firmwareUpdateInProgress = false;
long lastFirmwareUpdateCheck = 0;
long lastDiagnosticsPublish = 0;
SystemSleepConfiguration sleepConfigNormal;
SystemSleepConfiguration sleepConfigShort;
enum SleepDuration {
SLEEP_DURATION_NORMAL = 0,
SLEEP_DURATION_SHORT
};
SleepDuration sleepDuration = SLEEP_DURATION_NORMAL;
// setup() runs once, when the device is first turned on.
void setup() {
/**
* Setup system sleep configuration
* Wake-up source is set to RTC
*/
sleepConfigNormal.mode(SystemSleepMode::ULTRA_LOW_POWER)
.duration(sleepTimeNormal);
sleepConfigShort.mode(SystemSleepMode::ULTRA_LOW_POWER)
.duration(sleepTimeShort);
// It's only necessary to turn cellular on and connect to the cloud. Stepping up
// one layer at a time with Cellular.connect() and wait for Cellular.ready() can
// be done but there's little advantage to doing so.
Cellular.on();
Particle.connect();
stateTime = millis();
}
// loop() runs over and over again, as quickly as it can execute.
void loop() {
switch(state) {
case STATE_WAIT_CONNECTED:
// Wait for the connection to the Particle cloud to complete
if (Particle.connected()) {
// Log.info("connected to the cloud in %lu ms", millis() - stateTime);
// state = STATE_PUBLISH;
// connect to the MQTT server (unique id by Time.now())
mqttClient.connect("sparkclient_" + String(Time.now()),"wrm","WRM_mosquitto_2021");
state = STATE_CAPTURE_PHOTO;
stateTime = millis();
}
else
if (millis() - stateTime >= connectMaxTime.count()) {
// Took too long to connect, go to sleep with shorter sleep period.
// Log.info("failed to connect, going to sleep");
sleepDuration = SLEEP_DURATION_SHORT;
state = STATE_SLEEP;
}
break;
case STATE_CAPTURE_PHOTO:
// capturePhoto();
delay(2000);
state = STATE_PUBLISH;
case STATE_PUBLISH:
// Read camera fifo in burst mode and send everything to the cloud
//if(!read_fifo_burst(myCAM))
//{
// Error: Either too big or empty buffer
//}
//Clear the capture done flag
//myCAM.clear_fifo_flag();
//if (millis() - stateTime < cloudMinTime.count()) {
// Log.info("waiting %lu ms before sleeping", cloudMinTime.count() - (millis() - stateTime));
// state = STATE_PRE_SLEEP;
//}
//else {
// state = STATE_SLEEP;
//}
Particle.disconnect();
state = STATE_WAIT_DISCONNECTED;
break;
case STATE_WAIT_DISCONNECTED:
if(Particle.disconnected())
{
Cellular.off();
while(Cellular.isOn())
{
delay(500);
}
state = STATE_SLEEP;
}
break;
case STATE_SLEEP:
delay(10000);
// TODO: put camera to low-power mode
// Go to sleep
if (sleepDuration == SLEEP_DURATION_SHORT)
{
// Log.info("going to sleep for %ld seconds", (long) sleepTimeShort.count());
System.sleep(sleepConfigShort);
}
else if (sleepDuration == SLEEP_DURATION_NORMAL)
{
// Log.info("going to sleep for %ld seconds", (long) sleepTimeNormal.count());
System.sleep(sleepConfigNormal);
}
// Log.info("woke from sleep");
// On wake-up, device will be reset
System.reset();
break;
}