Optimize power consumption for maximum battery life in nrf52840 BLE Beacon.

I’m working on a BLE-based door sensor project and my focus is to optimize power consumption for maximum battery life. The code I’m using is designed for a beacon using sdk version v2.4.1 and I’m looking for guidance on reducing power usage. I’ve included my prj.conf and overlay files for reference. Any suggestions or insights on achieving the most efficient power management for this sensor would be greatly appreciated. I'm currently testing the current consumption of an nRF52840 using the Power Profiler Kit 2 as part of a BLE door sensor project. The current measured using ppk II is also included. It is approximately near 20mA. 

/* main.c - Application main entry point */

/*
 * Copyright (c) 2015-2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>

#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/device.h>

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define SLEEP_TIME_MS   1000
//#define SW0_NODE DT_ALIAS(sw0) 

#define LED0_NODE DT_ALIAS(led4)
#define SW0_NODE DT_ALIAS(sw6)

uint8_t door_status = 0;
uint8_t d[3] = {0x11, 0x66, 0x00};


static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(SW0_NODE, gpios);


/*
 * Set Advertisement data. Based on the Eddystone specification:
 * https://github.com/google/eddystone/blob/master/protocol-specification.md
 * https://github.com/google/eddystone/tree/master/eddystone-url
 */

static struct bt_data ad1[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
	BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x58, 0x36),
	BT_DATA_BYTES(BT_DATA_SVC_DATA16,0x11,0x66,0x00) 
	
};


static const struct bt_data sd[] = {
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};


static void bt_ready(int err)
{
	char addr_s[BT_ADDR_LE_STR_LEN];
	bt_addr_le_t addr = {0};
	size_t count = 1;

	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return;
	}

	printk("Bluetooth initialized\n");

	/* Start advertising */
	err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, ad1, ARRAY_SIZE(ad1),
			      sd, ARRAY_SIZE(sd));
	if (err) {
		printk("Advertising failed to start (err %d)\n", err);
		return;
	}

	/* For connectable advertising you would use
	 * bt_le_oob_get_local().  For non-connectable non-identity
	 * advertising an non-resolvable private address is used;
	 * there is no API to retrieve that.
	 */

	bt_id_get(&addr, &count);
	bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));

	printk("Beacon started, advertising as %s\n", addr_s);
}

int main(void)
{
	int err,ret;
	if (!device_is_ready(led.port)) {
		return ;
	}
	if (!device_is_ready(button.port)) {
	 	 return ;
    }

	ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
    if (ret < 0) {
		return ;
    }

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return ;
	}

	printk("Starting Beacon Demo\n");

	 /* Initialize the Bluetooth Subsystem */
	err = bt_enable(bt_ready);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
	}
	while(1)
	{
	    bool val = gpio_pin_get_dt(&button);
		gpio_pin_set_dt(&led,val);
		printk("Button Value: %d\n", val);
		door_status = (val == 1) ? 1 : 0;
		printk("Door Status: %s\n", door_status ? "Open" : "Closed");
		d[2]=door_status;
		ad1[2].data = (const uint8_t *)(d);
		err = bt_le_adv_update_data(ad1, ARRAY_SIZE(ad1),sd, ARRAY_SIZE(sd));
		if (err) 
		{
		printk("Advertising update with (err %d)\n", err);
		
	    }
	}
	
	return 0;
}

/*
 * Copyright 2022 Dronetag
 *
 * SPDX-License-Identifier: Apache-2.0
 */
 /{
    coex_gpio: coex {
        compatible = "gpio-radio-coex";
        grant-gpios = <&gpio1 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>;
        grant-delay-us = <150>;
    };

};
&radio {
    coex = <&coex_gpio>;
};

