What should I do after UART FIFO overruned?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

What should I do after UART FIFO overruned?

Jump to solution
6,095 Views
makotokatsukura
Contributor II

Dear Forum members,

I am using UART0 with receive FIFO(16 data words) function is enabled.

It works fine normally, but once it overflowed it works weirdly.

For example,  I sent strings "ABCDEFGHIJKLMLOPQRSTUVWXYZ" repeatedly to Vybrid from my PC.

After UART0 receive FIFO was overflowed, my program read D register until RXEMPT bit becomes 1.

Also my program checked RCFIFO register for debug.

Followings are register reading log.

( Left side of "="  shows register name or flag name, right side of "=" shows read value. )

( Top is oldest, bottom is newest.)

  1. RXOF=1
  2. RCFIFO=15
  3. D='H'
  4. RCFIFO=14
  5. D='I'
  6. RCFIFO=13
  7. D='J'
  8. RCFIFO=13
  9. D='K'
  10. RCFIFO=12
  11. D='L'
  12. RCFIFO=11
  13. D='M'
  14. RCFIFO=10
  15. D='N'
  16. RCFIFO=9
  17. D='O'
  18. RCFIFO=8
  19. D='P'
  20. RCFIFO=7
  21. D='Q'
  22. RCFIFO=7
  23. D='R'
  24. RCFIFO=6
  25. D='S'
  26. RCFIFO=5
  27. D='T'
  28. RCFIFO=4
  29. D='U'
  30. RCFIFO=3
  31. D='V'
  32. RCFIFO=2
  33. D='G'
  34. RCFIFO=2
  35. D='O'
  36. RCFIFO=1
  37. D='P'
  38. RCFIFO=0

(In this case, no error was happened except fifo overrun error.)

Then Line 33, 35, 37 is weird.

I think those should be 'W', 'X', 'Y'  but  they are 'G', 'O', 'P'.

it seems the data in the receive FIFO was corrupted.

Are there any special rules to read from D register after FIFO was overruned?

Please help us.

Regards,

Makoto Katsukura

Labels (2)
Tags (4)
0 Kudos
1 Solution
3,459 Views
jiri-b36968
NXP Employee
NXP Employee

Hi Makoto,

sorry for delay. Code sent by FAE was little bit complicated for tests. Simple test code showed that there is an issue in cleaning OR flag when FIFO is enabled. The sequence in RM does not for me either.

When OR is cleaned then you have to read the flag and then read Data register. In my test code it "moved pointer" in FIFO. That was probably causing described behavior.

