This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

nRF5340-DK Low Power Configuration Issues

Hi,

I am performing some evaluation on the low power capabilities of the nRF5340 using the DK and the PPK v1.

I have written a really basic BLE Peripheral Application based loosely around the peripheral_lbs sample code as I want to test with a button handler eventually.

The problem I have is that after considerable configuration, I can only get the current floor down to ~200uA with an average current of ~215uA with a 1.2 second advertising interval. I've seen a lot of people on here talk about seeing much, much lower currents so wondered is there a configuration that I am missing perhaps?

I have been reading the documents and a few threads on here to understand how to configure the device and I have done the following.

  1. My main application, running on the NS partition, has been configured as follows:

    CONFIG_NCS_SAMPLES_DEFAULTS=y
    
    CONFIG_BT=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_DEVICE_NAME="MH_TEST"
    
    # Enable the LBS service
    CONFIG_BT_LBS=y
    CONFIG_BT_LBS_POLL_BUTTON=y
    CONFIG_DK_LIBRARY=y
    
    # Drivers and peripherals
    CONFIG_I2C=n
    CONFIG_WATCHDOG=n
    CONFIG_GPIO=n
    CONFIG_PINMUX=n
    CONFIG_SPI=n
    CONFIG_SERIAL=n
    
    # Power management
    CONFIG_DEVICE_POWER_MANAGEMENT=y
    CONFIG_PM=y
    
    # Interrupts
    CONFIG_DYNAMIC_INTERRUPTS=n
    CONFIG_IRQ_OFFLOAD=n
    
    # Memory protection
    CONFIG_THREAD_STACK_INFO=n
    CONFIG_THREAD_CUSTOM_DATA=n
    CONFIG_FPU=n
    
    # Boot
    CONFIG_BOOT_BANNER=n
    CONFIG_BOOT_DELAY=0
    
    # Console
    CONFIG_CONSOLE=n
    CONFIG_UART_CONSOLE=n
    CONFIG_STDOUT_CONSOLE=n
    CONFIG_PRINTK=n
    CONFIG_EARLY_CONSOLE=n
    
    # Build
    CONFIG_SIZE_OPTIMIZATIONS=y


  2. I have added an spm.conf

    CONFIG_IS_SPM=y
    CONFIG_FW_INFO=y
    CONFIG_GPIO=y
    CONFIG_SERIAL=n


    and added that to the CMakeLists.txt

    set(spm_CONF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/spm.conf)


  3. I have also configured the hci_rpmsg via the menuconfig to turn off logging

  4. I also tried turning on Power Management via the SPM and HCI_RPMSG's menuconfig's as well but it did not seem to have any effect. 

As for my source code, I have attached it. I simply setup the BLE and handlers and then call:

for (;;) {
    k_cpu_idle();
	}

If we look at the PPK, I see this:

where my baseline current seems to be around 200uA - from what I had read around, I would have expected to be able to get it lower than this, so I imagine I must be configuring something incorrectly. 

If you had any advice, it would be appreciated!

nRF Connect SDK: v1.6.1


/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>
#include <drivers/gpio.h>
#include <soc.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>

#include <bluetooth/services/lbs.h>

#include <settings/settings.h>

#include <dk_buttons_and_leds.h>

#include <device.h>
#include "power/power.h"

#define DEVICE_NAME             CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN         (sizeof(DEVICE_NAME) - 1)


#define RUN_STATUS_LED          DK_LED1
#define CON_STATUS_LED          DK_LED2
#define RUN_LED_BLINK_INTERVAL  1000

#define USER_LED                DK_LED3

#define USER_BUTTON             DK_BTN1_MSK

#define BT_LE_ADV_CONN_TEST BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE, \
				            BT_GAP_ADV_SLOW_INT_MAX, \
				            BT_GAP_ADV_SLOW_INT_MAX, NULL)

const struct device *console, *uart1;

static bool app_button_state;

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

static const struct bt_data sd[] = {
	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_LBS_VAL),
};

static void connected(struct bt_conn *conn, uint8_t err)
{
	if (err) {
		printk("Connection failed (err %u)\n", err);
		return;
	}

	printk("Connected\n");

	dk_set_led_on(CON_STATUS_LED);
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	printk("Disconnected (reason %u)\n", reason);

	dk_set_led_off(CON_STATUS_LED);
}

#ifdef CONFIG_BT_LBS_SECURITY_ENABLED
static void security_changed(struct bt_conn *conn, bt_security_t level,
			     enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	if (!err) {
		printk("Security changed: %s level %u\n", addr, level);
	} else {
		printk("Security failed: %s level %u err %d\n", addr, level,
			err);
	}
}
#endif

static struct bt_conn_cb conn_callbacks = {
	.connected        = connected,
	.disconnected     = disconnected,
#ifdef CONFIG_BT_LBS_SECURITY_ENABLED
	.security_changed = security_changed,
#endif
};

#if defined(CONFIG_BT_LBS_SECURITY_ENABLED)
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Passkey for %s: %06u\n", addr, passkey);
}

static void auth_cancel(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Pairing cancelled: %s\n", addr);
}

static void pairing_confirm(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	bt_conn_auth_pairing_confirm(conn);

	printk("Pairing confirmed: %s\n", addr);
}

