UART Rx interrupt not enabled after PM_DEVICE_ACTION_RESUME

Hello,

I'm adding power management to a custom driver that talks to a sensor via uart2 of the nRF9151DK. But from my tests it seems that uart_irq_rx_enable()  has no effect after the driver resumes the uart device with pm_device_runtime_get().

The driver has three functions:

turn_on(): Runs pm_device_runtime_get() to resume uart operation and sets a gpio high to enable the sensor.

turn_off(): Runs pm_device_runtime_put() to suspend uart operation and set a gpio low to disable the sensor.

sample_fetch(): Sends a command to the sensor and waits for the rx buffer to have the expected response size in bytes, using a semaphore with a 1s timeout.

The pm_action callback function is:


static int sensor_pm_action(const struct device *dev,
                             enum pm_device_action action)
{
    const struct sensor_cfg *cfg = dev->config;
    struct gpio_dt_spec en_gpio = cfg->en_gpio;
    int ret = 0;

    switch (action)
    {
    case PM_DEVICE_ACTION_RESUME:
        LOG_INF("Resuming sensor");
        
        /* Re-initialize the sensor */
        ret = sensor_init(dev);
        break;

    case PM_DEVICE_ACTION_SUSPEND:
        LOG_INF("Suspending sensor");
        
        /* Disconnect GPIO */
        gpio_pin_configure((&en_gpio)->port, (&en_gpio)->pin, GPIO_INPUT | GPIO_DISCONNECTED);

        break;
    default:
        return -ENOTSUP;
    }

    return ret;
}

 The driver init function sets up the uart paramenters:

static int sensor_init(const struct device *dev)
{
    const struct sensor_cfg *cfg = dev->config;
    struct sensor_data *data = dev->data;
    struct gpio_dt_spec en_gpio = cfg->en_gpio;
    int ret = 0;

    LOG_DBG("Initializing sensor driver");

    if (!gpio_is_ready_dt(&en_gpio))
    {
        LOG_ERR("Sensor EN pin not ready");
        return -ENOSYS;
    }

    gpio_pin_configure((&en_gpio)->port, (&en_gpio)->pin, GPIO_OUTPUT);
    gpio_pin_set_dt(&en_gpio, 0);

    if (!device_is_ready(cfg->uart_dev))
    {
        LOG_ERR("UART not ready");
        return -ENOSYS;
    }

    uart_irq_rx_disable(cfg->uart_dev);
    uart_irq_tx_disable(cfg->uart_dev);

    ret = uart_configure(cfg->uart_dev, &uart_cfg_sensor);

    if (ret == -ENOSYS)
    {
        LOG_ERR("Unable to configure UART port");
        return -ENOSYS;
    }

    ret = uart_irq_callback_user_data_set(cfg->uart_dev, cfg->cb, (void *)dev);

    if (ret < 0)
    {
        if (ret == -ENOTSUP)
        {
            LOG_ERR("Interrupt-driven UART API support not enabled");
        }
        else if (ret == -ENOSYS)
        {
            LOG_ERR("UART device does not support interrupt-driven API");
        }
        else
        {
            LOG_ERR("Error setting UART callback: %d", ret);
        }
        return ret;
    }

    if (ret == -ENOSYS)
    {
        LOG_ERR("Unable to configure UART");
        return -ENOSYS;
    }

    data->rx_index = 0;
    data->tx_index = 0;

    k_sem_init(&data->tx_sem, 1, 1);
    k_sem_init(&data->rx_sem, 0, 1);

    return ret;
}

App overlay file:

&uart2 {
    status = "okay";
    current-speed = <4800>;
    pinctrl-0 = <&uart2_default>;
    pinctrl-1 = <&uart2_sleep>;
    pinctrl-names = "default", "sleep";
    zephyr,pm-device-runtime-auto;

    sensor_test: sensor {
        compatible = "sensor";
        en-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
        status = "okay";
        zephyr,pm-device-runtime-auto;
    };
};

