Device PowerManagement and NRF Uarte

Hi!

I want to integrate power management into our FW. Therefor I did enable it in the prj.conf:

CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y

And added runtime enable and action run calls regarding this device during bootup phase:

error = pm_device_runtime_enable(dev);
....
error = pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
....
error = uart_rx_enable(dev, buffer, UART_BUFFER_SIZE, UART_RECEIVE_TIMEOUT);
....

To test the pm of the UART, I created a timer which, when expired, switches between suspend and resume for this uart.


After BootUp, this timer is not yet started. So the uart was configured, pm runtime was enabled and the dev was resumed after runtime enable.
Therefor the device is active and I can send a message to it and receive an answer.

However, after the first message exchange, the timer (for pm tests) is activated. It does the switch between active->suspended->active and the UART stopped working.

Here the code which does the switch:

ret = pm_device_state_get(dev, &state);
if (ret == 0)
{
    if (state == PM_DEVICE_STATE_SUSPENDED)
    {
        ret = pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
        LOG_INF("pm action run ret: %d, new state: %s", ret, pm_device_state_str_get(dev));
    }
    else if(suspend > 0)
    {
        ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
        LOG_INF("pm action run ret: %d, new state: %s", ret, pm_device_state_str_get(dev));
        suspend--;
    }
}

For testing, I added an counter "suspend" which is static set to 1 to suspend only once.

Any Idea, why the uart receives only Zero-Bytes after the second switch between active and suspended?
And I get some Overrun errors, but I think this is not the cause but impact of the problem, as the overrun errors start to appear after the first byte received:

[00:00:06.938,110] <inf> d_uart: pm action run ret: 0, new state: active
[00:00:09.444,946] <inf> d_uart: uart@8000: received 1 bytes from queue.
[00:00:09.444,976] <inf> m_isn_uart_if: 0x00
[00:00:11.706,573] <err> d_uart: uart@8000: RX Stopped! Reson(0x01): ERROR_OVERRUN
[00:00:11.706,634] <err> d_uart: uart@8000: RX Stopped! Reson(0x01): ERROR_OVERRUN
[00:00:11.706,726] <err> d_uart: uart@8000: RX Stopped! Reson(0x01): ERROR_OVERRUN
[00:00:11.706,817] <err> d_uart: uart@8000: RX Stopped! Reson(0x01): ERROR_OVERRUN
[00:00:11.706,878] <err> d_uart: uart@8000: RX Stopped! Reson(0x01): ERROR_OVERRUN
[00:00:11.706,970] <err> d_uart: uart@8000: RX Stopped! Reson(0x01): ERROR_OVERRUN
[00:00:11.707,092] <wrn> d_uart: uart@8000: Buffer released!
[00:00:11.707,122] <wrn> d_uart: uart@8000: Buffer released!
[00:00:11.707,122] <wrn> d_uart: uart@8000: Disabled!
[00:00:11.707,153] <wrn> d_uart: uart@8000: Buffer requested!

Cheers,
Thilo

  • Problem found!

    		err = uart_rx_disable(uart);
    		__ASSERT(err == 0, "Failed to disable uart rx");
    
    		err = pm_device_action_run(uart, PM_DEVICE_ACTION_SUSPEND);
    		__ASSERT(err == 0, "Failed to suspend uart device");


    I need to wait, until the RX_DISABLED Interrupt occurred before I suspend the uart. 
    A simple k_sleep between uart_rx_disable and pm_device_action_run (.... SUSPEND) worked, as an quick test.

    The better way would be, that the uart callback will report an event that the rx is disabled of course.

    This ticket is done, from my point of view.

    Thanks!

    Cheers,
    Thilo

Related