BLE Nano - Low Power Consumption


#1

I am powering the BLE Nano using the GND and VIN pin with a 150mah 3.7V Lipo Battery in Arduino, but the battery life is very poor. Currently it consumes 2.4ma and is completely drained in 1-2 days. Is there any way to get the power consumption down below 1ma? Right now all the LED’s are turned off and I have the device sitting in this while loop:

//While device is not connected, just wait.
while(!ble.getGapState().connected){
ble.waitForEvent();
}

Is this code correct for a sleep mode when not being used? If anyone can help with this it would be much appreciated. I can always wake the device up via an analog read, I just need help getting the BLE Nano into the deepest sleep mode possible (lowest possible power consumption). Code would be appreciated if possible. Thanks.


Power reduce in ble nano..........?
Question about Advertising and Disconnecting
Power reduce in ble nano..........?
BLE Nano and coin cell
BLE Nano and coin cell
Power reduce in ble nano..........?
BLE Nano no longer Low Power
#2

Hi jstrag711,

void loop() {
ble.waitForEvent(); //Don't do other things
}

Don’t use the uart.


#3

Hi jixing,

I am using the simple chat sketch with no extra components, just the BLE Nano connected with a 3.7v Lipo to VIN and GND. Is it possible to achieve power consumption below 1ma using the regulated power on this board? Or does the 3.3v regulator prevent this?

I have turned off the onboard LED on pin 13. I even tried disabling uart as seen here:

And I used the code you provided for the main loop and did not do other things, only waited for the event. I still measured consumption at 2.2ma using a multimeter (black on GND and red on VDD).

I am very confused. Any help would be great. Thank you.


#4

Hi

Try this sample code

#include <BLE_API.h>

#define DEVICE_NAME            "BLE_Peripheral"
#define TXRX_BUF_LEN           20

BLE                            ble;

// The uuid of service and characteristics
static const uint8_t service1_uuid[]        = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[]     = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[]     = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[]   = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

// Initialize value of chars
GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );
GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};
GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

void disconnectionCallBack(const Gap::DisconnectionCallbackParams_t *params) {
  ble.startAdvertising();
}

void gattServerWriteCallBack(const GattWriteCallbackParams *Handler) {

}

void setup() {

  NRF_POWER->DCDCEN = 0x00000001;
  NRF_UART0->TASKS_STOPTX = 1;
  NRF_UART0->TASKS_STOPRX = 1;
  NRF_UART0->ENABLE = 0;
  
  // put your setup code here, to run once
  ble.init();
  ble.onDisconnection(disconnectionCallBack);
  ble.onDataWritten(gattServerWriteCallBack);

  // setup adv_data and srp_data
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                   (const uint8_t *)"TXRX", sizeof("TXRX") - 1);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                   (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
  // set adv_type
  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
  // add service
  ble.addService(uartService);
  // set device name
  ble.setDeviceName((const uint8_t *)"Simple Chat");
  // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
  ble.setTxPower(4);
  // set adv_interval, 100ms in multiples of 0.625ms.
  ble.setAdvertisingInterval(160);
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);
  // start advertising
  ble.startAdvertising();
}

void loop() {
    ble.waitForEvent();
}

About the multimeter,should be connected:

Lipo+ —> Red —> Black ----> Nano_VIN

Lipo- ---->Nano_GND


#5

Thank you jixing! You saved us lots of headache! :slight_smile:

Also, we used this in setup to disable onboard LED:
pinMode(13, INPUT);

And now power consumption around ~150ua. :slight_smile:


#6

Also for those struggling with low power consumption.

Set TX Power to 4 and set Advertising Interval to 1000 to keep the the BLE still easy to connect to. Any longer and the device may not be discovered easily.

Also be sure you have NOT used Serial.begin(9600) (or any baud rate for that matter). The Serial.begin() will still consume extra power, even with the following code:

NRF_POWER->DCDCEN = 0x00000001;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->ENABLE = 0;

Note that Serial.end() will not fix this either. Simply put, you must not use Serial.begin().

With these settings we have consumption around 100ua. We are trying to optimize it even further, for low power consumption while still in power on mode.

Hopefully this helps anyone else with low power consumption questions.


#7

Hi jstrag711,
Thanks very much!


#8

what peripheral are by default running in redbear core. like timers etc. 100uA is alot for long life of battery. I am switching off peripherals after use like I2C. so I would like to know how I can reduce current. most of time the program is sleepingI also have kept low freq wakeup low Latency.
NRF_POWER->TASKS_LOWPWR = 1;


#9

trailblazer47:

NRF_POWER->SYSTEMOFF = 1;

