can't get uart tx fifo to work

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

can't get uart tx fifo to work

3,075 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ToBeFrank on Sat Jul 30 20:44:25 MST 2011
Hello,

I've got my uart code working fine, however, when measuring it with a scope, it appears the TX fifo is not working. I send a byte with the following code:

while ((LPC_UART->LSR & LSR_THRE) == 0);
LPC_UART->THR = ch;


I call this in a loop to send the message. I would expect the first 16 bytes to go fast, however I see the first byte take 830ns, the second 2.2us, and the remaining bytes take 84us each. I'm running at 115200 baud so the 84us is consistent with that, but I don't understand why I don't see the first 16 bytes going quick. What am I doing wrong?

Forgot to mention I'm using a LPC11C24.
0 Kudos
13 Replies

2,027 Views
tobiasfrauenrat
Contributor I

This is my implementation:

/* Transmit a byte array through the UART peripheral (non-blocking) */
int Chip_UART_Send(LPC_USART_T *pUART, const void *data, int numBytes)
{
int sent = 0;
uint8_t *p8 = (uint8_t *) data;


/* beforehand, wait till the buffer is empty*/
while ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) == 0)
;

/*send 16 bytes to bufferred Tx*/
while (sent < numBytes) {
Chip_UART_SendByte(pUART, *p8);
p8++;
sent++;


/*Wait till buffer is empty every 16 Bytes*/
if(!(sent % 16))
{
while ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) == 0)
;
}


}
return sent;
}

0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gbiagioni on Wed Mar 16 09:10:33 MST 2016
I know this is an old thread but five years later I find that every example from NXP is still incorrect. I have spent a lot of wasted time on this issue and hope the following code from my interrupt handler can save some others the same plight. An interrupt handler based on this strategy will correctly flow data out of the UART 16 bytes per interrupt:


    if (uartReg.LSR & UART_LSR_THRE)
    { // the THR FIFO is empty, so send up to 16 bytes to UART from Tx buffer

        amt = amt>16 ? 16 : amt;     // FIFO limit is 16

        while  (amt>0)
        { // put a byte into Tx FIFO

            uartReg.THR = *buf++;
            amt--;
        }
    }

The FIFO will not overflow because a zero UART_LSR_THRE bit means the FIFO is empty.

The problem here is the examples provided by NXP, not the design of the UART nor the documentation (which correctly defines UART_LSR_THRE behaviour). Once understood, the design is actually rather nice for an interrupt driven scenario. Maybe not so nice in a polled environment.
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ant_ on Wed Dec 03 10:17:03 MST 2014
Someone might find this idea of use. It's no help for heavy traffic but if you have less than a fifo size of data to send and it's normally sent before the next burst, it works.
static char FifoContains = 0;
void Uart0WriteByte(const char ch)
{
    if (FifoContains < 16)
    {
        LPC_UART0->THR = ch;
        FifoContains++;
    }
    else
    {
        while ((LPC_UART0->LSR & LSR_THRE) == 0);
        LPC_UART0->THR = ch;
        FifoContains   = 1;
    }
}
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by AchimKraus on Wed Apr 23 08:42:06 MST 2014
Very good thread!

I was already starting to get crazy about the tx fifo und the THRE flag ('550 compatible, sure?)

Very bad, that the bug didn't make it to the erratas ... or did I miss it?
And the workaround is still missing in openLPC.
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Mon May 20 07:44:31 MST 2013
Ok thanks for that snippet, that's what you do on AVRs but I didn't realise the ARM had an equivalent register.
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ToBeFrank on Mon May 20 07:15:50 MST 2013

Quote: graynomad
I managed to get a fully working FIFO transmission routine running on the 1227 using my own counter.

I keep a software FIFO than feeds the hardware FIFO, the serial write func puts the byte into either the HW or SW FIFO depending on what is already in the HW FIFO. If there are no bytes in either it writes directly into THR



That's exactly how my implementation works.


Quote:
http://ardweenet.blogspot.com.au/2012/12/nasty-nasty-atomic.html

I left a comment for you on this one. :)
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Mon May 20 06:37:39 MST 2013
I managed to get a fully working FIFO transmission routine running on the 1227 using my own counter.

I keep a software FIFO than feeds the hardware FIFO, the serial write func puts the byte into either the HW or SW FIFO depending on what is already in the HW FIFO. If there are no bytes in either it writes directly into THR.

It tested well for all speeds up to about 500kbps at which time there is hardly any time between interrupts.

I can post the code but it has a lot of dependences on various library routines and structures I have.

Some details here

