arduino-libraries / ArduinoBLE

ArduinoBLE library for Arduino
GNU Lesser General Public License v2.1
307 stars 205 forks source link

Very high power consumption on Nano 33 IoT #246

Open baconcheese113 opened 2 years ago

baconcheese113 commented 2 years ago

Using a blank sketch with just the following on my Nano 33 IoT:

void setup() {
  BLE.begin();
}
void loop() {
  // no-op
}

Is drawing 90mA. Without BLE.begin() it's 21mA, so the NINA chip requires 69mA to just be active (no scanning or advertising, although there wasn't a significant change in power consumption doing either). That means using ArduinoBLE will give the following life expectancies:

With this in mind, many users of this library are seeking a way to just power down the NINA module for a set period of time without changing anything about the currently configured GATT.

1) I have tried calling BLE.end(), however this resets the GATT and the program crashes when trying to add the services back with BLE.addService(myService) after a subsequent BLE.begin(). The event handlers fail to register with BLE.setEventHandler(BLEConnected, onBLEConnected) as well 2) I have tried calling digitalWrite(NINA_RESETN, LOW) and HIGH directly and this actually works nearly perfect, except the scan is unable to find anything after turning the module back on. But it can advertise and call event handlers without problems, and the GATT is populated how it was before shutting down.

I'm having a hard time finding a work around, since the ArduinoLowPower sleep function only shaves off 13mA. Do you have any insight how to turn on/off the module without breaking things?

baconcheese113 commented 2 years ago

An update:

I pursued my second method above and I think I've found a way to power down the NINA module and get the scan functionality when it's powered back up. This is great because the GATT is retained as well.

You can shut down the module (after having called BLE.begin()) with:

digitalWrite(NINA_RESETN, LOW);

and power it back up with:

digitalWrite(NINA_RESETN, HIGH);
delay(750); // this is what the existing implementation uses after starting

and to restore scan ability, I've found that this is the only line I need to call:

// #include "utility/HCI.h" if you need the import

HCI.setEventMask(0x3FFFFFFFFFFFFFFF);

Calling the BLE.begin() method triggers an HCI.begin() and HCI.reset() as well as a GATT.begin() which resets the GATT back to just defaults. I'm still investigating the side effects of not calling the other HCI methods from the BLE.begin() method. However it's working so far to both preserve my GATT and scan correctly. It's also important to note that there might be other differences for other boards.