Issue with resuming UART1 on nRF9151 after PM suspend with BLE module

Board/Setup:

  • Board: nRF9151 DK / nRF9151 SoC

  • Peripheral: External BLE module connected via UART1

  • Use case: BLE module is only needed during commissioning. After commissioning, it can remain powered down to save energy.

Scenario / Problem:
We are using Zephyr OS with the nRF Connect SDK. Our goal is to reduce power consumption when the BLE module is not needed.

  • With UART1 running continuously for BLE communication, the device consumes ~7 mA.

  • When we suspend UART1 using Zephyr PM (pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND)), the current drops to ~700 μA, which is acceptable.

  • Issue: After suspending UART1, attempting to resume it using pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME) followed by uart_config_get() or uart_configure() consistently fails with -134 (EIO).

From investigation:

  • The PM resume successfully powers the UART peripheral, but the hardware is not responsive immediately.

  • uart_config_get() fails both before suspend and after resume if the BLE transport or peripheral is active, because the driver cannot communicate with the hardware.

  • Adding delays after resume does not solve the problem.

Goal:

  • Suspend UART1 to save power when BLE is not needed.

  • Be able to resume UART1 reliably when commissioning is required again.

  • Avoid relying on uart_config_get() since it fails with the current setup.

My Code:

/* Suspend UART device */
int ble_uart_suspend(void)
{
	int err;

	if (!device_is_ready(uart_dev))
	{
		WR_ERR("UART device not ready\n");
		return -ENODEV;
	}

	err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
	if (err)
	{
		WR_ERR("Failed to suspend UART: %d\n", err);
		return err;
	}

	WR_INF("UART suspended successfully\n");
	return 0;
}

/* Resume UART device */
int ble_uart_resume(void)
{
	int err;

	if (!device_is_ready(uart_dev))
	{
		WR_ERR("UART device not ready");
		return -ENODEV;
	}

	err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
	if (err)
	{
		WR_ERR("Failed to resume UART: %d", err);
		return err;
	}

	WR_INF("UART resumed successfully");
	return 0;
}

Support Needed:

  1. Is there a recommended way in Zephyr to safely resume a UART peripheral connected to a BLE module on nRF9151 after PM suspend?

  2. Are there any platform-specific constraints on nRF91 UART peripherals that we need to account for when suspending/resuming?

  3. Can the approach of using a static UART configuration safely replace uart_config_get() in this scenario?

Parents
  • the current drops to ~700 μA, which is acceptable

    You accept 100x more than it should be, at least considering the nRF9151 (~7µA).

    I frequently use pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND) and pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME). After resume the first bytes may be lost or crippled, but a "retry" usually solves that.

    I'm not aware, that the UART needs to be explicitly reconfigured after suspend/resume.
     

  • You accept 100x more than it should be, at least considering the nRF9151 (~7µA).

    I

    When I call system_off(), the current drops to around 5 µA, since most of my peripherals are off. Without this, the consumption is about 700 µA (after suspending UART1), which is still better than the 7 mA I had before. The 700 µA draw mainly comes from two sensors on I²C. One of them, the LIS2DW12, requires continuous power. I can’t power it off because it loses its configuration and only outputs 0 after wake-up. So most of the 700 µA consumption is due to this sensor.

    In my code, if I don’t call pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND) and let it run as before, my BLE module works fine. But when I call suspend and then resume, it stops working.

    I have two UARTs in my application: UART0 for debugging and UART1 for the BLE module.

    I am also suspending the Zephyr console, and after resuming it.

  • Not sure, why you get these results.

    About the uart_config_get():

    Did you enable the required CONFIG_UART_USE_RUNTIME_CONFIGURE ? If not, try that ;-).

    It's long ago, that I was common with debugging UART issues. What helped me in that past was a 2 channel UART2USB TTL converter (or 2 single channel). The TTL level must match your GPIO level (e.g. 3.3V). Connect the RXs of the 2 Channel UART2USB with both UART (rx/tx) you want to debug. That should make it visible, what's going on.

    As I wrote, I would assume some lost or crippled bytes, and a retransmission should help here. Crossing the fingers. 

Reply
  • Not sure, why you get these results.

    About the uart_config_get():

    Did you enable the required CONFIG_UART_USE_RUNTIME_CONFIGURE ? If not, try that ;-).

    It's long ago, that I was common with debugging UART issues. What helped me in that past was a 2 channel UART2USB TTL converter (or 2 single channel). The TTL level must match your GPIO level (e.g. 3.3V). Connect the RXs of the 2 Channel UART2USB with both UART (rx/tx) you want to debug. That should make it visible, what's going on.

    As I wrote, I would assume some lost or crippled bytes, and a retransmission should help here. Crossing the fingers. 

Children
Related