how to prevent sleep mode in ZEPHYR while UARTE DMA transaction is not completed

Our project is built wit NRF Connect SDK 2.9.0. For the UART we use nrfx_uarte library directly.

RX works perfectly, but TX is working only in blocking mode. If I call `nrfx_uarte_tx()` with flags=0, which assumes that the entire buffer will be sent over DMA in one go, the packet gets corrupted. I think this is because zephyr is not aware that the sleep should not be that deep.

To circumvent  entering the sleep mode I place a loop after the nrfx_uarte_tx() which runs until the ISR resets a flag indicating the TX completion

static void uart0_handler(nrfx_uarte_event_t const * p_event, void * p_context)
{
    nrfx_uarte_t * p_inst = p_context;
    static k_timeout_t idle_period = K_MSEC(IDLE_PERIOD);

    switch (p_event->type)
    {
        case NRFX_UARTE_EVT_TX_DONE:
            LOG_INF("TX0 done");
            txRunning = false; // this is the flag indicating the completion
            break;
            
        // other event types
        ...
    }
}

bool uart0_tx_blocking(uint8_t *data, uint16_t size, uart0_tx_done_cb cb)
{
    nrfx_err_t err;
    err = nrfx_uarte_tx(&uart0_inst, data, size, 0);
    if (err == NRFX_SUCCESS) {
        // prevent sleep while DMA transfer is running
        txRunning = true;
        while (txRunning) {}
        return true;
    }
    
    return false;
}

So far it works like this, but as you can see it is blocking now. I can of course call it in a separate thread, but it's not nice to create a thread just for that.

Cleaner solution would be to somehow tell the Zephyr, that it should not sleep, it should use less restrictive power mode, so that DMA could finish the transaction.

I tried different pm_* functions, but without success. Obviously I'm missing something.

So the question is how to force a power mode that will allow DMA to finish?

  • Hello,

    What NCS version are you using? Is it possible to upload an application showing the behavior that you are seeing? 

    It is not clear to me what happens when you return from the uart0_tx_blocking() function. 

    While it is possible to only show where you call it from, it is a lot easier for me to have access to an entire application that can reproduce the application that you are seeing, and poke around in it, so if possible, just zip the entire application folder, specify what NCS version, and I can give it a shot.

    Another option, although it is not using the nrfx driver directly, is to have a look at the ncs\nrf\samples\bluetooth\peripheral_uart, and it's uart implementation. I believe this will work for your use case.

    Best regards,

    Edvin

Related