http://ardweenet.blogspot.com.au/2012/12/nxp-wtf.html

and here

http://ardweenet.blogspot.com.au/2012/12/nasty-nasty-atomic.html
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by FBUTTY on Sat May 05 05:20:42 MST 2012
I totally agree.

The manual reads as if bit 5 in LSR is set when the THRE is empty, and THRE is the input into the FIFO, so one would assume that when THRE is empty there could still be data in the FIFO, allowing it to be drip fed. Having status bits for both THRE empty and TSR empty (bit 6) in [B]the current implementation makes the FIFO practically useless, [/B]in my opinion.

Bit 5 should have been implemented to signal when the FIFO is not full, not when the entire FIFO is empty ... when it's too late to do anything about it.

Frank
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Sun Jul 31 14:26:11 MST 2011
Wow,

This is a major flaw in the FIFO implementation.
My software can only determine how many bytes it can write when the fifo is empty (THRE) and the Tx interrupt is only fired when the fifo is empty (possibly resulting in a period of silence on the data line ...).


Quote:
Unfortunately reading FIFO status via FIFOLVL doesn't work.



So this is missing from the Errata sheets ...
I was still using the old user manual and NXP should have written this flaw down in the errata sheet of the respective chips. Or do they expect me to download and compare new versions of the user manuals each time a new one comes out :confused:


Quote:

Another question... it appears the THRE interrupt will never fire until  you've written a byte into THR. Is this true or is there a way to have  it fire without having to write a byte first?



Yes, this is true.
When you use an interrupt based uart, the first byte (or serie of bytes) is written from the non-interrupt routine and you set up the driver such that the rest of the data is sent using the interrupt routine.

Rob
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ToBeFrank on Sun Jul 31 09:17:14 MST 2011

Quote: Rob65
As expected ...

LSR_THRE gives you the information that the Transmit Holding Register is [B]empty[/B].
I.e: the FIFO is empty ...
So you are writing one byte to the FIFO, waiting for the fifo to be empty and only then write the next byte.



Thank you, this makes sense. My confusion comes from the user manual. It states the THR register is for the top byte in the fifo, and that byte will get sent when it makes it to the bottom of the fifo. If that's the case, then THRE should get set when a new space in the fifo has become available. But obviously that's not how it works.

Another question... it appears the THRE interrupt will never fire until you've written a byte into THR. Is this true or is there a way to have it fire without having to write a byte first?
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sun Jul 31 06:27:16 MST 2011

Quote:

...it appears the TX fifo is not working...

FIFO should work if you enable it: LPC_UART->FCR = 0x07; //Enable and reset TX and RX FIFO

Unfortunately reading FIFO status via FIFOLVL doesn't work.

A simple workaround is to write 16 bytes to FIFO and then read THRE again.

 void UART_Tx(char *BufferPtr, int Length)
 {
  unsigned char tx_data = 0;
   while ( Length != 0 )
   {
      if(!(tx_data % 16))
      {
        while ( !(LPC_UART->LSR & LSR_THRE) );
      }
       LPC_UART->THR = *BufferPtr;
      BufferPtr++;
      tx_data ++;
      Length--;
   }
   return;
 }
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Sat Jul 30 23:45:50 MST 2011
Aahhrrgg...

the same is true for the lpc13xx and lpc17xx series.

The FIFOLVL register is still in CMSIS but not in the new manuals.
Dear NXP, please explain what is going on, I did not read anything about a new uart implementation that voids the use of the TX FIFO ...

Rob
0 Kudos

2,027 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Sat Jul 30 23:34:59 MST 2011
As expected ...

LSR_THRE gives you the information that the Transmit Holding Register is [B]empty[/B].
I.e: the FIFO is empty ...
So you are writing one byte to the FIFO, waiting for the fifo to be empty and only then write the next byte.

I would have expected something like an LSR_THRF (Transmit Holding Register Full) but I could not find that one.
One way to solve this (I don't think this is a nice way to do it but apparantly this is the only way) is to check the LPC_UART->FIFOLVL register.
Somehow this register did not pop up in the bookmarks of the PDF file :confused: but it is in chapter 9 ssection 5.21 of the old version of the UM (Rev 00.10 - 11 january 2010) but it got removed from the latest version of the UM ... :eek::(:confused:

[COLOR=Red][B]This is something for NXP to explain.
The FIFOLVL register is still available in CMSIS version 2[/B][/COLOR]

According to the old manual bits 11-8 specify the fill level of the TX FIFO (0x0 - empty, 0xF - full). Bits 3-0 do the same for the RX FIFO.

Rob
0 Kudos