arduino-BLEPeripheral icon indicating copy to clipboard operation
arduino-BLEPeripheral copied to clipboard

current consumption with BLE Nano 2

Open gtalusan opened this issue 6 years ago • 17 comments

I've been trying to get my BLE Nano 2 current consumption down. Right now I have it at ~2.8mA with DCDC enabled.

If I call sd_app_evt_wait() in my loop right after the application starts up, my current consumption drops to ~0.33mA. Once I use a central (my iPhone) to connect to the Nano 2, the current consumption jumps up to 2.8mA and stays there even after the central disconnects, and even if I call sd_app_evt_wait() again in my loop.

My sketch looks roughly like this..

BLEService tempService("CCC0");
BLEFloatCharacteristic tempCharacteristic("CCC1", BLERead | BLENotify);
BLEDescriptor tempDescriptor("2901", "Temperature");

void setup(void)
{
	ble.setDeviceName("temp");
	ble.setAdvertisedServiceUuid(tempService.uuid());
	ble.addAttribute(tempService);
	ble.addAttribute(tempCharacteristic);
	ble.addAttribute(tempDescriptor);

	ble.setEventHandler(BLEConnected, connectHandler);
	ble.setEventHandler(BLEDisconnected, disconnectHandler);
 
	ble.begin();
}

void loop(void)
{
	ble.poll();
        sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
        sd_app_evt_wait();
}

2.8mA is pretty good, but I'd like it go back down to 0.33mA :D

gtalusan avatar Sep 19 '17 01:09 gtalusan

Hi @gtalusan,

Are you using the RedBear core?

sandeepmistry avatar Nov 13 '17 01:11 sandeepmistry

Hi @sandeepmistry,

I'm using your arduino-nRF5 core.

gtalusan avatar Nov 13 '17 02:11 gtalusan

@gtalusan Were you able to fix the problem? I'm currently trying to get lower than 1.2mA in advertising

I found lot of articles/forums where people say they have around 0.1-0.2mA consumption, but I'm not able to replicate that. Also everyone writes that in DEEP SLEEP mode it consumes only 6uA, which I also wasn't able to replicate as my board consumes around 350uA in DEEP SLEEP mode.

Maybe you had some luck with lowering current consumption?

unCleanCode avatar Dec 28 '17 17:12 unCleanCode

@unCleanCode Sort of... I hard reset the core and go to sleep right away.

gtalusan avatar Dec 28 '17 18:12 gtalusan

And what's your current consumption after that? How did you hard reset it?

unCleanCode avatar Dec 28 '17 18:12 unCleanCode

It's down to 0.33mA.

        connected = false;
	ble.setEventHandler(BLEConnected, [=] (BLECentral &central) {
		connected = true;
	});
	ble.setEventHandler(BLEDisconnected, [=] (BLECentral &central) {
		sd_nvic_SystemReset();
	});

and in the event loop,

	if (!connected) {		
		sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
		sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
		sd_app_evt_wait();
	}

gtalusan avatar Dec 28 '17 18:12 gtalusan

Thanks! I'll test it today

Were you ever using DEEP SLEEP mode?

unCleanCode avatar Dec 28 '17 18:12 unCleanCode

Nope, didn't get that far.. my IoT device (temp sensor) runs for weeks being polled twice an hour on a beefy 18650. I put a solar panel and TP4056 charge circuit on it and it'll go forever.

gtalusan avatar Dec 28 '17 18:12 gtalusan

My device is also powered by 2x18650 3000mAh. Simple calculations shown me that most of the current consumed in advertising mode when device is waiting for connection and doing no useful job, so DEEP SLEEP mode can increase device lifetime from 15days to around 90 !!!

unCleanCode avatar Dec 28 '17 18:12 unCleanCode

Wow, I just found that my second board works perfectly fine with exactly the same code (consumptio in advertising is below 100uA), but second one is around 300-400uA !

Do you know what, except the code itself device saves when power is off? Maybe there is some kind of factory reset?

unCleanCode avatar Dec 28 '17 19:12 unCleanCode

I hope this is relevant to @gtalusan 's issue and possibly leads to a bug fix/clarification: I have an ID107 (NRF51882) fitness tracker board and I just had a very similar problem. My current consumption was about 60 µA after reset, then after the first connect and disconnect it was in the mA range.

I found out that the reason is that sd_app_evt_wait() always immediately returns after the first connection, so the device never really goes to sleep. More poking revealed that there is an interrupt pending after leaving ble.poll() which causes sd_app_evt_wait() to return immediately. The interrupt number is 22 which is SWI2_IRQn or also known as SD_EVT_IRQn. I don't really know if poll() is supposed to clear the pending interrupt but I think it should and this might be a bug. As far as I've understood this interrupt is supposed to tell the application that there was a BLE event. So I think after poll() has handled all events it should not be pending when leaving poll(). By the way I also tried calling poll() in a loop until the interrupt is cleared but it never gets cleared and so that loop is stuck.

What works for me is manually clearing the pending interrupt after leaving poll() in the main loop:

#include <nrf_nvic.h>//interrupt controller stuff

void loop() {
  // wait for event/interrupt (low power mode)
  sd_app_evt_wait();
  // some event woke us up --> poll peripheral
  blePeripheral.poll(); //this does not clear SD_EVT_IRQn for some reason, even in a loop
  sd_nvic_ClearPendingIRQ(SD_EVT_IRQn); //this fixes low power as the stuck IRQ is cleared 
}

This then gives me the same power consumption as after reset when disconnecting.