/{
    leds{
        compatible = "gpio-leds";
        led4: led_4 {
            gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
            label = "Yellow LED 0";
            status="okay";
        };
    };
    
    buttons {
        compatible = "gpio-keys";
        button6: button_6 {
            //gpios = <&gpio0 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>;
            gpios = <&gpio0 15( GPIO_ACTIVE_LOW)>;
            label = "Push button switch 6";
        };
    };
    
        aliases {
            led4=&led4;
            sw6=&button6;
        };
    };

    
    &pwm_led0 {
	
        status = "disabled";	
    };
    &button1 {
        
        status = "disabled";	
    };
    &button2 {
        
        status = "disabled";	
    };
    &button3 {	
        status = "disabled";	
    };
    
    &led0 {
        status = "disabled";
    };
    &led1 {
        status = "disabled";
    };
    &led2 {
        status = "disabled";
    };
    &led3 {
        status = "disabled";
    };
    /* Disable unused peripherals to reduce power consumption */
    &uart0 {
        status = "disabled";
    };
    &adc {
        status = "disabled";
    };
    &uart1 {
        status = "disabled";
    };
    &i2c0 {
        status = "disabled";
    };
    &pwm0 {
        status = "disabled";
    };
    &spi1 {
        status = "disabled";
    };
    &spi0 {
        status = "disabled";
    };
    &usbd {
        status = "disabled";
    };
    
    
    &i2c1 {
        status = "disabled";
    };
    &spi2 {
        status = "disabled";
    };
    
    &qspi {
        status = "disabled";
    };
    
    &timer0 {
        status = "disabled";
    };
    
    &timer1 {
        status = "disabled";
    };
    
    &timer2 {
        status = "disabled";
    };
    
    &timer3 {
        status = "disabled";
    };
    
    &timer4 {
        status = "disabled";
    };
    &nvic {
        status = "disabled";
    };
    
    &gpiote {
        status = "disabled";
    };
    &temp {
        status = "disabled";
    };
    &rtc0 {
        status = "disabled";
    };
    
    &rtc1 {
        status = "disabled";
    };
    &ecb {
        status = "disabled";
    };
    
    &ccm {
        status = "disabled";
    };
    
    &egu0 {
        status = "disabled";
    };
    
    &egu1 {
        status = "disabled";
    };
    
    &egu2 {
        status = "disabled";
    };
    
    &egu3 {
        status = "disabled";
    };
    
    &egu4 {
        status = "disabled";
    };
    
    &egu5 {
        status = "disabled";
    };
    &pwm0 {
        status = "disabled";
    };
    
    &acl {
        status = "disabled";
    };
    
    &ppi {
        status = "disabled";
    };
    
    &mwu {
        status = "disabled";
    };
    
    &usbd {
        status = "disabled";
    };
    
    &spi3 {
        status = "disabled";
    };
    
    &wdt0 {
        status = "disabled";
    };
    
    &rng_hci {
        status = "disabled";
    };
    &ieee802154{
        status = "disabled";
    };
      

CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_DEVICE_NAME="Door Sensorrr"

###################################################
CONFIG_PM=y
CONFIG_LOG=n
CONFIG_SERIAL=n
CONFIG_PM_DEVICE=y
CONFIG_BT_CTLR_TX_PWR_ANTENNA=0

