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

nRF UARTE with EasyDMA unusable for communication between two controllers

Hello,

I am really wondering about the design of the UARTE peripheral. The documentation for the nrf_drv_uart and the nrf_serial library is lacking quite a bit. Most of the documentation is the sourcecode it seems. I need to implement reliable communication between two controllers without the use of FlowControl. So the natural way is to look at EasyDMA. 

Of course, the EasyDMA buffers have to be big enough so that no packets can be dropped while the SoftDevice is active. Let's say, the softdevice interrupts my application for 2ms and my UART is running at 1Mbit. That gives me around 200 bytes I could miss in that time, which means they have to be buffered using EasyDMA. So far so good.

But if I make the EasyDMA receive buffer 256 bytes big, I will not get any interrupts only, when the buffer is full. But maybe the other controller only sends 50 bytes and then has nothing to send for a few seconds? How will I receive the data? If I have to use a timeout, that would be a really crude workaround and means I will have a delay when receiving messages most of the time.

The example of the nrf_serial library example uses a dma buffer of 1 byte, like if it tries to hide something. What's the usecase of having easydma if my buffers are 1 byte big?

Also, does the nrf_serial library use double buffering? It looks like there are parts in the code where uart messages will get lost if the softdevice activates within these lines.

Thanks,

Marius

Parents
  • Do you really need to run at 1 Mbit/s ?

    So the natural way is to look at EasyDMA

    Is it?

    I'd have thought that most of the issues you raise would apply in general to any DMA-based approach?

  • Well, the only thing supported by the nrf is called easyDMA. But without flow control at high speed (no matter if 1 Mbit or a bit lower) I need to use some DMA approach.

  • Sorry, but that's out of question here. I expect the UART hardware to work as advertised. The hardware design is final and I cannot change it. Even when running with 57600 baud, I would still get 12 bytes in 2ms which is too big for the buffer of the UART hardware, so that argument doesn't count here.

  • Hi Marius,

    My recommendation is to use the low level nrfx_uart drivers directly if you want this to work as you want, from the documentation you can find:

    "The receive buffer pointer is double buffered in non-blocking mode. The secondary buffer can be set immediately after starting the transfer and will be filled when the primary buffer is full. The double buffering feature allows receiving data continuously."

    http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.2.0/group__nrfx__uarte.html?cp=4_0_0_6_9_0_31_0_13#ga1e605ee5a6e23572d958b3971a4faaf5 

    So initially make sure to call nrfx_uarte_rx() two times, with two different buffers.

    Then every time you get receive data interrupt, just make sure to call nrfx_uarte_rx() again. You may need to have 3 uart buffers in RAM, one that contain the last received UART data, one that is currently receiving data, and one that is prepared to receive next UART data. Thereby as long as you are able to call nrf_uart_rx() within the time to receive 1 complete uart buffer (e.g. 1024byte UART buffer = 8ms), then you will be fine. Also remember that data is written to RAM continuously as they are received, so you may just also have an app_timer in the background that go through the RAM buffers at given intervals and check for new data without actually waiting for a buffer to fill up.

    So what you want to do is possible, however some of the upper layer UART implementations was made prior to EasyDMA was made, thereby doesn't work quite as one would want.

    The alternative to using the the low lever nrfx_uart drivers is to use the examples\peripheral\experimental_libuarte in your project. This library does pretty much as described above, but also contain a timeout value, so you may handle received UART data that if there is a timeout between UART transmissions.

    Best regards,
    Kenneth

  • Hi, thanks @Kenneth. I couldn't reply to you, don't know why. I think this may help. I am just wondering why the nrf_serial (which was obviously created after easydma existed) would not use it properly. I'll have a look at the experimental lib, but I am still on sdk 14, so I have to see what to do.

    Is there a possibility to get the number of bytes written to the UARTE buffer? It's still weird that I have to use a timer instead of going for a much easier UART interrupt once a byte is received, I wonder why this is not available from the hardware. Would have been nicer to have a serial library off the shelf as it is rather basic functionality.

  • If you wont stop receiver you will not know about number of received bytes :( Hence we have implemented libERTE I've linked an example.

  • Hi I am facing a similar issue perhaps. I am using the nrfx_uarte drivers and would like the NRFX_UARTE_EVT_RX_DONE event handler to handle reception of the data and save that to a buffer (regardless of the size of the incoming data) such that during run time I can manually check what the latest data written was. What would be the way forward please? I read that double buffering is a correct way of continuously receiving data from an RX port however the implementation is not well documented.

Reply
  • Hi I am facing a similar issue perhaps. I am using the nrfx_uarte drivers and would like the NRFX_UARTE_EVT_RX_DONE event handler to handle reception of the data and save that to a buffer (regardless of the size of the incoming data) such that during run time I can manually check what the latest data written was. What would be the way forward please? I read that double buffering is a correct way of continuously receiving data from an RX port however the implementation is not well documented.

Children
No Data
Related