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

Weird behavior of UARTE

Hi!
I am currently writing a DMA driver for UARTE which with the goal of being able to handle large data transmissions with little software intervention as well as handling a command based communication interface. Ie, packet sizes are highly unknown.
The chip that I am using is nRF52832.

A few general questions:

  • I assume that RXD.MAXCNT is doubled buffered the same way as RXD.PTR ?
  • Is the ENDRX_STARTRX really needed? My interrupt handler is happily receiving packets without this shortcut set. The only thing that I do is that I add a new buffer when RXSTARTED is generated and parse the previous buffer when ENDRX is generated. To prime the system, I set 2 buffers on the first RXSTARTED event to make sure that double buffering is in use.
  • How accurate is the RXD.AMOUNT value? Assume that the CPU is blocked for a while and both buffers have been used when the handler responds to the ENDRX call. My assumption is that RXD.AMOUNT is going to reflect the number of bytes in the second buffer and the number of bytes in the first buffer is 'lost'?

Here are some more specific questions:

  • What happens if I miss one ENDRX event? Assume that the CPU is heavily loaded and the 2nd ENDRX event is overlapping the first one. Will I still see 2 ENDRX events or is the first one considered lost? Any thoughts on how to handle this? In my code, this would result in the double buffering being lost since the driver got 1 step behind. One potential solution would be to set up PPI to count the ENDRX events to keep track of the number of buffers that have been added vs number of ENDRX events generated from the hardware.
  • How can I flush the buffers and what happens when I do? I have tried to generate a FLUSHRX task periodically, but nothing seem to happen. However, if I trigger a STOPRX task. The currently active buffer is flushed and an ENDRX event is generated. When I tried this, I was assuming that the reception of data would be stopped. However, the UARTE seems to be active and subsequent bytes are being transferred to the next buffer. Any thoughts on why the UARTE is not stopping the reception of data? (The ENDRX_STARTX shortcut is -not- set when I examine the UARTE registers)
  • How do I stop reception of data? Triggering ENDRX is not making a difference and if I stop supplying buffers, data will be overwritten in the last buffer used. Should I set RXD.MAXCNT to 0 to achive this?
  • Is there any way to get an event after some silence in the UART? I was assuming that the RXTO event was for this, but it seems like it is not. I guess I could set up a timer interrupt that I keep advancing every time there is an event from the UARTE and if the timer interrupt expires without any bytes being received, I would issue a STOPRX task to ensre that any bytes received are flushed.

Best regards,

Stefan Burstrom

  • Update: My driver is a derivative of the libuarte driver. Obviously, there were pieces of code that I copied that I did not fully examine. The PPI was used to trigger a new STARTRX from ENDRX. That would explain why the driver keeps going without intervention. This does not change many of the questions though. But stopping the receiver should be straighforward by disabling the RX PPI channel.
    Out of curiosity, why was the ENDRX -> STARTRX shortcut created using PPI and not with the built in UARTE shortcut?

  • Hi,

    I assume that RXD.MAXCNT is doubled buffered the same way as RXD.PTR ?

    Yes, see EasyDMA chapter in UARTE documentation: "The .PTR and .MAXCNT registers are double-buffered"

    Is the ENDRX_STARTRX really needed?

    This depends on how fast you are able to handle the interrupts. Without this, you will not start receiving data in the second buffer until the RXSTART task is triggered in the UARTE IRQ handler. If you have higher priority interrupts (for instance softdevice events) blocking the handling of the UARTE interrupt, you may see data loss.

    My assumption is that RXD.AMOUNT is going to reflect the number of bytes in the second buffer and the number of bytes in the first buffer is 'lost'?

    Yes, the RXD.AMOUNT register is updated on the ENDRX event. However, unless you trigger the STOPRX task, the AMOUNT should match MAXCNT register.

    What happens if I miss one ENDRX event? Assume that the CPU is heavily loaded and the 2nd ENDRX event is overlapping the first one. Will I still see 2 ENDRX events or is the first one considered lost? Any thoughts on how to handle this? In my code, this would result in the double buffering being lost since the driver got 1 step behind. One potential solution would be to set up PPI to count the ENDRX events to keep track of the number of buffers that have been added vs number of ENDRX events generated from the hardware.

     The event register is cleared in the interrupt handler. The register will not be set again if the second event has already been generated. You can read more about events and interrupts in the Peripheral interface chapter in the PS.

    • How can I flush the buffers and what happens when I do? I have tried to generate a FLUSHRX task periodically, but nothing seem to happen. However, if I trigger a STOPRX task. The currently active buffer is flushed and an ENDRX event is generated. When I tried this, I was assuming that the reception of data would be stopped. However, the UARTE seems to be active and subsequent bytes are being transferred to the next buffer. Any thoughts on why the UARTE is not stopping the reception of data? (The ENDRX_STARTX shortcut is -not- set when I examine the UARTE registers)
    • How do I stop reception of data? Triggering ENDRX is not making a difference and if I stop supplying buffers, data will be overwritten in the last buffer used. Should I set RXD.MAXCNT to 0 to achive this?

    These were answered by yourself and caused by ENDRX to STARTRX short. 

    Is there any way to get an event after some silence in the UART? I was assuming that the RXTO event was for this, but it seems like it is not. I guess I could set up a timer interrupt that I keep advancing every time there is an event from the UARTE and if the timer interrupt expires without any bytes being received, I would issue a STOPRX task to ensre that any bytes received are flushed.

     Yes, this would be the preferred approach. Clear the timer whenever the RXDRDY event is generated, and trigger STOPRX when the timer reaches the timeout COMPARE event. The RXTO is only used to indicate that no more data will be received and it is safe to trigger FLUSHRX (as the UARTE peripheral has HW FIFO allowing data to be received for a short period of time after triggering STOPRX task).

    Best regards,
    Jørgen

Related