&pinctrl {
    uart2_default: uart2_default {
        group1 {
            psels = <NRF_PSEL(UART_TX, 0, 24)>,
                    <NRF_PSEL(UART_RTS, 0, 23)>;
        };
        group2 {
            psels = <NRF_PSEL(UART_RX, 0, 25)>,
                    <NRF_PSEL(UART_CTS, 0, 17)>;
            bias-pull-up;
        };
    };

    uart2_sleep: uart2_sleep {
        group1 {
            psels = <NRF_PSEL(UART_TX, 0, 24)>,
                    <NRF_PSEL(UART_RX, 0, 25)>,
                    <NRF_PSEL(UART_RTS, 0, 23)>,
                    <NRF_PSEL(UART_CTS, 0, 17)>;
            low-power-enable;
        };
    };
};

And prj.conf file:

CONFIG_GPIO=y
CONFIG_LOG=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y

CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_SENSOR=y
CONFIG_CUSTOM_SENSOR_DRIVER=y
CONFIG_CUSTOM_SENSOR=y

CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y

CONFIG_TFM_SECURE_UART=n
CONFIG_TFM_LOG_LEVEL_SILENCE=y

If the  zephyr,pm-device-runtime-auto is removed from the uart node in devicetree, the driver gets the response form the sensor.

Any ideas of what is causing this? Thanks!

Best regards,

Lalo

  • Can you share a schematic or similar on how this is setup? There's an enable pin in the mix here as well on P0.07, what is its function?

    P0.07 is connected to the transceiver's EN pin.

    What is the configured IO voltage of the nRF9151-DK?

    3.3V

    It is hard to see what line is from the nRF and which is from the sensor, NRF_RXD or is it SENSOR_RXD that is misbehaving?

    The teal trace is NRF_RXD, in both cases -with an wihout zephyr,pm-device-runtime-auto selected in the uart node-, the sensor sends a valid response. So the Rx timeout should be related to the pm config and not hardware related.

    Best regards,

    Lalo  

  • Hi,

     

    Could you share a schematic or any info about your sensor setup?

    Håkon Alseth said:
    Can you share a schematic or similar on how this is setup?

    NRF_RXD shall be driven by the EXT_SENSOR_TXD pin.

    One of the sides is pulling the pin. If you disconnect either side, you can measure which side tries to pull low.

    If it is the NRF, check the NRF_GPIO register for the specific pin to see if it is set as output low.

     

    Kind regards,

    Håkon

  • Hi Håkon,

    Could you share a schematic or any info about your sensor setup?

    The colors correspond to the scope traces mentioned above.

    As mentioned before, regardless of whether zephyr,pm-device-runtime-auto is enabled under the uart node, the trace shows a response in the NRF_RXD (teal trace) pin.

    The strange behavior of the NRF_TXD (yellow trace) when zephyr,pm-device-runtime-auto is enabled -although not optimal- is not affecting the correct transmition of the command to the sensor, and the subsequent response from the sensor is received in the NRF_RXD pin. 

    This in my opinion discards any hardware related issues and points to some configuration issue in the uart power management that is not enabling rx interrupts when the device is reactivated.

    BR,

    Lalo

  • Hi,

     

    Thank you for sharing a schematic.

    Are you using THVD1426DR (https://www.ti.com/lit/ds/symlink/thvd1426.pdf)? I was not able to get any hits on ..1436DR.

     

    Lalo_16 said:

    The strange behavior of the NRF_TXD (yellow trace) when zephyr,pm-device-runtime-auto is enabled -although not optimal- is not affecting the correct transmition of the command to the sensor, and the subsequent response from the sensor is received in the NRF_RXD pin. 

    This in my opinion discards any hardware related issues and points to some configuration issue in the uart power management that is not enabling rx interrupts when the device is reactivated.

    Thank you again for clarifying.

    You have an external pull up on that line. Given that the signal is between VDD and GND, it indicates that you have a component that is pulling down on that line. It seems to settle at around 2.5V, as compared to the expected 3.3V.

    I highly suspect that this is the nRF TXD GPIO which is in a output state, when you're switching off the transceiver device. Have you tried re-configuring P0.24 to be floating when you place your ext sensor in a suspended state?

    You are suspending your sensor, and not the (NRF) UARTE peripheral.

     

    Kind regards,

    Håkon

Related