Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cordio: lower power polling with timeout #15

Merged

Conversation

sandeepmistry
Copy link
Contributor

I've been testing this with the Examples -> Peripheral -> LEDCallback example, with two changes:

  1. Removing: while (!Serial); from setup()
  2. Changing BLE.poll(); in loop() to BLE.poll(60000);

Unfortunately, in my brief testing it doesn't seem to be lower power (using a USB supply input).

@facchinm any thoughts on this?

@sandeepmistry
Copy link
Contributor Author

sandeepmistry commented Sep 9, 2019

Ok, so I've done some more testing on this, setup is cutting the 3.3V pad on the back and supplying a direct 3.3V input.

This reference sketch, seems to consume ~0.93 mA:

void setup() {
  pinMode(LED_PWR, OUTPUT);
  digitalWrite(LED_PWR, LOW);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(60 * 1000);
}

With and without this patch, the following sketch is ~6.95 mA:

/*
  Callback LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED. The callback features of the
  library are used.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  Serial.begin(9600);
//  while (!Serial);


  pinMode(LED_PWR, OUTPUT);
  digitalWrite(LED_PWR, LOW);
  
  pinMode(ledPin, OUTPUT); // use the LED pin as an output

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("LEDCallback");
  // set the UUID for the service this peripheral advertises
  BLE.setAdvertisedService(ledService);

  BLE.setAdvertisingInterval(1600);

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);

  // start advertising
  BLE.advertise();

  Serial.println(("Bluetooth device active, waiting for connections..."));
}

void loop() {
  // poll for BLE events
  BLE.poll();
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.print("Characteristic event, written: ");

  if (switchCharacteristic.value()) {
    Serial.println("LED on");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, LOW);
  }
}

So I think the patch is fine to merge, but still think something in Cordio is consuming power.

cc/ @facchinm

@@ -103,6 +103,9 @@ extern "C" void wsf_mbed_ble_signal_event(void)
}
#endif //CORDIO_ZERO_COPY_HCI

#undef WSF_MS_PER_TICK
#define WSF_MS_PER_TICK 10
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively I think we can rename it in the file, as it doesn't seem to be compiled in mbed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming it here should work just fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@facchinm great, just pushed. This is ready for review now.

Later on we could be a bit smarter and change the poll interval dynamically based on the connection, advertising or scan intervals. However, let's see how feedback from customers goes.

@sandeepmistry
Copy link
Contributor Author

@facchinm so much better results with the last commit I've pushed, the following sketch uses ~1.6 mA of current while advertising and powered directly via 3.3V (jumper sliced):

/*
  Callback LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED. The callback features of the
  library are used.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  Serial.begin(9600);
//  while (!Serial);

  pinMode(LED_PWR, OUTPUT);
  digitalWrite(LED_PWR, LOW);
  
  pinMode(ledPin, OUTPUT); // use the LED pin as an output

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("LEDCallback");
  // set the UUID for the service this peripheral advertises
  BLE.setAdvertisedService(ledService);

//  BLE.setAdvertisingInterval(1600);

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);

  // start advertising
  BLE.advertise();

  Serial.println(("Bluetooth device active, waiting for connections..."));
}

void loop() {
  // poll for BLE events
  BLE.poll(10000);
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.print("Characteristic event, written: ");

  if (switchCharacteristic.value()) {
    Serial.println("LED on");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, LOW);
  }
}

@sandeepmistry sandeepmistry changed the title [DO NOT MERGE] cordio: use signals to wait for new HCI data when polling cordio: lower power polling with timeout Sep 11, 2019
@sandeepmistry sandeepmistry merged commit 5e44386 into arduino-libraries:master Sep 19, 2019
@ixj111
Copy link

ixj111 commented Sep 21, 2019

Does the code put the board into sleep between the polling intervals?

@sandeepmistry
Copy link
Contributor Author

Hi @ixj111,

Does the code put the board into sleep between the polling intervals?

The behaviour is as follows for the Nano 33 BLE: BLE.poll(10000) will do a low power wait for the sketch code for 10s or until a radio event occurs. Please note there will still be a link layer thread running that might prevent sleep mode.

@ixj111
Copy link

ixj111 commented Sep 23, 2019

Sandeep, thank you for the reply. I tested the code by BLE.setAdvertisingInterval(5000)
and BLE.poll(300000) to make it a much longer sleep. Then I used BLE apps on my smartphone to see if the board still advertises during the sleep. I discovered the device all the time in the smartphone apps like the device doesn't go to sleep at all. Am I missing anything?

@ixj111
Copy link

ixj111 commented Oct 15, 2019

Is it possible to share a picture of the board setup (jumper sliced)?

@sandeepmistry
Copy link
Contributor Author

@ixj111

I discovered the device all the time in the smartphone apps like the device doesn't go to sleep at all. Am I missing anything?

This is the intended behaviour there is no sleep, the power consumption is just lower between radio events.

Is it possible to share a picture of the board setup (jumper sliced)?

I don't have the board with me, however here's an annotated photo. You will need to cut the trace and supply 3.3V to the right pad. Including when programming.

abx00030_back

@SteenPetersen
Copy link

SteenPetersen commented Feb 19, 2020

For those asking to see what 'cut the trace' means. You need to cut the connection between the two jumpers on the bottom of the board as mentioned (see picture). To test if the connection has been severed, put in the USB cable again. Notice that it no longer powers the board, if it does, you need to cut a bit deeper. You will now need to power the board using the 3.3v pin, even when uploading code.

If you later wish to go back to using the board through the USB cable, simply solder up the joint that was severed by the cut.

cutTrace

@alexisicte
Copy link

For those asking to see what 'cut the trace' means. You need to cut the connection between the two jumpers on the bottom of the board as mentioned (see picture). To test if the connection has been severed, put in the USB cable again. Notice that it no longer powers the board, if it does, you need to cut a bit deeper. You will now need to power the board using the 3.3v pin, even when uploading code.

If you later wish to go back to using the board through the USB cable, simply solder up the joint that was severed by the cut.

cutTrace

If you want to keep the above configuration and flash the board again, you have to solder the Vusb traces and power the board using the 3.3v pin. Is that true?

@per1234
Copy link
Contributor

per1234 commented Feb 19, 2020

you have to solder the Vusb traces and power the board using the 3.3v pin. Is that true?

You don't need to solder the VUSB jumper. That is only used to connect Vusb to the +5V pin (it's disconnected by default to emphasize to the user that, unlike the classic Nano, this is a 3.3 V board). To upload to the Nano 33 BLE after cutting the 3.3 V jumper, you only need to power the board via the 3.3 V pin, connect the USB cable, and upload as usual. You will not be able to upload with only the USB cable attached because the nRF52840 is no longer powered via USB.

@SteenPetersen
Copy link

If you later wish to go back to using the board through the USB cable, simply solder up the joint that was severed by the cut.

Sorry I wasn't clear here - yes you can still use the USB cable after the cut, it simply won't power the board. You will need to do that by supplying power to the 3.3v pin. If you wish for the USB cable to power the board at a later stage you can solder the cut connection.

@whofmeis
Copy link

When using the 3.3v pin, do I still need to provide 5v over the USB cable when I want to program the Arduino (33 BLE Sense)? No matter what I do, I can't get my computer to detect the Arduino after powering it from the 3.3v pin - it doesn't even show up under USB devices. However, the BUILT_IN_LED is pulsing when I connect the USB cable to the computer, so I suppose that the Arduino seems to detect being connected to a USB host.

@SteenPetersen
Copy link

When using the 3.3v pin, do I still need to provide 5v over the USB cable when I want to program the Arduino (33 BLE Sense)? No matter what I do, I can't get my computer to detect the Arduino after powering it from the 3.3v pin - it doesn't even show up under USB devices. However, the BUILT_IN_LED is pulsing when I connect the USB cable to the computer, so I suppose that the Arduino seems to detect being connected to a USB host.

It will still recognize the Arduino it will simply not be able to power the board, so you will need to provide it with a power source somehow. Alternatively, you might want to try putting the board into 'development mode' by pressing the 'reset' button twice in quick succession.

@whofmeis
Copy link

I'm powering it with a 3v3 LDO, which is powered through the same USB cable I'm connecting the Arduino to the computer with. I can see that the Arduino does enter the development mode, but unfortunately, it still don't show up in the device list at all.

@SteenPetersen
Copy link

The power from the USB will no longer reach the MCU once the cut has been made. So your power source will need to come in from the 3.3 pin.

@gbar90
Copy link

gbar90 commented May 21, 2020

Hi, I was wondering if there is any news on this.
I tried the "LEDCallback" example code provided by @sandeepmistry on an Arduino Nano 33 BLE Sense powered directly via 3.3V (jumper sliced) with 3V. I still get a current of ca. 8mA.
I wonder if there is a way to send everything (mainly the NINA module and the nrf chip I guess) to deep sleep on this board. I want to measure every few minutes and save as much power as possible.
Thanks

@jaredmaks
Copy link

Hi, I was wondering if there is any news on this.
I tried the "LEDCallback" example code provided by @sandeepmistry on an Arduino Nano 33 BLE Sense powered directly via 3.3V (jumper sliced) with 3V. I still get a current of ca. 8mA.
I wonder if there is a way to send everything (mainly the NINA module and the nrf chip I guess) to deep sleep on this board. I want to measure every few minutes and save as much power as possible.
Thanks

You need to update the ArduinoBLE library on your IDE. The library might be old and not having new commits for your case.

@gbar90
Copy link

gbar90 commented Nov 27, 2020

Hey billiyz,
I haven't tried recently, the libraries might be updated.
I worked around it by powering the nfr52 down and waiting 1 min for an external wake up. This way it runs for months with a coin cell battery, measuring every minute.

void gotosleep() {

  // low power comparator setup to wake-up when the capacitor is discharged to 1/16 of VIN
  NRF_LPCOMP->PSEL=1; //select AIN3 = PIN_A1 = P0.05
  NRF_LPCOMP->REFSEL=8; // VDD * 1/16 selected as reference
  NRF_LPCOMP->ENABLE=1;
  NRF_LPCOMP->TASKS_START=1;
  while(!NRF_LPCOMP->EVENTS_READY){}

  NRF_POWER->SYSTEMOFF = 1;

}

@arduino-libraries arduino-libraries deleted a comment from Tazrih Oct 25, 2021
@Guides4you

This comment has been minimized.

@reniar1
Copy link

reniar1 commented May 28, 2023

Hey guys,

I am using the Arduino nano 33 ble and I am powering it with 3.3 volt and I cut the jumper to make that possible.

However if I start the board (peripheral) with 3v3 it will not be visible to the clients when they scan for bluetooth.

However if i plugin the 5v cable (micro usb) it will be visible, I can then plug it out again and it will still be visible.

It is like if the Arduino nano 33 ble need the 5v initially provided through the usb port to start up and then it can be constantly powered by 3v3.

Do you have any knowledge about this behaviour?

Idealy I would like to power the board with 3v3 and then see it (as an peripharal device) on my clients withoput having to initalize it by pluggin in the 5v cabl one time.

@Hsubtnarg
Copy link

Did this ever make it into the library as the above code still draws ~7mA and looking at the code in the library it does not seem to have changed (I have the latest version 1.3.6). But if I change WSF_MS_PER_TICK in mbed_config.h to 10, the same code only draws ~2mA

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet