This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

UART receive in background without callback on nRF52 SDK11

Hi, I'm looking for an easy way to use the UART in blocking mode (or something similiar) with a receive buffer that is filled in background:

  • If possible using EasyDMA for better performance and easier software design
  • TX data may either block until all data has been sent or may return immediately and provide an additional function call to check if all data has been sent successfully.
  • RX data shall received in background and stored in a buffer/FIFO. It shall be possible to read data of arbitrary size from the receive buffer without stopping reception.
  • No callbacks or event handlers shall be used (synchroneous control flow in application).

In the past, on the nRF51, we used the app_uart library with FIFO support. Looking at the SDK11 documentation on infocenter.nordicsemi.com, I couldn't find any information about this library (although the directory is still there in the SDK11 archive). Is app_fifo still working on SDK11 on nRF52? Does it take advantage of the EasyDMA feature?

Looking at nrf_drv_uart.h, double buffering is mentioned to provide support for continuous data reception in non-bocking mode. But what does happen if the last received data byte does not fill the buffer to 100%? Will the driver wait for more bytes until the buffer is full, not giving any opportunity to receive data from the partially filled buffer? In other words, is there any possibility to receive "byte streams" of arbitrary length using UART with EasyDMA (something like app_uart with FIFO feature using EasyDMA)?

Parents
  • Based on my discussion with bat13 in the comments, I have been looking into the UARTE documentation in Product Specification v1.0 and came to the following conclusion:

    My current assumption is that it should be possible to prevent data loss if the START_RX task is triggered immediately after the END_RX event (see shortcut in SHORTS register). If the corresponding shortcut is set, START_RX should be triggered by END_RX again, just like when the RX buffer has become full. If you have a look at figure 95, p332, the shortcut has to be reset to really stop reception ("ENDRX_STARTRX = 0") If this bit stays 1, reception should continue.

    I didn't have time yet to check if this feature is already supported by the driver already (when used in EasyDMA mode).

    Race conditions also seem to become important here: A critical situation is when STOP_RX is issued shortly after the current RX buffer becomes full and triggers a END_RX task - END_RX might be triggered twice within a short time, before there was time to update the double buffered pointers... this might lead to corruption of RX data. Is there a good way to prevent this scenario? Maybe the FLUSHRX task can help?

    I'm really curious about is the FLUSHRX task. According to the current Product Specification, it is only used if RX has been stopped. Maybe it can also be used during reception to switch to the next RX buffer? Although that would be pretty much the same as described above with the STOP_RX task and the shortcut. Would be nice to have some more information.

    Update:

    One more question to the Nordic engineers

    From the moment when a full buffer is detected (which initiates a buffer update using the RX.PTR) to the moment when the RX.END interrupt handler is called, is it possible that application code which writes to the RX_STOP task is executed? And how will the STOP_RX task be handled in this case?

    Clean buffer switching might work under the following conditions:

    • Either a buffer full condition immediately interrupts the application control flow and switches to the END_RX interrupt hander, so that calling the STOP_RX task from a lower priority than the interrupt handler is prevented
    • Or a STOP_RX task that is issued from the moment when a full buffer is detected to the moment the interrupt handler is called will be merged with the full buffer STOP_RX event

    To the application engineers: A workaround proposal

    • Create a large RX buffer which cannot become full within a defined time interval, even in a worst case scenario.
    • Within the mentioned time interval, periodically call the STOP_RX task to switch to the next buffer. It might even be possible to use a hardware timer and the PPI to trigger the STOP_RX task.
    • In the END_RX event handler, configure the next buffer (double buffering) and handle the bytes received (if any).
    • In your timing calculations, take the timing requirements from the SoftDevice into account (it might be busy for quite some time and delay the END_RX handler, so that more data might arrive in the buffer than originally calculated).

    This way, using the EasyDMA feature, it should be possible to implement robust UART reception that doesn't lose data when the SoftDevice is active (e.g. during a radio event). The old UART device only had a short FIFO buffer that would overflow on long SoftDevice activities.

    The major drawback of this implementation is that it will cause periodic interrupts, even if no data has been received.

    Maybe the sample posted by Hung Bui (have a look at his post) shows something similiar to this workaround. I didnt have time to try it out yet. My extra suggestion to his implementation would be to use a large RX buffer that cannot be filled within the configured time interval (+ some extra time for the SoftDevice).

  • if the ENDRX-STARTRX shortcut is not set, there will be no "next buffer". And if the shortcut is set, receiving will be restarted and no RXTO will be issued. A new buffer is only used at the moment the STARTRX task is triggered. But like I saif, RXTO only seems to make sense when using flow control. Without flow control, it may be used, but doesn't help very much.

Reply
  • if the ENDRX-STARTRX shortcut is not set, there will be no "next buffer". And if the shortcut is set, receiving will be restarted and no RXTO will be issued. A new buffer is only used at the moment the STARTRX task is triggered. But like I saif, RXTO only seems to make sense when using flow control. Without flow control, it may be used, but doesn't help very much.

Children
No Data
Related