Boron - Sleep 2.0 Examples and Power Savings

Now that deviceOS@1.5.0 is (almost?) here, I have been working to field my first Boron based devices.

First, I build a new carrier board and shared the results here:

Then, I started posting my main counting application over. The biggest adjustment in this effort has been working on low power / sleep. As you all know, the Boron - unlike the Electron - does not have a Real Time Clock. So, I added one to the carrier board based on @rickkas7’s awesome MCP79410RK library and circuit design to control the EN or WKP pin (see carrier board thread).

I started to get overwhelmed by the different ways that the Boron could sleep so, I thought it might be helpful to write a sketch that explored all the different sleep modes and use it to both share what is working and see if anyone can help on the one mode that is not.

The idea is that this sketch runs through five different sleep modes and provides a running tally on successful tests.

Here are the main learnings:

  • The System.sleep seems to add a second to the sleep time - not a big deal but a bit surprising
  • The Wake on interrupt RISING and FALLING won’t work if you are using a debounced switch. However CHANGE does work. I suspect all would work fine with a digital pin from another device.
  • I cannot get the ENABLE pin sleep to work with @rickkas7’s library and circuit. I am quite sure I am doing something wrong but any help here would be appreciated.

Once I get everything working, I plan to measure current draw for each mode.

As always, I hope this is helpful and I would appreciate any comments / suggestions.

Thanks, Chip

I found a couple errors in my circuit which are now fixed. With this, I have been able to complete my sleep testing including the following:

  1. Basic Sleep - Stop Mode
  2. RTC Alarm - Not really sleep but needed to test
  3. Sleep until hardware interrupt
  4. Deep Sleep with RTC Wake on D8
  5. Power Off Sleep - With Enable pin with RTC Wake

I have updated the repo with the new code and here is the revised schematic.

Please take a look and let me know if you have any questions.

Next up, rewrite with Sleep 2.0 that is part of deviceOS@1.5.0

Thanks, Chip

@All, In order to test the power savings, I have created a sketch that uses a coulomb counter connected to a Photon / Argon to monitor the Boron which is sleeping.

Here is a first pass at this code which I will use to determine the current consumption in three different sleep modes (STOP, HIBERNATE, and ENABLE) and in two configurations (Bare Boron and Boron in Carrier).

More to come but wanted to share the code I will be using to test:

Comments / Criticisms / Suggestions welcome!

Thanks,

Chip

1 Like

@all, Here are my initial results. Please take a look and let me know if my approach makes sense. I have built a fairly flexible engine to allow for iteration. So, please take a look and let me know your thoughts.

Here is the code I am using for the Sleep Test cases. You can set the duration and the sleep mode (see below). The test kicks off 5 seconds later and the coulomb counter is triggered when the D7 light goes off. Then the coulomb counter provides a running average of up to 10 coulombs for the calculation.

For the Bare Boron Use Case:

  • Test 0 - STOP mode sleep with network keep alive
        config.mode(SystemSleepMode::STOP)
          .duration(testDurationSeconds * 1000)
          .network(NETWORK_INTERFACE_CELLULAR);
  • Test 0 - Average Current - 12.80mA

  • Test 1 - STOP mode sleep without network keep alive

        config.mode(SystemSleepMode::STOP)
          .duration(testDurationSeconds * 1000);
  • Test 1 - Average Current - 10.77mA

  • Test 2 - Hibernate mode sleep with user button wake

        config.mode(SystemSleepMode::HIBERNATE)
          .gpio(userSwitch,FALLING);
  • Test 2 - Average Current - 10.240mA

  • Test 3 - Enable Pin Sleep with user button wake
    In This mode, we simply hold the Enable Pin low as there is no RTC to wake the device (that comes next with the carrier board tests).

  • Test 3 - Average Current - In progress - coulombs are coming very slowly. Will update when I have something.

Please let me know if you are interested in other test cases. One thing is clear - not much different between STOP mode and HIBERNATE sleep so not having a RTC like the Electron does not seem to be a big deal here.

Thanks,

Chip

2 Likes

So 10mA is the lowest your seeing in all the modes?

Were you able to see uA sleep currents with just the Boron?

@chipmc, something seems fishy w/ the 10’s and 12’s mA demands in Sleep Mode.

@RWB,

All these tests were done with a bare Boron - no extra parts. The lowest power consumption would be with the “Enable” sleep but I am still running that test.

Here is my test setup.

Thanks,

Chip

@Rftop,

Please take a look at my sketch which has no hardware requirements other than a button to wake from HIBERNATE sleep. If I am missing something, I would appreciate the help.

One question is whether I need to go through the whole Cellular.OFF() bit in the new model.

Thanks,

Chip

I just cheat and use Manual Mode for initial testing.

I just updated a Boron LTE to 1.5.0 final.
Measuring the Sleep Current with a µCurrent GOLD, I don’t see any changes from the same tests on 1.5.0-rc1.
About 660 µA is the best I get, nothing close to the ~150 µA that was previously mentioned for 1.5.0 final. I must be missing a step.

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