You can go into power off (deep sleep) mode using this code. It consumes about 6uA which is much more long term battery friendly. However you will have to wake it up using interrupts or timers and BLE is disabled in power off mode. I have not had success with this yet, but it is possible. But this is what you might be looking for as far a true sleep mode.


#10

I think that will also reset the chip which I don’t want, I am maintaining time for clock (RTC 32Khz). is it the Regulator over nano that consumes 100uA-200uA avg current in nano?


#11

hai

i am using bleperipheral.h to program my ble nano.
So can i use

NRF_POWER->DCDCEN = 0x00000001;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->ENABLE = 0;

in bleperipheral.h

bleperipheral library


#12

Hi I would like to update on power consumption. I am getting power for one of the product I am working on as 5-8uA in sleep. I can’t share the complete code of it but we are not using any serial port and also switching off any peripherals(I2C NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; ) we are using when we go to sleep. We are using MDBT40 modules, no regulator only one EEPROM on it.

NRF_POWER->TASKS_LOWPWR = 1; NRF_POWER->DCDCEN = 0x00000001; ble.waitForEvent();

I do this much. I am still not sure that current is accurate. I am using fluke 17B+ multimeter. Is there any better way to make sure the current is ok? any low cost instrument.


#13

hiii @jstrag711,

Is there any possible way to wake up BLE nano from sleep using an internal interrupt…??

thank you


#14

Hey guys,

I am trying to set my BLE Nano into a deep sleep with power off. How would somebody go about waking it up by some change in the analogIn?

So basically I want my BLE to go into deep sleep after a inactivity timeout and be woken up by a strong signal from analogIn.
Do I have to make an event? Or interrupt?
I don’t need BLE when I wake it up. In fact, BLE should be off when it is woken up.


#15

Hi js
Just gotten the BLE nano, flash it with the mbed example of simple controller.
Used your advice in getting low power consumption, but i still get like 1mA drawn.
can you see what can be wrong at all? Thanks much for the time.

my main looks like this
int main(void)
{
Ticker ticker;
ticker.attach_us(m_status_check_handle, 200000);
// ADDED
NRF_POWER->DCDCEN = 0x00000001;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->ENABLE = 0;
// END OF ADDED

ble.init();
ble.onDisconnection(disconnectionCallback);
ble.onDataWritten(WrittenHandler);  

//pc.baud(9600);
//pc.printf("SimpleChat Init \r\n");

//pc.attach( uartCB , pc.RxIrq);

// setup advertising 
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                (const uint8_t *)"Biscuit", sizeof("Biscuit") - 1);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));

// ADDED     
// 100ms; in multiples of 0.625ms. 
ble.setAdvertisingInterval(1000); // advertise interval 
ble.setTxPower(4); // tx power to 4 
ble.addService(uartService);
//ENDED 
ble.startAdvertising(); 

//pc.printf("Advertising Start \r\n");

while(1)
{
    ble.waitForEvent(); 
}

}


#16

I have similar issue, but it only affects one Nano 2 board, not another one.

#include <nRF5x_BLE_API.h>

void setup() {
  NRF_POWER->SYSTEMOFF = 1;
}

void loop() {}

This code on my normal Nano 2 gives 4uA consumption. On the second one it shows around 300uA

Could you help me with that?


#17

Hello
I Am having the same problem as boon
Using the following code as described by boon I also get current consumption around 1mA
What could be wrong with that?
Thanks a lot

int main(void)
{
Ticker ticker;
ticker.attach_us(m_status_check_handle, 200000);
// ADDED
NRF_POWER->DCDCEN = 0x00000001;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->ENABLE = 0;
// END OF ADDED

ble.init();
ble.onDisconnection(disconnectionCallback);
ble.onDataWritten(WrittenHandler);

//pc.baud(9600);
//pc.printf(“SimpleChat Init \r\n”);

//pc.attach( uartCB , pc.RxIrq);

// setup advertising
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
(const uint8_t *)“Biscuit”, sizeof(“Biscuit”) - 1);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
(const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));

// ADDED
// 100ms; in multiples of 0.625ms.
ble.setAdvertisingInterval(1000); // advertise interval
ble.setTxPower(4); // tx power to 4
ble.addService(uartService);
//ENDED
ble.startAdvertising();

//pc.printf(“Advertising Start \r\n”);

while(1)
{
ble.waitForEvent();
}
}


#18

I have published a detailed tutorial on how to program the NanoV2 for very low power <100uA all the time, advertising and connected send/receive
https://www.forward.com.au/pfod/BLE/LowPower/index.html
You can use either the NanoV2 programmer or this tutorial shows you how to use a BlackMagic Probe to program the NanoV2.
There is a free app that will generate the low power Arduino Sketch for you that lets you show control menus and plot and log data on your Android mobile, using pfodApp.

