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

UARTE dropping received characters @ 115,200

I have written a UARTE driver, to conform to the kind of API we need, for NRF52840.  It is very nearly working except that it drops single received characters and I'm trying to find out why.  In summary I have:

  • four buffers each of length 256 characters,
  • the buffers are arranged as a circular list,
  • the RXSTARTED interrupt re-programmes RXD to point to the next buffer,
  • ENDRX is shorted to STARTRX,
  • the ENDRX interrupt sends a notification to an RTOS task which takes all the data out of the Rx buffers that it can,
  • a free-running timer expires every 130 ms and issues STOPRX to handle cases where incoming data has stopped.

So, if my understanding is correct, receive is continuous and interrupt based through use of RXSTARTED to re-programme RXD and shorting ENDRX to STARTRX.  The RTOS task only has to read stuff and, in any case, if it were too slow for some reason it would be unlikely to cause single characters to drop, more likely whole chunks.

The complete code can be found here, where the initialisation function is at line #338, the interrupt handler at line #176 and the read function at line #652.

Can anyone spot my [deliberate :-)] mistake/misunderstanding?!

FYI, here is an example of the character loss.  The far end sent:

_____0000:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
_____0100:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
_____0200:01234567890123456789012345678901234567890123456789012

I received:

_____0000:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
_____0100:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
_____0200:0123456789012345678901234567890123456789013456789012

------------ THE "2" IS MISSING HERE --------------^

Parents Reply Children
  • I have now read that diagram several times and coded what I believe is correct but it has not helped (actually made things worse) so I would like to check my understanding of the diagram, which I have laid out below.

    Recall that the design is to run a short timer (130 ms) which stops the DMA and flushes things through in order to avoid the situation where there is data lying around in the RX FIFO and/or DMA buffers that has not been forwarded to the application; this needs to work both when the flow of bytes from the far end is constant and when it is intermittent, which I trust the task/event/interrupt system is sufficiently fast to support with a UART running at 115,200; in other words reference lines 23 to 37 below must be executed sufficiently fast to avoid character loss (the far end may not implement flow control). You can also find the full code that is intended to implement my current understanding here.

    QUESTION: is my interpretation of the diagram correct and should it work without character loss at 115,200 in a non-flow-controllable scenario?

    Ref.  Timeline                                    UART RX bytes    DMA destination   DMA bytes
    1:  we set SHORT_ENDRX_STARTRX = true
    2:  we set RXD.PTR = a
    3:  we set RXD.MAXCOUNT = 10
    4:  we trigger TASK_STARTRX
    5:                                                       1
    6:  event EVENT_RXSTARTED                                2                  a             1 
    7:  we set RXD.PTR = b                                   3                  a             2
    8:                                                       4                  a             3
    9:                                                       5                  a             4
    10:                                                      6                  a             5
    11:                                                      7                  a             6
    12:                                                      8                  a             7
    13:                                                      9                  a             8
    14:                                                      10                 a             9
    15:                                                      11                 a             10
    16: event EVENT_ENDRX ('cos DMA hit 10) triggers STARTRX 12                 b             11
    17: event EVENT_RXSTARTED                                13                 b             12 
    18: we set RXD.PTR = c                                   14                 b             13
    19:                                                      15                 b             14
    20: our timer goes off                                   16                 b             15
    21: we set SHORT_ENDRX_STARTRX = false                   17                 b             16
    22: we trigger TASK_STOPRX                               18                 b             17
    23: event EVENT_ENDRX ('cos DMA has stopped)             19
    24:    ...                                               20
    25:    ...                                               21
    26: event EVENT_RXTO
    27: we trigger TASK_FLUSHRX to get bytes 18 to 21                           c             18
    28:                                                                         c             19
    29:                                                                         c             20
    30:                                                                         c             21
    31: event EVENT_ENDRX ('cos DMA has finished flushing)
    32: to continue:
    33:   we set SHORT_ENDRX_STARTRX = true
    34:   we set RXD.PTR = d
    35:   we set RXD.MAXCOUNT = 10
    36:   we trigger TASK_STARTRX
    37:                                                     22
    38: event EVENT_RXSTARTED                               23                 d             22
    39: we set RXD.PTR = e                                  34                 d             23
    etc.
    


  • FYI, I believe I have eliminated the single character loss by adopting a strategy that is half way between the one in my first post and that shown immediately above.  Basically, when my 130 ms timer goes off I do still stop the short and I also wait for the RXTO event but I do not do the flush: I will pick those characters up on the next DMA run in any case so the flush is not necessary.  Instead I just trigger the STARTRX task once more.

    I guess that either the flush process means things take too long and characters end up being dropped or my implementation was at fault.

Related