nRF54LM20A DK – Sleep current rises to 270 µA after USB VBUS removal when CONFIG_BT=y is set (NCS v3.2.1)

Board: nRF54LM20A DK NCS version: v3.2.1 Sample base:  nrf/samples/zephyr/subsys/usb/cdc_acm


Background

I am evaluating power consumption on the nRF54LM20A DK before integrating both USB (CDC ACM) and Bluetooth LE into a production product. I noticed an unexpected increase in sleep current when CONFIG_BT=y is added, even though the Bluetooth stack is never initialized or used in the application code.


Test Setup

I started from the standard cdc_acm sample, modified main() as shown below, and added the following to prj.conf:

CONFIG_PM_DEVICE=y 
CONFIG_PM_DEVICE_RUNTIME=y

main.c (simplified):

int main(void) { 
    int ret; 
    if (!device_is_ready(uart_dev)) { 
        LOG_ERR("CDC ACM device not ready"); 
        return 0; 
    } 
    ret = enable_usb_device_next(); 
    if (ret != 0) { 
        LOG_ERR("Failed to enable USB device support"); 
        return 0; 
    } return 0; 
}

All other code and configuration are identical to the stock sample.


Measurement Procedure

  1. Flash firmware, then measure current before inserting USB — result: ~4 µA White check mark
  2. Insert USB VBUS, then remove it — result: current rises to ~270 µA X
  3. Only a full reboot restores the current to ~4 µA

Reproducing the Problem

When I add only the following line to prj.conf (keeping everything else the same), the issue appears:

CONFIG_BT=y

Without CONFIG_BT=y, the current correctly returns to ~4 µA after VBUS is removed.

The Bluetooth stack is never initialized (no bt_enable() call) and no BLE functionality is used in the test code.


Questions

  1. Is this a known interaction between the USB device stack and the Bluetooth subsystem on the nRF54LM20A when CONFIG_BT=y is set, even without the stack being actively used?
  2. Does enabling CONFIG_BT=y implicitly activate peripherals or clocks that are not released properly after USB VBUS removal?
  3. Is there a recommended way to cleanly handle VBUS removal and ensure all relevant peripherals (including those pulled in by CONFIG_BT=y) return to their low-power state without a full reboot?

Any guidance or pointers to relevant documentation or samples would be greatly appreciated. Thank you.