Also it seems that the nRF52 chip can get into debug mode by its self which draws mA’s instead of uA’s
Once you have programmed your chip, connect a 470R and 1nF, in parallel, directly from SWCLK to GND to stop noise triggering debug


#19

Hello drmpf,

Thanks a lot for your tutorial it’s awesome !

I just one question, I use my read bear with a solar panel cell and I can’t be sure to have enough energy to wait a user connection on android device. So if it’s possible I want to create a “best effort” code that do exactly the same thing that your but not in connected mode but in advertising mode.

Before I found your solution that was my code.

#include <nRF5x_BLE_API.h>
#include "nrf_temp.h"

#define DEVICE_NAME            "Kinder1"

#define LED                    D7

#define ADVPERIOD              1 //Adv every x seconds
#define ADVDURATION            400000  //adv during x micro seconds
#define LED_DURATION           30 // Miliseconds

BLE                            ble;
Ticker                         ticker1s;
Ticker                         tickerStop;

void setAdvertisement(void) {
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
  
  // Add short name to advertisement
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,(const uint8_t *)DEVICE_NAME,sizeof(DEVICE_NAME) - 1);

  // Add complete device name to scan response data
  ble.accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME,(const uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
}

void task_handle(){

  // Blink led to notify the user
  digitalWrite(LED, HIGH);
  delay(LED_DURATION);
  digitalWrite(LED, LOW);

  // Here is the code to update new temperature but it look like doing it disable bluetooth
  /*
  NRF_TEMP->TASKS_START = 1;
  while (NRF_TEMP->EVENTS_DATARDY == 0)
    delay(10);
  int rawTemp = NRF_TEMP->TEMP;
  NRF_TEMP->TASKS_STOP = 1;

  ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA,(const uint8_t *)&rawTemp,sizeof(rawTemp));
  */

  ble.startAdvertising(); 
  tickerStop.attach_us(stopAdv,ADVDURATION);
}

void stopAdv(){
  ble.stopAdvertising();
  tickerStop.detach();
}

//------------------
void setup() {
  pinMode(LED, OUTPUT);

  NRF_TEMP->TASKS_START = 1;

  NRF_POWER->DCDCEN = 0x00000001;
  NRF_UART0->TASKS_STOPTX = 1;
  NRF_UART0->TASKS_STOPRX = 1;
  NRF_UART0->ENABLE = 0;
  
  // put your setup code here, to run once
  ble.init(); 
  // set advertisement
  setAdvertisement();
  ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
  // 100ms; in multiples of 0.625ms
  ble.setAdvertisingInterval(160); 
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);

  // Get temperature 
  //while (NRF_TEMP->EVENTS_DATARDY == 0);
  int rawTemp = NRF_TEMP->TEMP;
  //NRF_TEMP->TASKS_STOP = 1;

  // Set payload
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA,(const uint8_t *)&rawTemp,sizeof(rawTemp));

  ble.startAdvertising(); 

  ticker1s.attach(task_handle, ADVPERIOD);
  tickerStop.attach_us(stopAdv,ADVDURATION);
  
  // Blink led to notify the user
  digitalWrite(LED, HIGH);
  delay(LED_DURATION);
  digitalWrite(LED, LOW);
}

void loop() {
    ble.waitForEvent();
}

Do you know if its possible ?

Thanks a lot,


#20

I may be missing the point of your question, but in my case the connected current is less than the advertising current.
BUT the real problem with running from pure solar cells is that there is a much higher start up current required, a few mA, for about 400mS, before the nRF52 drops down to <100uA average.

So after many ‘trials and horrors’ I came up with a circuit that will let the nRF52 start up from a 100uA current source. i.e. a solar cell in low light.
Actually the circuit will startup from <100uA but then will stop later as the storage caps discharge. How long it takes to stop depends on the difference between the solar cell current and the required nRF52 current.
Adjusting your Advertising interval and Connection interval and TX power should let you get down to 50uA or so.

In my case I used two small solar cells (50mm x 30mm) in series to get > 4.5V from two 5V cells in heavy shade.

While testing I was surprised to find my circuit starting up with NO power supply/solar cells at all. What was happening was that a long cable was picking up a local radio transmitter and the rectified RF was charging up the startup circuit and starting the BLE. With a big enough aerial and a low enough running current you could do without a power supply at all. Think crystal sets and RF powered receivers.

A simpler circuit is to diode OR the solar cells with a normal battery. Then the solar cells take over when there is any sun and extend the battery life.

I have not published that project and circuits yet, Still working on the prototype. Contact pfod.com.au support if you can’t wait.