Low power - disable UART while maintaining printk or printf functionality

So whatever I try, the only way to get my idle current consumption to an acceptable low value is to set CONFIG_SERIAL=n in my configuration. But then I don't get printk functionality. The lowest I can achieve using a nRF52DK & PPK2 is about 1mA, compared to 7uA with CONFIG_SERIAL=n.

I looked at lpuart, but I can't use that because I can't implement the handshake protocol, and the lpuart sample doesn't use printk anyway, it uses a raw buffer.

My gut feeling is it's the kernel keeping the uart alive.

I need ultra low power, but still need to send a report over uart based on a BLE event. This is for a port of an existing application built under SDK17 where I would simply set the register NRF_UART0->ENABLE directly.

This is using NCS 2.9.0

Can you advise?

Parents Reply Children
  • Sounds good,

    Can RX be re-enabled by code in this way? Sorry, I omitted to say earlier that I do also need to enable uart RX sometimes... I currently have a GPIO input dedicated to the task, think of it as half of the lpuart arrangement.

    (I can't change the hardware or handshaking arrangement as I need this code to be retro-compatible to existing product)

    FYI The uart is used primarily for sending a data packet to a connected system after a BLE transaction, but it is also used for a CLI interface for configuration by the user. Otherwise it will be idle.

    Thanks

  • I see. It is not possible to enable RX with this property set in the Devicetree. However, if you set CONFIG_PM_DEVICE=y in your configuration, you can use the "suspend" and "resume" action to control when the uart is to be enabled and disabled.

    #include <zephyr/pm/device.h>
    
    static struct device const *uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
    
    ...
    
    int main(void)
    { 
        ...
        
    	/* Disable UART to reduce System ON idle current */
    	err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
    	if (err) {
    		printk("UART suspend failed. (err %d)\n", err);
    		return 1;
    	}
    

  • Thank you, that's much better!! I tried it using the Hello World example for simplicity - now I get 16uA vs 1.1mA

    int main(void)
    {
    	int err;
    	while(true)
    	{
    		printf("Hello World! %s\n", CONFIG_BOARD_TARGET);
    		err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
    		if (err) {
    			printk("UART suspend failed. (err %d)\n", err);}
    		k_sleep(K_MSEC(1000));
    		err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
    	}
    	
    	return 0;
    }

Related