Suspending uart with Zephyr console

NCS 3.02 54L10

I am using uart0 in async mode for printk and user input (my own callback not zephyr CLI). I need to be able to put the uart into suspend after an inactivity timeout to reduce current consumption.

Based on advice from ticket 344896 I am using rc = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND) gets me an error -88 Not Implemented.

These are my config options:

CONFIG_SERIAL=y
CONFIG_PM_DEVICE=y
CONFIG_UART_ASYNC_API=y
CONFIG_UART_ASYNC_ADAPTER=y
CONFIG_UART_CONSOLE=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y
CONFIG_CONSOLE=y

I get a feeling this might be because the console is using the driver? In any case, how can I force a shutdown of the uart? It doesn't matter if there is no way of restarting it outside of a reboot.

Parents Reply Children
  • Would you include relevant code snippets in your message please? All you've done is link to is a generic documentation page.

    if you're referring to the flash sleep code my modified version here returns UART suspend failed. (err -88)

    if (device_is_ready(uart)) {
      uint32_t err = pm_device_action_run(uart, PM_DEVICE_ACTION_SUSPEND);
      if (err) {
        printk("UART suspend failed. (err %d)\n", err);
      }
    } else
      printk("UART is not ready\n");

    I can actually kill the uart using nrf_uarte_disable(NRF_UARTE00) (thank you ChatGPT). But I need to handle this within Zephyr as this code needs to be hardware agnostic; currently it's running on 54L10 and 52832 with different uarts.

    I know for a fact the uart isn't actually sending when I'm trying to suspend it - it's an inactivity timeout after all!

  • Here is the test code:

    	if (device_is_ready(uart_dev))
        {
    		printk("Put the peripheral into suspended state.\n");
    		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);
    		if (err) {
    			printk("UART resume failed. (err %d)\n", err);
    		} else {
    			printk("Resume the peripheral from the suspended state.\n");
    		}
    	} else {
    		printk("UART device not ready.\n");
    	}

    My test project: hello_world_361858.7z
    Expect outlog:

    “Beware that this code/configuration is not fully tested or qualified and should be considered provided “as-is”. Please test it with your application and let me know if you find any issues.”

  • Thanks, this works OK for me.

    Back to my project, it seems it is because I am using Async. After a bit of hacking around this is the offending code in my uart_init, culled from your peripheral_uart example:

    		/* Implement API adapter */
    		uart_async_adapter_init(async_adapter, uart);
    		uart = async_adapter;

    Removing it my CLI no longer works of course, but uart suspend/resume now does. (Note the CLI is my own using a uart callback rather than Zephyr's, because the Zephyr CLI doesn't support the format required for this app)

    Given this, any ideas how to suspend the uart?

  • Why is an adapter used instead of native async support in the UART driver? Our R&D thinks the adapter was mainly added to emulate the UART async API on devices that do not support it (primarily for USB CDC ACM). When using UART0, I would not use the adapter at all.

Related