Parents Reply Children
  • Hi Neethu, 


    Thanks for the trace. Green part look expected. The idle current is low (close to 0mA) But the red part is quite strange (idle current is about 4mA). For me it seems like the CPU didn't sleep the whole time. So you may want to check if there is something running in the background that keep the CPU awake all the time. 

  • I have implemented sleep mode in my BLE beacon project. However, I am still looking for ways
    to further reduce power consumption. I have configured the system to enter sleep mode, but I would like to know if there are additional strategies or configurations that can
    help minimize power usage even further.
    Any guidance or suggestions would be much appreciated!

    Thank you!

              

    /* main.c - Application main entry point */
    
    /*
     * Copyright (c) 2015-2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/util.h>
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/hci.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/device.h>
    #include <zephyr/pm/pm.h>
    
    
    #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    
    
    #define LED0_NODE DT_ALIAS(led4)
    #define SW0_NODE DT_ALIAS(sw6)
    void led_timer_expiry_function(struct  k_timer *timer_id);
    void  sleep_timer_expiry_function(struct  k_timer *timer_id);
    //int val;
    K_MSGQ_DEFINE(ble_status_queue, sizeof(int), 16, 4);
    K_TIMER_DEFINE(led_timer, led_timer_expiry_function, NULL);  // Define a timer for the LED 
    K_TIMER_DEFINE(sleep_timer, sleep_timer_expiry_function, NULL);  // Define a timer for the LED 
    
    uint8_t door_status = 0;
    uint8_t d[3] = {0x11, 0x66, 0x00};
    uint8_t current_state ,prev_state ;
    
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
    static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
    static struct gpio_callback button_cb_data;
    
    /*
     * Set Advertisement data. Based on the Eddystone specification:
     * https://github.com/google/eddystone/blob/master/protocol-specification.md
     * https://github.com/google/eddystone/tree/master/eddystone-url
     */
    
    static struct bt_data ad1[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
    	BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x58, 0x36),
    	BT_DATA_BYTES(BT_DATA_SVC_DATA16,0x11,0x66,0x00) 
    	
    };
    
    
    /* Set Scan Response data */
    static const struct bt_data sd[] = {
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static void bt_ready(int err)
    {
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	bt_addr_le_t addr = {0};
    	size_t count = 1;
    
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	/* Start advertising */
    	err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, ad1, ARRAY_SIZE(ad1),
    			      sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Advertising failed to start (err %d)\n", err);
    		return;
    	}
    
    
    	/* For connectable advertising you would use
    	 * bt_le_oob_get_local().  For non-connectable non-identity
    	 * advertising an non-resolvable private address is used;
    	 * there is no API to retrieve that.
    	 */
    
    	bt_id_get(&addr, &count);
    	bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));
    
    	printk("Beacon started, advertising as %s\n", addr_s);
    }
    
    
    void led_timer_expiry_function(struct k_timer *timer_id)
    {
        gpio_pin_set_dt(&led, 0);  // Turn off the LED after 100ms
    }
    void  sleep_timer_expiry_function(struct  k_timer *timer_id)
    {
    	
    	pm_state_force(0, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
    }
    
     void button_pressed(const struct device *dev, struct gpio_callback *cb,
    		    uint32_t pins)
    {
    
    	//printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
    	int val= gpio_pin_get_dt(&button);
    	k_msgq_put(&ble_status_queue, &val, K_NO_WAIT);
    	
    }
    void update_advertisement_data(int rec_data)
    {
    	k_timer_stop(&sleep_timer);
    	printk("Door Status: %s\n", rec_data ? "Open" : "Closed");
    	gpio_pin_set_dt(&led, 1);
    	k_timer_start(&led_timer, K_MSEC(50), K_NO_WAIT);  // Start the timer for 100ms
    	d[2] = rec_data;
    	ad1[2].data =  (const uint8_t *)(d);
    			
    	int err = bt_le_adv_update_data(ad1, ARRAY_SIZE(ad1), sd, ARRAY_SIZE(sd));
    	if (err) {
    				printk("Advertising update failed with err %d\n", err);    
    	}
    	
    	k_timer_start(&sleep_timer, K_MSEC(5000), K_NO_WAIT);  // Start the timer for 5sec
    	
    	
    }
    
    
    		
    int main(void)
    {
    	int err,ret;
    
    	if (!device_is_ready(led.port)) {
    		return ;
    	}
    	if (!device_is_ready(button.port)) {
    	 	 return ;
        }
    
    	ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
        if (ret < 0) {
    		return ;
        }
    
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT);
    	if (ret < 0) {
    		return ;
    	}
    
    	ret = gpio_pin_interrupt_configure_dt(&button,GPIO_INT_EDGE_BOTH);
    	if (ret != 0) {
    		printk("Error %d: failed to configure interrupt on %s pin %d\n",
    			ret, button.port->name, button.pin);
    		return 0;
    	}
    
    	gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
    	gpio_add_callback(button.port, &button_cb_data);
    	printk("Starting Beacon Demo\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(bt_ready);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    	}
    
    	//k_timer_init(&led_timer, NULL, led_timer_expiry_function);
        while(true)
    	{ 	int rec_data;
    		k_msgq_get(&ble_status_queue,&rec_data,K_FOREVER);
    		update_advertisement_data(rec_data);
    		
    	}
    	return 0;
    }
    

  • The current measured using ppk II is also included. 

  • Hi Neethu, 
    Your current consumption is a bit high. You can find the sleep current is a few hundred uA. 
    Do you have anything else on the board that may consume power ? Please let us know more about your board setup. 

    What I would expect to see is what at the green part here: 

    The sleep current should be closer to 2-4 uA. 

  • The sleep current is currently 18uA. But my system doesn't wake up from sleep. Is there a way to wake up from sleep mode.

Related