Parents
  • Hi,

    It is very strange that the BT config is showing power implications on USB. I need to try this tomorrow and will come back with some observations most likely by Friday.

  • Hi ,
    Thanks for letting me know. Standing by for your observations. 

  • Hi,
    • Measurement Tool: I am using an Amp meter to measure the current.
    • Logs & Debugger: I have not disabled logs, and the debugger USB wire is still connected during the test.
    I have attached my sample code below so we can ensure we are testing the exact same configuration.

  • cdc_acm.7z

    /*
     * Copyright (c) 2019 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <sample_usbd.h>
    
    #include <stdio.h>
    #include <string.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/uart.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/ring_buffer.h>
    
    #include <zephyr/usb/usbd.h>
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(cdc_acm_echo, LOG_LEVEL_INF);
    
    const struct device *const uart_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
    
    #define RING_BUF_SIZE 1024
    uint8_t ring_buffer[RING_BUF_SIZE];
    
    struct ring_buf ringbuf;
    
    static bool rx_throttled;
    
    static inline void print_baudrate(const struct device *dev)
    {
    	uint32_t baudrate;
    	int ret;
    
    	ret = uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
    	if (ret) {
    		LOG_WRN("Failed to get baudrate, ret code %d", ret);
    	} else {
    		LOG_INF("Baudrate %u", baudrate);
    	}
    }
    
    static struct usbd_context *sample_usbd;
    K_SEM_DEFINE(dtr_sem, 0, 1);
    
    static void sample_msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg)
    {
    	LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type));
    
    	if (usbd_can_detect_vbus(ctx)) {
    		if (msg->type == USBD_MSG_VBUS_READY) {
    			if (usbd_enable(ctx)) {
    				LOG_ERR("Failed to enable device support");
    			}
    		}
    
    		if (msg->type == USBD_MSG_VBUS_REMOVED) {
    			if (usbd_disable(ctx)) {
    				LOG_ERR("Failed to disable device support");
    			}
    		}
    	}
    
    	if (msg->type == USBD_MSG_CDC_ACM_CONTROL_LINE_STATE) {
    		uint32_t dtr = 0U;
    
    		uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_DTR, &dtr);
    		if (dtr) {
    			k_sem_give(&dtr_sem);
    		}
    	}
    
    	if (msg->type == USBD_MSG_CDC_ACM_LINE_CODING) {
    		print_baudrate(msg->dev);
    	}
    }
    
    static int enable_usb_device_next(void)
    {
    	int err;
    
    	sample_usbd = sample_usbd_init_device(sample_msg_cb);
    	if (sample_usbd == NULL) {
    		LOG_ERR("Failed to initialize USB device");
    		return -ENODEV;
    	}
    
    	if (!usbd_can_detect_vbus(sample_usbd)) {
    		err = usbd_enable(sample_usbd);
    		if (err) {
    			LOG_ERR("Failed to enable device support");
    			return err;
    		}
    	}
    
    	LOG_INF("USB device support enabled");
    
    	return 0;
    }
    
    static void interrupt_handler(const struct device *dev, void *user_data)
    {
    	ARG_UNUSED(user_data);
    
    	while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
    		if (!rx_throttled && uart_irq_rx_ready(dev)) {
    			int recv_len, rb_len;
    			uint8_t buffer[64];
    			size_t len = MIN(ring_buf_space_get(&ringbuf),
    					 sizeof(buffer));
    
    			if (len == 0) {
    				/* Throttle because ring buffer is full */
    				uart_irq_rx_disable(dev);
    				rx_throttled = true;
    				continue;
    			}
    
    			recv_len = uart_fifo_read(dev, buffer, len);
    			if (recv_len < 0) {
    				LOG_ERR("Failed to read UART FIFO");
    				recv_len = 0;
    			};
    
    			rb_len = ring_buf_put(&ringbuf, buffer, recv_len);
    			if (rb_len < recv_len) {
    				LOG_ERR("Drop %u bytes", recv_len - rb_len);
    			}
    
    			LOG_DBG("tty fifo -> ringbuf %d bytes", rb_len);
    			if (rb_len) {
    				uart_irq_tx_enable(dev);
    			}
    		}
    
    		if (uart_irq_tx_ready(dev)) {
    			uint8_t buffer[64];
    			int rb_len, send_len;
    
    			rb_len = ring_buf_get(&ringbuf, buffer, sizeof(buffer));
    			if (!rb_len) {
    				LOG_DBG("Ring buffer empty, disable TX IRQ");
    				uart_irq_tx_disable(dev);
    				continue;
    			}
    
    			if (rx_throttled) {
    				uart_irq_rx_enable(dev);
    				rx_throttled = false;
    			}
    
    			send_len = uart_fifo_fill(dev, buffer, rb_len);
    			if (send_len < rb_len) {
    				LOG_ERR("Drop %d bytes", rb_len - send_len);
    			}
    
    			LOG_DBG("ringbuf -> tty fifo %d bytes", send_len);
    		}
    	}
    }
    
    int main(void)
    {
    	int ret;
    
    	if (!device_is_ready(uart_dev)) {
    		LOG_ERR("CDC ACM device not ready");
    		return 0;
    	}
    
    	ret = enable_usb_device_next();
    	if (ret != 0) {
    		LOG_ERR("Failed to enable USB device support");
    		return 0;
    	}
    
    	return 0;
    }
    

  • Hi,
    A key question worth asking: Did you plug in the USB first, then unplug it, and then measure the current?

  • Did you encounter the same issue (sleep current rising to ~270 µA) after plugging in and then unplugging the USB using the same configuration?

Reply Children
No Data
Related