The reason @gtalusan 's code works is I think because the reset also clears the pending interrupt. I am also unsure if my manual clearing of the interrupt might drop events important for the BLE peripherial. I think that poll() should actually exit without an pending interrupt, but maybe @sandeepmistry can shine some light on that.

arglurgl avatar Jul 22 '18 17:07 arglurgl

@arglurgl good catch. I've noticed this behavior on my project as well.

NRF51822 with S110 doesn't stay in sleep mode after connecting/disconnecting so I just made it non connectable and broadcast the data for now. I'll have to give your code a try tonight.

h2zero avatar Aug 09 '18 15:08 h2zero

Got a chance to test @arglurgl s fix and can confirm (in my case anyway) that adding sd_nvic_ClearPendingIRQ(SD_EVT_IRQn); in the main loop after poll() that it does indeed go back to sleep properly. Thanks @arglurgl !

h2zero avatar Aug 13 '18 02:08 h2zero

@gtalusan @sandeepmistry @arglurgl and @h2zero I am developing a project based on nrf51822 and use @sandeepmistry Arduino core for it.

My Problem: After following all of your valuable comments, I wrote a code for the project. It turns out that in Advertising mode the nrf51822 consumes 1.76mA and when connected to a central device(in this case, my phone) it is 4.98mA. I don't understand where I am going wrong. 😕 ❓ I cannot get the board to consume 0.33mA even after following gtalusan's comment and arglurgl's comment in advertising mode.

This is the board I use. I use STM32 BluePill board as Black Magic Probe to upload firmware from Arduino IDE

My code:

#include <BLEPeripheral.h>
#include <nrf_nvic.h>
//////////////
// Hardware //
//////////////
#define LED_PIN    20// LED on pin 20
#define LED_ACTIVE LOW // Pin 20 LED is active low
#define LED_DEFAULT LOW
///////////////////////
// BLE Advertisments //
///////////////////////
const char * localName = "nrf51822 LED";

BLEPeripheral blePeriph;
BLEService bleServ("58be27e8-f4f0-43e7-9997-34166889a7c3");
BLECharacteristic ledChar("58be27e8-f4f0-43e7-9997-34166889a7c3", BLERead | BLEWrite | BLENotify, 20);
bool connectedToCentral = false;
const unsigned char* ledState = NULL;
const char* ledison = "ON";

void setup()
{
  Serial.begin(115200); // Set up serial at 115200 baud
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, !LED_ACTIVE);

  setupBLE();
}


void loop()
{
  blePeriph.poll();
  ledState = ledChar.value();
  if (!blePeriph.connected()) {
    sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
    sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
    sd_nvic_ClearPendingIRQ(SD_EVT_IRQn); //this fixes low power as the stuck IRQ is cleared
    sd_app_evt_wait();
  }
  else
  {
    if (ledChar.written())
    {

      if (memcmp(ledison, ledState, 2) == 0)
      {
        digitalWrite(LED_PIN, LED_ACTIVE);
        ledChar.setValue(ledison);
      }

      else if (memcmp((const char*)"OFF", ledState, 2) == 0)
      {
        digitalWrite(LED_PIN, !LED_ACTIVE);
        ledChar.setValue("OFF");
      }

    } 

  }
}
void setupBLE()
{
  // Advertise name and service:
  blePeriph.setDeviceName(localName);
  blePeriph.setLocalName(localName);
  //blePeriph.setManufacturerData(manufacturer, 26);
  blePeriph.setAdvertisedServiceUuid(bleServ.uuid());

  // Add service
  blePeriph.addAttribute(bleServ);

  // Add characteristic
  blePeriph.addAttribute(ledChar);
  blePeriph.setEventHandler(BLEConnected, connectHandler);
  blePeriph.setEventHandler(BLEDisconnected, disconnectHandler);


  // Now that device6, service, characteristic are set up,
  // initialize BLE:
  blePeriph.begin();
  sd_ble_gap_tx_power_set(-12);

  // 660ms; in multiples of 0.625ms.
  blePeriph.setAdvertisingInterval(412);

  // Set led characteristic to default value:
  //ledChar.setValue(!LED_ACTIVE);
}



void connectHandler(BLECentral& central) {
  // central connected event handler
  Serial.print(F("Connected event, central: "));
  Serial.println(central.address());
  connectedToCentral = true;
}

void disconnectHandler(BLECentral& central) {
  // central disconnected event handler
  Serial.print(F("Disconnected event, central: "));
  Serial.println(central.address());
  sd_nvic_SystemReset();
}

Please help!

TamojitSaha avatar Sep 28 '18 12:09 TamojitSaha

One remark: Did you reset and power-cycle the board after uploading? If not, the JTAG hardware stays activated an draws additional current. Try disconnecting everything after flashing and then only reconnecting power.

arglurgl avatar Oct 05 '18 17:10 arglurgl

Right !!I just did that. Now it draws around 0.3ma But after using the SPI library for interfacing with LORA- Ra01 it uses 1.4ma even after removing the sed connections and power cycling

TamojitSaha avatar Oct 05 '18 17:10 TamojitSaha

@arglurgl When I'm using sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE) with nRF52840 E-Byte E73-2G4M08S1C module, I get consumption increase to 30-35mA instead of 6-6.5mA after the command is executed in code: https://github.com/gtalusan/nrf52-ds18b20/blob/master/nrf52-ds18b20.ino - the issue is somehow related to NRF_POWER_DCDC_ENABLE on that module. Removing sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE) solves the 30mA issue. Any ideas?

mrdc avatar Dec 25 '19 17:12 mrdc