After correct initiation and changing sequence both ways from following code works for me fine:

  • Read overloaded buffer - when longer sequence was sent, then only first part of the sequence, which fits into Rx buffer remains. Later data are ignored - no overwriting of previous data. The code prints Rx FIFO back to TX channel.(#if 1)
  • Flush overloaded buffer - previous data are lost (#if 0)

RM also recommends to disable RE when flushing FIFO - it work for me with of without. Disable RE cleans OR flag immediately

Initialization

//disable transmitter and receiver during the change

  UART_PORT->C2 &= ~UART_C2_RE_MASK;

  UART_PORT->C2 &= ~UART_C2_TE_MASK;

  //UART_PORT-> PFIFO = UART_PFIFO_RXFE_MASK | UART_PFIFO_RXFIFOSIZE(3);    //enable Rx FIFO 16 bytes

  UART_PORT-> PFIFO = UART_PFIFO_RXFE_MASK | UART_PFIFO_RXFIFOSIZE(2);    //enable Rx FIFO 8 bytes

  status = (UART_PORT-> S1) | UART_S1_OR_MASK; // clear OR

  get = UART_PORT->D;    //clear OR

  UART_PORT-> CFIFO |= UART_CFIFO_RXFLUSH_MASK;    //flush RX buffer

  UART_PORT-> SFIFO |= UART_SFIFO_RXOF_MASK;    //clear RXOF

  // Enable receiver and transmitter

  UART_PORT->C2 |= UART_C2_RE_MASK;

  UART_PORT->C2 |= UART_C2_TE_MASK;

...

...

...

Overflow handling

        //overflow

      if ( (UART_PORT-> SFIFO) & UART_SFIFO_RXOF_MASK)

      {

          //UART_PORT->C2 &= ~UART_C2_RE_MASK; // recommended to disable RE

#if 1

          //read the overflowed data

          while (uart_getchar_present())

          {

              get=uart_getchar();    // will also clear the OR flag

              uart_putchar(get);

              time_delay_ms(2);

          }

          UART_PORT-> CFIFO |= UART_CFIFO_RXFLUSH_MASK;    //flush RX buffer

          UART_PORT-> SFIFO |= UART_SFIFO_RXOF_MASK;    //clear RXOF

#else

          //flush read FIFO buffer

          status = (UART_PORT-> S1) & UART_S1_OR_MASK; // clear OR - read OR and read Data (disable RE clears OR also)

          get = UART_PORT->D;

          UART_PORT-> CFIFO |= UART_CFIFO_RXFLUSH_MASK;    //flush RX buffer

          UART_PORT-> SFIFO |= UART_SFIFO_RXOF_MASK;    //clear RXOF

#endif

          //UART_PORT->C2 |= UART_C2_RE_MASK;

      }

/Jiri

View solution in original post

0 Kudos
12 Replies
3,459 Views
jiri-b36968
NXP Employee
NXP Employee

Hi Makoto,

In this case I would need try to replicate it.

Please attach your code (simplified)

/Jiri

0 Kudos
3,459 Views
makotokatsukura
Contributor II

Dear Jiri,

Thank you for your reply and I'm really sorry for my late reply.

May I attach the sample code of Linux driver?

If I need to write a code without Linux, please give me a time.

Thank you,

Makoto Katsukura

0 Kudos
3,459 Views
jiri-b36968
NXP Employee
NXP Employee

Hi Makoto,

send me the code where you see the issue. I need to replicate it here to check if it is SW issue or HW/silicon issue.

/Jiri

0 Kudos
3,460 Views
jiri-b36968
NXP Employee
NXP Employee

Hi Makoto,

sorry for delay. Code sent by FAE was little bit complicated for tests. Simple test code showed that there is an issue in cleaning OR flag when FIFO is enabled. The sequence in RM does not for me either.

When OR is cleaned then you have to read the flag and then read Data register. In my test code it "moved pointer" in FIFO. That was probably causing described behavior.

After correct initiation and changing sequence both ways from following code works for me fine:

  • Read overloaded buffer - when longer sequence was sent, then only first part of the sequence, which fits into Rx buffer remains. Later data are ignored - no overwriting of previous data. The code prints Rx FIFO back to TX channel.(#if 1)
  • Flush overloaded buffer - previous data are lost (#if 0)

RM also recommends to disable RE when flushing FIFO - it work for me with of without. Disable RE cleans OR flag immediately

Initialization

//disable transmitter and receiver during the change

  UART_PORT->C2 &= ~UART_C2_RE_MASK;

  UART_PORT->C2 &= ~UART_C2_TE_MASK;

  //UART_PORT-> PFIFO = UART_PFIFO_RXFE_MASK | UART_PFIFO_RXFIFOSIZE(3);    //enable Rx FIFO 16 bytes

  UART_PORT-> PFIFO = UART_PFIFO_RXFE_MASK | UART_PFIFO_RXFIFOSIZE(2);    //enable Rx FIFO 8 bytes

  status = (UART_PORT-> S1) | UART_S1_OR_MASK; // clear OR

  get = UART_PORT->D;    //clear OR

  UART_PORT-> CFIFO |= UART_CFIFO_RXFLUSH_MASK;    //flush RX buffer

  UART_PORT-> SFIFO |= UART_SFIFO_RXOF_MASK;    //clear RXOF

  // Enable receiver and transmitter

  UART_PORT->C2 |= UART_C2_RE_MASK;

  UART_PORT->C2 |= UART_C2_TE_MASK;

...

...

...

Overflow handling

        //overflow

      if ( (UART_PORT-> SFIFO) & UART_SFIFO_RXOF_MASK)

      {

          //UART_PORT->C2 &= ~UART_C2_RE_MASK; // recommended to disable RE

#if 1

          //read the overflowed data

          while (uart_getchar_present())

          {

              get=uart_getchar();    // will also clear the OR flag

              uart_putchar(get);

              time_delay_ms(2);

          }

          UART_PORT-> CFIFO |= UART_CFIFO_RXFLUSH_MASK;    //flush RX buffer

          UART_PORT-> SFIFO |= UART_SFIFO_RXOF_MASK;    //clear RXOF

#else

          //flush read FIFO buffer

          status = (UART_PORT-> S1) & UART_S1_OR_MASK; // clear OR - read OR and read Data (disable RE clears OR also)

          get = UART_PORT->D;

          UART_PORT-> CFIFO |= UART_CFIFO_RXFLUSH_MASK;    //flush RX buffer

          UART_PORT-> SFIFO |= UART_SFIFO_RXOF_MASK;    //clear RXOF

#endif

          //UART_PORT->C2 |= UART_C2_RE_MASK;

      }

/Jiri

0 Kudos
3,459 Views
makotokatsukura
Contributor II

Dear Jiri,

Thank you for your reply.

As you have recommended, we've changed our code to disable RE when flushing FIFO.

It works fine.

Thank you,

Makoto Katsukura

0 Kudos
3,459 Views
falstaff
Senior Contributor I

Hi,

I've seen the same issue on Linux as well, but not in normal conditions. While debugging, I printed lots of characters in the receive path of UART to the TTY (running on a different UART). This lead to overrun conditions. I think the FIFO is then somehow misaligned. However, I never had that behavior in normal condition, I think, on Linux, this is not a real world case.

Stefan

0 Kudos
3,459 Views
makotokatsukura
Contributor II

Dear Stefan and forum members,

Thank you for your reply.

I've removed debug prints from my test codes, but FIFO misalignment is still happening.

So we've gave up to take the data from FIFO buffer after overrun error occurred :smileycry:

Then we are focusing on buffer clear operation after overrun error.

As I mentioned at previous post, the operation written at Vybrid Reference Manual, chapter  "49.8.4.1 Overrun operation" is not work properly in my condition.


Buffer clear operation defined at Vybrid Reference Manual

    1. using CFIFO[RXFLUSH] to clear the buffer

    2. Clear S1[OR]

    3. Clear SFIFO [RXUF]

I've made some test programs and I've found that following operation works fine.

   1. Clear S1[OR]

    2. Clear SFIFO [RXUF]

    3. using CFIFO[RXFLUSH] to clear the buffer

The difference is the order of S1[OR] clearing and CFIFO flushing.

The reference manual says, we have to flush the FIFO first, then clear overrun error bit (S1[OR]).

But our test result implies that clearing overrun bit first is seems to be properly.:smileyconfused:

Which is the correct order?

We want to know proper operation.

Thank you,

Makoto Katsukura

0 Kudos
3,459 Views
jiri-b36968
NXP Employee
NXP Employee

Dear Makoto Katsukura,

As I read chapter 49.8.4.1 Overrun operation.

When overrun occur you should:

- remove data from buffer (reading data) or CFIFO[RXFLUSH] to clear buffer

- clear S1[OR]

- if clear was done by CFIFO[RXFLUSH] than SFIFO[RXUF] have to be cleared before S1[OR]

So sequence from RM:

clear CFIFO[RXFLUSH]

disable SFIFO[RXUF] interrupt - which is CFIFO[RXUFE]

clear S1[OR]

clear SFIFO[RXUF]

/Jiri

0 Kudos
3,459 Views
makotokatsukura
Contributor II

Dear Jiri,

Thank you for your advise.

We've tried following sequence which you've mentioned.

  1. clear CFIFO[RXFLUSH]
  2. disable SFIFO[RXUF] interrupt - which is CFIFO[RXUFE]
  3. clear S1[OR]
  4. clear SFIFO[RXUF]

Unfortunately, it doesn't work.

After S1[OR] clearing, the data read from D register becomes incorrect.

Regards,

Makoto Katsukura



0 Kudos
3,459 Views
makotokatsukura
Contributor II

Additional information.

In Vybrid Reference Manual, Rev. 5,  there is a chapter  "49.8.4.1 Overrun operation".

It says following instructions:

1. using CFIFO[RXFLUSH] to clear the buffer

2. Clear S1[OR]

3. Clear SFIFO [RXUF]

I tried above instruction too, but after that, read data from D register became corrupted.

For example, I send "ABC" to Vybrid from PC, but Vybrid only receive "AB" only.

After that, I send "D" to Vybrid, then Vybrid receive "C". It's weird.

It only happens after overrun occurred, so I don't think it is a H/W trouble.

Our Vybrid's UART works really fine in normal situation.

Regards,

Makoto Katsukura

0 Kudos
3,459 Views
jiri-b36968
NXP Employee
NXP Employee

Dear Katsukura,

when overflow occur than it is too late to get right data. Honestly it is not important, what is in the buffer - something has been lost already.

To ensure right work of your UART communication and prevent overflow situation you can use Watermark feature. For example for UART receive it is RXWATER register.

When the number of datawords in the receive FIFO/buffer is equal to or greater than the value in this register field, an interrupt or a DMA request is generated.

/Jiri

3,459 Views
makotokatsukura
Contributor II

Dear Jiri,

Thank your for your advice.

We set RXWATER to 1, lowest value, but we could not avoid overrun.

The cause of overrun was interrupt disable from SD card driver (mmc driver).

It disabled the interrupt longer than 800[us].

So finally, we redesigned our communication speed down to 38400 bps ( originally 115200 bps).

After that, we can avoid uart overrun.

Thank you,

Makoto Katsukura

0 Kudos