I have a Nano 33 BLE which I plan to use in a remote sensor. Low power operation is very important - I'd like it to go many months between battery changes. I should be able to accomplish this by having the board in a deep-sleep state for much of the time, waking up periodically to send data. I made the following simple sketch to test the low-power performance of this board:
// Low power blink
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(D2, INPUT_PULLUP);
digitalWrite(LED_PWR,LOW); // keep Power LED off
pinMode(PIN_ENABLE_SENSORS_3V3, OUTPUT);
pinMode(PIN_ENABLE_I2C_PULLUP, OUTPUT);
digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW); // turn off sensors
digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);
}
void loop() {
// flash LED
digitalWrite(LED_BUILTIN, HIGH);
delay(20);
digitalWrite(LED_BUILTIN, LOW);
delay(2000);
}
This sketch just turns the built-in LED on for 20ms, then off for 2s, repeating this cycle. I find that during the off phase, current draw is only 3 microamps, which is great - just what I'm looking for. It proves that during a delay(), the chip can go into a true deep-sleep mode. Note that I cut the jumper which makes it possible to power the board from an external 3.3v supply, and that's what I'm doing. I also disconnected the USB and pressed reset before the current measurement.
But, what I really need is to be able to do this from a sketch that has BLE code and functionality. Consider this sketch:
#include <ArduinoBLE.h>
// BLE Service
BLEService Service1("BA45889A-FC12-2298-33D4-2EE6554A90B0");
// BLE Characteristics
BLEByteCharacteristic count("BA45889A-FC12-2298-33D4-2EE6554A90BC", BLERead | BLENotify);
BLEBooleanCharacteristic ccbit("BA45889A-FC12-2298-33D4-2EE6554A90BD", BLERead | BLENotify);
BLEIntCharacteristic ca1in("BA45889A-FC12-2298-33D4-2EE6554A90BE", BLERead | BLENotify);
byte cntr = 0;
boolean cbit = 0;
int a1in = 0;
boolean f1 = 0;
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected
pinMode(D2, INPUT_PULLUP);
digitalWrite(LED_PWR,LOW); // keep Power LED off
pinMode(PIN_ENABLE_SENSORS_3V3, OUTPUT);
pinMode(PIN_ENABLE_I2C_PULLUP, OUTPUT);
digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW); // turn off sensors
digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);
}
void loop() {
// begin initialization
digitalWrite(LED_BUILTIN, HIGH);
if (!BLE.begin()) {
while (1);
}
// Set a local name for the BLE device
BLE.setLocalName("Nano33BLE1");
BLE.setAdvertisedService(Service1); // add the service UUID
Service1.addCharacteristic(count);
Service1.addCharacteristic(ccbit);
Service1.addCharacteristic(ca1in);
BLE.addService(Service1); // Add the service
// start advertising
digitalWrite(LED_BUILTIN, LOW);
BLE.advertise();
// wait for connection
f1 = 1;
while (f1) {
BLEDevice central = BLE.central(); // believe this is a declaration of local variable "central"
// BLE.central() means query the central BLE device connected. Returns BLE device representing the central.
if (central) { // if central now connected
// do variable checks as long as central is connected
while (central.connected()) { // while central connected
// bleDevice.connected means query if a BLE device is connected. Returns true if connected.
digitalWrite(LED_BUILTIN, HIGH);
delay(20);
digitalWrite(LED_BUILTIN, LOW); // flash LED
cntr = cntr + 1;
cbit = digitalRead(D2);
a1in = analogRead(A1);
count.writeValue(cntr);
ccbit.writeValue(cbit);
ca1in.writeValue(a1in);
delay(2000);
}
// when central disconnects
BLE.end();
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW); // turn off sensors
digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);
delay(15000);
f1 = 0;
}
}
}
Looking near the bottom, under "when central disconnects", notice the BLE.end() line. When this wasn't included, I got current draw of about 1.4mA during the 15s wait caused by delay(15000). I hoped that BLE.end() would shut off BLE and make deep sleep possible, but current draw with that line included was 0.6mA, more than I want. Another problem is that after that, it should loop back to the top of loop() and again execute BLE.begin. BLE should restart and advertising should start again. Instead, BLE.begin fails. I know that because the LED is on solid while it loops because of the while(1). It's as if BLE.begin can't be called more than once in a program. Is that true?
In other sketches, I've tried doing NRF_POWER->SYSTEMOFF = 1. That also puts the board in a very low-power state. A problem is that there apparently isn't a way to wake from this using timing. Another is that if I wanted to wake from this state using an I/O pin transition, I'd need to know exactly how to specify what pin I plan to use and whether it happens on the rising or falling edge. I'd also need to know where in my sketch to put this code.
So, my overall question is how to go into a deep sleep state from a sketch that includes working BLE code, and how to wake from that using timing or a pin transition.
Thanks