nRF52840 UARTE RX DMA pointer

Hi

Is there a possibility to read out the actual RX pointer of the DMA if the amount of chars is not reached?

Start Stop the RX is not really an option and I have no free Timer for PPI function...

https://devzone.nordicsemi.com/f/nordic-q-a/33813/nrf58232-uarte-rx-easydma-pointer

There should be a possibility to read the actual pointer value.

nrf_uarte_rx_amount_get(ext_uart.p_reg); this is returning 0 even if I received some characters. the return value is 10 if I the UARTE received 10+ chars, this is useless!

nrfx_uarte_rx(&ext_uart, ext_uart_rx_dma_buffer, 10);

Regards, Dominik

Parents
  • Hi,

    Unfortunately, there is no other ways to check the number of received bytes than the two methods suggested in your linked post. The pointer is handled in the HW peripheral, and there is no register to read out the current RAM pointer from the EasyDMA process. The AMOUNT register is not updated until after the receive operation have been stopped/completed.

    If you have a slow UART speed, you may enable interrupt for the RXDRDY event and count the number of bytes in your application, but this may not be reliable.

    Best regards,
    Jørgen

  • Hi

    This makes the DMA function not really usefull with a RX data with different data length. The DMA has exactly this function to store the data, how should I work with the Buffer when I don't know how many char I have in it?

    Anyway, pointing to the "solution" A from the post:

    A) Stop the RX by activating the STOPRX task, wait for the ENDRX event to occur, and read the number of bytes read in the RXD.AMOUNT register. 
        Since the RX pointer is double buffered you can pre-load the next buffer to be used, and use the ENDRX_STARTRX shortcut to start the RX immediately following the ENDRX event. 

    To Stop the RX which function should I use? And am I right that I have to use 2 RX Buffers for the switch between Stop and Start? Can you provide me the stop and restart functions please? This would be really helpfull.

    Thanks

Reply
  • Hi

    This makes the DMA function not really usefull with a RX data with different data length. The DMA has exactly this function to store the data, how should I work with the Buffer when I don't know how many char I have in it?

    Anyway, pointing to the "solution" A from the post:

    A) Stop the RX by activating the STOPRX task, wait for the ENDRX event to occur, and read the number of bytes read in the RXD.AMOUNT register. 
        Since the RX pointer is double buffered you can pre-load the next buffer to be used, and use the ENDRX_STARTRX shortcut to start the RX immediately following the ENDRX event. 

    To Stop the RX which function should I use? And am I right that I have to use 2 RX Buffers for the switch between Stop and Start? Can you provide me the stop and restart functions please? This would be really helpfull.

    Thanks

Children
  • I use this function in the RX IRQ to get the amount of RX DMA chars:

    pos = nrf_uarte_rx_amount_get(ext_uart.p_reg);

    every 10ms I call:

    nrfx_uarte_rx_abort(&ext_uart);

    to trigger the RX IRQ and get the new values. Its working, but on long strings the DMA is losing some chars, what is to improve?

    in the RX IRQ I copy the data to the ringbuffer.

    After processing the data I have to restart the UART DMA with:

    nrfx_uarte_rx(&ext_uart, ext_uart_rx_dma_buffer, RING_BUFFER_SIZE_RX);

    But this is too slow, because the DMA buffer is losing some chars with the nrfx_uarte_rx_abort function

    TX from Terminal:

    Debug Window:

  • Most likely, the driver is not written to handle the double-buffering in this case, and there will be a short period where the RX is not enabled while you copy the data from the buffer. The nrfx_uarte_rx_abort() function will disable the shortcut from ENDRX_STARTRX, as described in the linked post.

    You can try to do it using the HAL functions. Something like this may work, but I have not tested it:

    // Setup primary buffer and start RX
    nrf_uarte_rx_buffer_set(NRF_UARTE0, p_data0, length);
    nrf_uarte_task_trigger(NRF_UARTE0, NRF_UARTE_TASK_STARTRX);
    while(nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_RXSTARTED) == 0);
    nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_RXSTARTED);
    
    // Setup secondary buffer for next transfer and enable shortcut
    nrf_uarte_rx_buffer_set(p_instance->p_reg, p_data1, length);
    nrf_uarte_shorts_disable(NRF_UARTE0, NRF_UARTE_SHORT_ENDRX_STARTRX);
    
    // Delay 10ms
    
    // Stop RX and wait for events before reading out amount
    nrf_uarte_task_trigger(NRF_UARTE0, NRF_UARTE_TASK_STOPRX);
    while(nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX) == 0);
    while(nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_RXTO) == 0);
    nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX);
    nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_RXTO);
    uint32_t amount = nrf_uarte_rx_amount_get(NRF_UARTE0);

    Note that there may still exist issue when the STOPRX task is triggered while a transfer is in progress. In this case, bytes received during RX timeout window may be left in the HW FIFO of the UARTE peripheral, as the FLUSHRX task is not triggered. This may need some testing/verification, to get working properly.

  • Ok, Thank you, I will try it. Do you know if there is an example from Nordic which is focusing this topic? For sure a lot of other people had the same problem with the amount of RX data and the DMA.

    Should it not be enabled?

    nrf_uarte_shorts_disable(NRF_UARTE0, NRF_UARTE_SHORT_ENDRX_STARTRX);
    nrf_uarte_shorts_enable(...)

  • Most customer that have this requirement will use the Libuarte - advanced UARTE driver library, which uses a TIMER in count mode to count the received bytes using PPI and the RXDRDY event. This is the only proven and stable solution we provide for this topic.

    Dominik Eugster said:
    Should it not be enabled?

    Yes, sorry. I forgot to change it. Like I said, the code is not tested, so it there may be other small changes needed.

  • Most customer that have this requirement will use the Libuarte - advanced UARTE driver library, which uses a TIMER in count mode to count the received bytes using PPI and the RXDRDY event. This is the only proven and stable solution we provide for this topic.

    Unfortunately I have no Timer left to count the bytes and don't like to spend one just to count bytes even if I have one, I think this should be implemented in the UART logic from Nordic, I never saw that a Timer is needed to count the received bytes in DMA mode, i.e. STM32 has direct access to the counter on the fly (but also about 20 timers), but maybe there are some good reasons to use the correct logic on the nRF Chips, I will find a workaround. And of course, the focus of the nRF is on BLE which is not included on a STM32 for sure.

    Thanks for your reply, I will try and post the result, because I think a lot of users will have the same topic on UART RX with DMA.

Related