inline void softDelay(uint32_t t) {
  for (uint32_t ms = millis(); millis() - ms < t; Particle.process());  //  safer than a delay()
}

 SystemSleepConfiguration config;

void setup() {

// Pick a Sleep Mode                                                                    Li-Po @ 4.08V ,  Final Release 1.5.0 
//   config.mode(SystemSleepMode::STOP).gpio(D0, RISING).duration(30s);                 //  1.128 mA
//   config.mode(SystemSleepMode::HIBERNATE).gpio(D0, RISING).gpio(WKP, RISING);        //  0.663 mA   
//   config.mode(SystemSleepMode::STOP).duration(30s);                                  //  1.127 mA

}

void loop() {
  softDelay(15000);    // wait 15 seconds before Sleep.
  System.sleep(config);  
}

@Rftop,

Your example was not connected to Particle correct? I will do more checking on my end as I like your numbers better.

Thanks, Chip

Correct, just Manual Mode and I never call for the Modem to fire up…for initial testing.

We are still missing out on something important for Sleep 2.0, because theses numbers aren’t near the goal.

2 Likes

@avtolstoy @rickkas7

Can you show me where this was quoted Rftop? It would dramatically change my setup if we could get down to 150uA.

Frankly im a little disappointed in the devs. The nRF52 chip is able to sleep with 1uA with RTC. whats going on here.

Im also only able to get down to 660uA using Sleep2.0. I cant figure out how to get it lower. Im using just a bare boron with no other things attached to it.

1 Like

I wonder who we should ask about this high sleep current readings??

I was excited to see the progress towards lower sleeping current options.

@jack4566 @RWB @wesner0019 The sleep current is still higher than expected. The modem is not shutting down properly - this is being treated as high priority by the Engineering team.

You can get it down quite a bit but is still requires jumping through a few hoops. I’ve personally seen 160 uA on a Boron, so it is possible.
Manual Mode is required and in some cases you need to explicitly turn off the modem.

@no1089,

That would explain the difference between my readings and @Rftop but still leaves some gap between his readings and the expected results.

In my current code, I am using a sequence to help ensure the cellular modem is shut down. I believe this code was originally provided by @rickkas7

bool disconnectFromParticle()                                     // Ensures we disconnect cleanly from Particle
{
  Particle.disconnect();
  waitFor(notConnected, 15000);                                   // make sure before turning off the cellular modem
  Cellular.off();
  delay(2000);                                                    // Bummer but only should happen once an hour
  return true;
}

I was hoping we would not have to do this anymore but, could it be an interim fix? I will do some testing to see if it helps in my connected sketch.

Thanks,

Chip

1 Like

Chipmc you could probably replace your last delay with a _WFE loop to get a smidge more power savings.

1 Like

Any insight into what those hoops are and how one should jump through them would be greatly appreciated.

Yes, sorry this took a while.
I tested this over the weekend, and I am getting a consistent reading of 0.00013A/130uA as shown in the screenshot.


SYSTEM_MODE(MANUAL);

void setup()
{
}

void loop()
{
delay (5000);
powerModemOff(); // See the patch.
SystemSleepConfiguration config;
  config.mode(SystemSleepMode::STOP) 
  .gpio(WKP, RISING) 
  .duration(600s); 
System.sleep(config);
}

bool waitModemPowerOff()
{
    // Verify that the modem was powered down by checking the VINT pin up to 10 sec
 bool powerGood;
 for (unsigned i = 0; i < 100; i++) {
        powerGood = digitalRead(UBVINT);
 if (!powerGood) {
 break;
        }
 delay(100);
    }
 return !powerGood;
}

bool powerModemOff() {
 // Delay enough time to make sure pppncp thread has handled all events.
 delay(20000);
    // Important! We need to disable voltage translator here
    // otherwise V_INT will never go low
 digitalWrite(BUFEN, 1);
    // Low pulse 1.5s+ on UBPWR pin
    // IMPORTANT: SARA R4-based devices need to be using the latest firmware,
    // otherwise shutdown may need to be postponed by at least 30 seconds.
    // Affected version: L0.0.00.00.05.06,A.02.00
 digitalWrite(UBPWR, 0);
 delay(1600);
 digitalWrite(UBPWR, 1);
    // Wait for it to power off again
    bool poweredOff = waitModemPowerOff();
 if (!poweredOff) {
        Log.error("Modem failed to power off explicitly via shutdown sequence");
    }
    // Just in case explicitly disable voltage translator once again
 digitalWrite(BUFEN, 1);
#if PLATFORM_ID == PLATFORM_BORON
    // Do not leak current through antenna switch
 pinMode(ANTSW1, INPUT);
#endif // PLATFORM_ID == PLATFORM_BORON
    // Just in case disable Serial2 connected to the modem
 HAL_USART_End(HAL_USART_SERIAL2);
 return poweredOff;
}

1 Like