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?

Parents
  • 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

Reply
  • 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

Children
  • Hello Edvin, thank you for the answer.

    We use NCS 2.9.0

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

    we are on the early stage, currently it is inside a loop waiting for a message from a button press, but later there will be more complicated scenario.

    void thread1(void)
    {
    	uint8_t msg;
    	while(1) {
    		// For some reason hid_keyboard and uart tx do not work in the main thread together.
    		// MCU hangs.
    		// we have to send uart in a separate thread.
    		k_msgq_get(&uart_test_msgq, &msg, K_FOREVER);
    		LOG_INF("TX test");
    		uart0_tx_blocking("1234567890123456789012345678901\n", 32, txdone_cb);
    	}
    }

    That comment about hid_keyboard is a separate issue Slight smile

    > 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.

    This was our first attempt. Unfortunately it did not work. We need to disable and enable uart in runtime and change the baud rate. For some reason the uart driver returned an error on reenabling. I have researched a bit and found that some internal variable in uart_nrfx_uarte.c  was not correctly reset after disabling and this caused an error on enabling. So I decided to go with nrfx_uarte. To be honest, juggling KConfig settings and discovering features in the device tree is a very time consuming pleasure.

    > so if possible, just zip the entire application folder, specify what NCS version, and I can give it a shot.

    is it possible to send the zip file to you directly? I'd like to avoid sharing it in the ticket.

Related