UART_RX_RDY not called after RESUME

Hello,

I am working on a project were two MCU's need to communicate with each other via UART. I am using async UART. I am stuck with this problem where after

PM_DEVICE_ACTION_RESUME call the uart_device is in Active state but UART_RX_RDY  is not called and I know for sure that there are incoming data. I am probably missing something obvious. 

To elaborate a little more about the specifics. The two MCU's are connected via UART and some GPIO's. The idea is that LTE module receives data, suspends UART driver, uplink the received data and go to PSM. To resume the UART device I used one GPIO with interrupt. When the other MCU pulls GPIO high an interrupt fires, resumes the UART device and waits for data. But instead I get UART_RX_STOPPED and UART_RX_DISABLED because the other MCU turned off its UART and now its pulling RX line low. 
I tried to uart_rx_enable after the PM_DEVICE_ACTION_RESUME but it returns error as expected because reception was never disabled. 
Everything works fine if I remove pm_device_action_run from UART driver and set other MCU to pull the nRF9160 RX pin high instead of low. That's why I am pretty sure that there is something missing in nRF9160 code not on the other MCU


Here are some code snippets how I enable/disable the driver. It's still a bit messy because I was testing what works and what doesn't:
static int gpioCallback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    int err;
    err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
    if (err && err != -EALREADY)
    {
        // LOG_ERR("Call `pm_device_action_run` failed: %d", err);
    }

    if (!device_is_ready(uart_dev))
    {
        // LOG_ERR("Device not ready");
    }
    // LOG_INF("UART waked up");
}
    case UART_RX_RDY:
        size_t offset = evt->data.rx.offset;
        size = evt->data.rx.len;
        memcpy(rxBuf, &evt->data.rx.buf[offset], size);

        // Enable CoAP work to transmit newly received data
        k_work_schedule(workCoap, K_NO_WAIT);
        err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
        if (err && err != -EALREADY) 
        {
            LOG_ERR("Call `pm_device_action_run` failed: %d", err);
        }
        break;
Any ideas?
Parents
  • Hello,

    Have you tried enabling the receiver again after the UART_RX_DISABLED event?

    The UART_RX_STOPPED is raised if an error condition has been detected on the bus. For instance, if the receiver is enabled why the other MCU pulls the RX line low. 

    Best regards,

    Vidar

  • I discovered that if I do something like this: 

        int err = pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
        if (err && err != -EALREADY) 
        {
            // LOG_ERR("Call `pm_device_action_run` failed: %d", err);
        }
    
        err = uart_rx_disable(uart_dev);
        if(err !=0)
        {
            LOG_ERR("uart_rx_disable err %d", err);
        }
        err = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
        if(err !=0)
        {
            LOG_ERR("k_mem_slab_alloc err %d", err);
        }
        k_sleep(K_SECONDS(1)); // So that DISABLED event is received
        err = uart_rx_enable(uart_dev, buf, BUF_SIZE, 10000);
        if(err !=0)
        {
            LOG_ERR("uart_rx_enable err %d", err);
        }
    }

    I am able to receive data. This means that I SUSPEND the uart_dev, then RESUME and basically re-init the reception buffer. It seems that this is not the right way to do it. I don't like the delay inbetween the disable/enable rx functions it just adds more power consumption while the device is not doing anything.

    One question related to power consumption - to save as much power as possible, can I just call uart_rx_disable and when necessary uart_rx_enable or for better performance I should use the PM device calls to SUSPEND/RESUME as I was doing it for now? 

    Regards,

    Andris

  • Hi Andris, 

    It's not clear to me if you are receiving a valid RX frame or not when you receive the UART_RX_STOPPED event, have you probed the RX signal with scope? The suspend task follows the sequence outlined here Low power to ensure the peripheral is properly powered down. The implementation for it can be found here: https://github.com/nrfconnect/sdk-zephyr/blob/41095df79d11e081ea96d150fbe3dbd93f73af6c/drivers/serial/uart_nrfx_uarte.c#L1902 

    You should also consider requesting the crystal oscillator when the UARTE is enabled if you are not doing already.

    Regards,

    Vidar

  • Hi Vidar,

    Yes, there is a valid frame before UART_RX_STOPPED event so UART_RX_RDY should be called prior but its not. 

    Yes I have used logic analyzer and can confirm that there is a valid frame after RESUME is called on LTE uart_dev. 

    Also I mentioned earlier: if I dont SUSPEND uart_dev at all, the data frames are received and everything works as expected but when I try to SUSPEND while in PSM and RESUME moments before incoming data the UART_RX_RDY event is not happening.

    For now it seems like uart_rx_disable() and uart_rx_enable() gives good enough results for power consumption (it decreases for about 600uA) comparing to not disabling anything at all. 

    Anyway this question seems to go a bit off rail because basically I wanted to know if PM_DEVICE_ACTION_SUSPEND and PM_DEVICE_ACTION_RESUME should work for asynchronous UART without any additional code? And if yes could you give me a brief example because I can't manage to utilize this functionality since UART_RX_RDY event never fires asfter RESUME even though there are incoming data

  • It should be sufficient to perform the PM_DEVICE_ACTION_RESUME action to re-enable reception, provided the UARTE is given enough time to start up and you provide DMA buffers when requested through the callback.

Reply Children
No Data
Related