static void pairing_complete(struct bt_conn *conn, bool bonded)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Pairing completed: %s, bonded: %d\n", addr, bonded);
}

static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Pairing failed conn: %s, reason %d\n", addr, reason);
}

static struct bt_conn_auth_cb conn_auth_callbacks = {
	.passkey_display = auth_passkey_display,
	.cancel = auth_cancel,
	.pairing_confirm = pairing_confirm,
	.pairing_complete = pairing_complete,
	.pairing_failed = pairing_failed
};
#else
static struct bt_conn_auth_cb conn_auth_callbacks;
#endif

static void app_led_cb(bool led_state)
{
	dk_set_led(USER_LED, led_state);
}

static bool app_button_cb(void)
{
	return app_button_state;
}

static struct bt_lbs_cb lbs_callbacs = {
	.led_cb    = app_led_cb,
	.button_cb = app_button_cb,
};

static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	if (has_changed & USER_BUTTON) {
		bt_lbs_send_button_state(button_state);
		app_button_state = button_state ? true : false;
	}
}

static int init_button(void)
{
	int err;

	err = dk_buttons_init(button_changed);
	if (err) {
		printk("Cannot init buttons (err: %d)\n", err);
	}

	return err;                                                                                                                                                                                                                                              
}

void main(void)
{       
        int blink_status = 0;
	int err;

	printk("Starting Bluetooth Peripheral LBS example\n");

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

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

	bt_conn_cb_register(&conn_callbacks);
	if (IS_ENABLED(CONFIG_BT_LBS_SECURITY_ENABLED)) {
	    bt_conn_auth_cb_register(&conn_auth_callbacks);
	}

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

	printk("Bluetooth initialized\n");

	if (IS_ENABLED(CONFIG_SETTINGS)) {
		settings_load();
	}

	err = bt_lbs_init(&lbs_callbacs);
	if (err) {
		printk("Failed to init LBS (err:%d)\n", err);
		return;
	}

	err = bt_le_adv_start(BT_LE_ADV_CONN_TEST, ad, ARRAY_SIZE(ad),
			      sd, ARRAY_SIZE(sd));
	if (err) {
		printk("Advertising failed to start (err %d)\n", err);
		return;
	}

	printk("Advertising successfully started\n");

	for (;;) {
		//dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
                //dk_set_led(RUN_STATUS_LED, 0);
		//k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
                k_cpu_idle();
	}
}

Parents Reply Children
  • Ok, so based on the blog, I have made some changes but get exactly the same result.

    1. I have added hci_rpmsg.conf in a folder in named child_image as described, copied ncs\v1.6.1\zephyr\samples\bluetooth\hci_rpmsg in and changed LOG and SERIAL to n

      CONFIG_LOG=n
      CONFIG_SERIAL=n
      
      CONFIG_RPMSG_SERVICE=y
      CONFIG_RPMSG_SERVICE_MODE_REMOTE=y
      
      CONFIG_HEAP_MEM_POOL_SIZE=8192
      
      CONFIG_MAIN_STACK_SIZE=512
      CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
      CONFIG_BT=y
      CONFIG_BT_HCI_RAW=y
      CONFIG_BT_MAX_CONN=16
      CONFIG_BT_CTLR_ASSERT_HANDLER=y
      CONFIG_BT_HCI_RAW_RESERVE=1
      
      CONFIG_ASSERT=y
      CONFIG_DEBUG_INFO=y
      CONFIG_EXCEPTION_STACK_TRACE=y


    2. Added the following to my prj.conf

      CONFIG_PM=y
      CONFIG_PM_DEVICE=y


    3. Disabled Uart0 and Uart1 in nrf5340dk_nrf5340_cpuappns.overlay

      &uart0{
      
          status="disabled";
      };
      
      &uart1{
      
          status="disabled";
      };


    I still get the base current of around 200uA as shown...

    On that blog post it says:

    "Power Management Subsystem can put an idle system in one of the supported power states, based on the selected power management policy and the duration of the idle time allotted by the kernel"

    I am making the idle call at the end of my main, do I also need to set some kind of power policy via my code?

  • I'm currently discussing the this internally, trying to find a good answer to this. I'm uncertain if adding CONFIG_PM will activate the Power Management automatically or if you need to enable it by adding e.g.

    /**
     * @brief Put processor into a power state.
     *
     * This function implements the SoC specific details necessary
     * to put the processor into available power states.
     *
     * @param info Power state which should be used in the ongoing
     *	suspend operation.
     */
    void pm_power_state_set(struct pm_state_info info)


    Or if the k_cpu_idle() is sufficient for your use. Can you please try adding Power Management hooks into your main?

  • Thanks for discussing internally, I will try the hooks tomorrow and let you know. 

  • Hi - I got this working. 

    It was a problem with segger embedded studio, there might be a potential bug with it. 

    It was not finding my .dtoverlay file - it had duplicated the path string behind the file so it could not find it. 

    When I stopped using the IDE and went to West on the terminal, it found the dtoverlay fine:

    -- Found devicetree overlay: /Users/mhazley/src/nrf-low-power-investigation/application/boards/nrf5340dk_nrf5340_cpuappns.overlay

    The build from west gave me an average current of 8uA

Related