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

Safe UART line idle detection with DMA

Hi, 

We've circled back to this problem, now that we've increased speed.

We're using UART to communicate between the nRF52832 and an STM32. 

Recently we increased the speed to 1M and to do so, have to switch to DMA transfer. We had made some attempts 2 years ago, but gave up, and reverted to byte-by-byte interrupt based uart after not finding a 100% solution in this thread back then:

https://devzone.nordicsemi.com/f/nordic-q-a/29197/uarte-receive-timeout-rxto

To be able to use DMA, we're padding our (variable length) packets to the size of our DMA Blocks. Most of the time this seems to be working. 

However, when an error occurs, and a single byte is dropped, we start getting into trouble, and without idle line detection, cannot recover.

So we're now adding idle line detection as suggested in the above thread: "A solution is to connect GPIOTE IN event to the UARTE RX pin and reset a timer when there is any activity on the pin. If the timer reaches a certain timeout, you know that there have been no data received for that time and you can flush the DMA buffer."

However, as mentioned in the last comment in the above thread:  "there is a possibility that bytes can be received in the timeout period after triggering STOPRX task". 

We're wondering if there's a way to avoid the timeout of STOPRX.

ie: could we simply call FLUSHRX without calling STOPRX? We don't want to stop reception, we just want DMA give us the (incomplete) data and move onto the next DMA block without ever stopping RX. We can handle the "hole" in our data in the higher levels of our protocol.

Thanks to double-buffering, the RXD.PTR would already be moved, and FLUSHRX would cause EasyDMA to copy all the data, then call ENDRX, which in turn would immediately start STARTRX again, so in effect, never actually stop reception.

Or is there an even better solution? 

Parents
  • Hello,

    it's better not to use STOPRX/FLUSHRX stuff if you need continuous reception. Lost bytes is a lesser evil - sometimes you'll get loss of bitstream synchronization. After some experiments, I came to the most simple and reliable solution for reception: make a double-buffered ring, set ENDRX-STARTRX shortcut  and configure a counter for RXDRDY event to know how many bytes are received at the moment.  An issue with DMA delay can be handled with higher layer, for example, write a zero to memory where last byte of packet is expected, and make sure that your packet ends with non-zero byte.

Reply
  • Hello,

    it's better not to use STOPRX/FLUSHRX stuff if you need continuous reception. Lost bytes is a lesser evil - sometimes you'll get loss of bitstream synchronization. After some experiments, I came to the most simple and reliable solution for reception: make a double-buffered ring, set ENDRX-STARTRX shortcut  and configure a counter for RXDRDY event to know how many bytes are received at the moment.  An issue with DMA delay can be handled with higher layer, for example, write a zero to memory where last byte of packet is expected, and make sure that your packet ends with non-zero byte.

Children
  • Thanks for your answer, but this is not our current issue.

    Our protocol has packet headers, so our higher levels detecting packets are no problem - the problem is that we have variable sized packets, and don't have a continuous data-stream.

    The issue is that sometimes we want to send big amounts of data (255 byte packets, up to 1MB as fast as possible), but usually we're sending very small packets (5-12 bytes) and have to reply to each packet. 

    Lets say we've set DMA to 32 bytes

    When single, small 5 byte packet arrives, we also need to handle that ASAP, and not just after we've received the 8th small packet, and filled up the DMA block, when we receive the ENDRX event.

    So we're looking for a safe method to detect an idle RX line for these small packets which would cause a DMA transfer and and ENDRX event (or similar). But it could also happen, that we get another packet with any amount of delay between the two packets, and we're worried about that second packet. 

    No matter what we would set the idle timeout to, there's a chance we start receiving more data JUST after the idle timeout. 

    Our current solution was to pad our packets with 0's to the exact DMA buffer size, and we thought we'd solved our issue, but then one byte got discarded because of a UART error, and we were left with the same issue, where we received just 31 bytes instead of the expected 32 bytes, and DMA not firing ENDRX until the NEXT packet starts coming in. Of course from then on, this problem continues forever, since 1 byte will always be missing from each of the next packets.

  • I think you should not rely on ENDRX event, use it only for switching buffers. Having a byte counter, you can schedule an interrupt after an expected number of bytes on-the-fly with CC registers, and an issue with lost bytes can be solved with a simple software timer.

Related