Suspending the UART using PM_DEVICE ACTION_SUSPEND does not reduce power consumption that much

Hello

As the title says, I am suspending the UART using PM_DEVICE ACTION_SUSPEND, but the power consumption is not decreasing significantly.

With CONFIG_SERIAL=n and no UART used, power consumption is now around 20uA.

When using pm_device_action_run, the power consumption was about 1.3mA.

Please tell me the correct way to stop UART.

SDK : nrf Connect SDK 2.6.1

Board : Raytac MDBT42Q-DB

#include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/logging/log.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/uart.h>

LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

static uint8_t Buffer[16];

static const struct device *Uart = DEVICE_DT_GET(DT_NODELABEL(uart0));

static void Callback(const struct device *dev, struct uart_event *evt, void *user_data);

int main(void)
{
#if defined(CONFIG_SERIAL)
    if (!device_is_ready(Uart))
    {
        LOG_ERR("device is not ready");
        return 0;
    }

    const struct uart_config cfg = {
        .baudrate = 1000000,
        .parity = UART_CFG_PARITY_NONE,
        .stop_bits = UART_CFG_STOP_BITS_1,
        .data_bits = UART_CFG_DATA_BITS_8,
        .flow_ctrl = UART_CFG_FLOW_CTRL_RTS_CTS,
    };

    int err = uart_configure(Uart, &cfg);
    if (err)
    {
        LOG_ERR("uart_configure (%d)", err);
        return 0;
    }

    err = uart_callback_set(Uart, Callback, NULL);
    if (err)
    {
        LOG_ERR("uart_callback_set (%d)", err);
        return 0;
    }

    err = uart_rx_enable(Uart, Buffer, sizeof(Buffer), 1000);
    if (err)
    {
        LOG_ERR("uart_rx_enable (%d)", err);
        return err;
    }

    int count = 0;
    while (count < 10)
    {
        k_msleep(1000);
        LOG_INF(".");
        count++;
    }
    err = pm_device_action_run(Uart, PM_DEVICE_ACTION_SUSPEND);
    if (err)
    {
        LOG_ERR("pm_device_action_run (%d)", err);
        return 0;
    }
    else
    {
        LOG_INF("SUSPEND");
    }
#endif
    while(true)
    {
        k_msleep(1000);
        LOG_INF(".");
    }

    return 0;
}

static void Callback(const struct device *dev, struct uart_event *evt, void *user_data)
{
    switch (evt->type)
    {
    case UART_TX_DONE:

        break;
    case UART_TX_ABORTED:

        break;
    case UART_RX_RDY:

        break;
    case UART_RX_BUF_REQUEST:

        break;
    case UART_RX_BUF_RELEASED:

        break;
    case UART_RX_DISABLED:

        break;
    case UART_RX_STOPPED:

        break;
    default:
        break;
    }
}

Parents
  • Using the uart_rx_disable() function or receiving data to disable the UART RX has significantly reduced power consumption.

    Using the uart_rx_disable() function alone does not yet disable GPIO, so PM_DEVICE_ACTION_SUSPEND was also used to reduce power consumption to the ideal value.

    The power consumption results for each pattern are shown below.

    pattern 1 : use PM_DEVICE_ACTION_SUSPEND

    pattern 2 : use uart_rx_disable()

    pattern 3 : use uart_rx_disable() & PM_DEVICE_ACTION_SUSPEND

    The source code is shown below.

    int main(void)
    {
        if (!device_is_ready(Uart))
        {
            LOG_ERR("device is not ready");
            return 0;
        }
    
        const struct uart_config cfg = {
            .baudrate = 1000000,
            .parity = UART_CFG_PARITY_NONE,
            .stop_bits = UART_CFG_STOP_BITS_1,
            .data_bits = UART_CFG_DATA_BITS_8,
            .flow_ctrl = UART_CFG_FLOW_CTRL_RTS_CTS,
        };
    
        int err = uart_configure(Uart, &cfg);
        if (err)
        {
            LOG_ERR("uart_configure (%d)", err);
            return 0;
        }
    
        err = uart_callback_set(Uart, Callback, NULL);
        if (err)
        {
            LOG_ERR("uart_callback_set (%d)", err);
            return 0;
        }
    
        err = uart_rx_enable(Uart, Buffer, sizeof(Buffer), 1000);
        LOG_INF("uart_rx_enable (%d)", err);
    
        k_msleep(1000);
    
        err = pm_device_action_run(Uart, PM_DEVICE_ACTION_SUSPEND);
    
        err = uart_rx_disable(Uart);
    
        k_msleep(1000);
    
        err = pm_device_action_run(Uart, PM_DEVICE_ACTION_RESUME);
    
        err = uart_rx_disable(Uart);
        LOG_INF("uart_rx_disable (%d)", err);
    
        k_msleep(10);
    
        err = uart_rx_enable(Uart, Buffer, sizeof(Buffer), 1000);
        LOG_INF("uart_rx_enable (%d)", err);
    
        return 0;
    }

    The above code works, is this method correct?

Reply
  • Using the uart_rx_disable() function or receiving data to disable the UART RX has significantly reduced power consumption.

    Using the uart_rx_disable() function alone does not yet disable GPIO, so PM_DEVICE_ACTION_SUSPEND was also used to reduce power consumption to the ideal value.

    The power consumption results for each pattern are shown below.

    pattern 1 : use PM_DEVICE_ACTION_SUSPEND

    pattern 2 : use uart_rx_disable()

    pattern 3 : use uart_rx_disable() & PM_DEVICE_ACTION_SUSPEND

    The source code is shown below.

    int main(void)
    {
        if (!device_is_ready(Uart))
        {
            LOG_ERR("device is not ready");
            return 0;
        }
    
        const struct uart_config cfg = {
            .baudrate = 1000000,
            .parity = UART_CFG_PARITY_NONE,
            .stop_bits = UART_CFG_STOP_BITS_1,
            .data_bits = UART_CFG_DATA_BITS_8,
            .flow_ctrl = UART_CFG_FLOW_CTRL_RTS_CTS,
        };
    
        int err = uart_configure(Uart, &cfg);
        if (err)
        {
            LOG_ERR("uart_configure (%d)", err);
            return 0;
        }
    
        err = uart_callback_set(Uart, Callback, NULL);
        if (err)
        {
            LOG_ERR("uart_callback_set (%d)", err);
            return 0;
        }
    
        err = uart_rx_enable(Uart, Buffer, sizeof(Buffer), 1000);
        LOG_INF("uart_rx_enable (%d)", err);
    
        k_msleep(1000);
    
        err = pm_device_action_run(Uart, PM_DEVICE_ACTION_SUSPEND);
    
        err = uart_rx_disable(Uart);
    
        k_msleep(1000);
    
        err = pm_device_action_run(Uart, PM_DEVICE_ACTION_RESUME);
    
        err = uart_rx_disable(Uart);
        LOG_INF("uart_rx_disable (%d)", err);
    
        k_msleep(10);
    
        err = uart_rx_enable(Uart, Buffer, sizeof(Buffer), 1000);
        LOG_INF("uart_rx_enable (%d)", err);
    
        return 0;
    }

    The above code works, is this method correct?

Children
No Data
Related