EmbeddedRelated.com
Forums

can't get uart tx fifo to work

Started by fhriley July 31, 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 this loop to be fast for the first 16 bytes, 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?

I'm using a LPC11C24.

An Engineer's Guide to the LPC2100 Series

THRE is the transmit hold register empty, ( actually in this case it is the
Tx FIFO empty so is mis-named ) so once it has transferred the first byte
the THRE will not be empty but will appear empty as soon as the byte is
transferred to the true THR, this takes a couple of us as it is synchronous
to the Uarts Tx clock, the next byte then has to wait until the THR is empty
before being transferred and emptying the fifo again, so each byte will be
delayed until the previous byte has been transmitted.

For the behaviour you are expecting you would need the flag to be Transmit
FIFO Not Full, but there is not such flag.

Unfortunately this is a problem with 16550 type UARTS, they need to be
driven a character at a time, or from an ISR when the FIFO is empty, then
you can use a counter to limit the Tx to 16 byte bursts.

Generally the 16550 UART architecture is flawed, it was designed many years
ago for a PC to be driven under interrupts, usually when designing embedded
systems I tend to add the additional flags to make polling possible.

Ideally the UART should make the Tx and Rx fifo levels visible, but sadly
NXP did not think to add this capability.

Regards

Phil.

From: l... [mailto:l...] On Behalf Of
fhriley
Sent: 31 July 2011 05:23
To: l...
Subject: [lpc2000] can't get uart tx fifo to work

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 this loop to be
fast for the first 16 bytes, 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?

I'm using a LPC11C24.
On Sun, 31 Jul 2011 04:23:01 -0000, you wrote:

>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 this loop to be fast for the first 16 bytes, 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?
>
>I'm using a LPC11C24.
The documentation is rather unclear on this point - for a long time I was skeptical about whether
the TX fifo actually existed until I realised that the THRE flag is effectively after the FIFO.
When THRE is set, you can then send a fifo-full of data without any further checking.
Actually probably fifo-size+1 as one byte will immediately go from the fifo to the THR

Thanks guys, 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?

--- In l..., "Phil Young" wrote:
>
> THRE is the transmit hold register empty, ( actually in this case it is the
> Tx FIFO empty so is mis-named ) so once it has transferred the first byte
> the THRE will not be empty but will appear empty as soon as the byte is
> transferred to the true THR, this takes a couple of us as it is synchronous
> to the Uarts Tx clock, the next byte then has to wait until the THR is empty
> before being transferred and emptying the fifo again, so each byte will be
> delayed until the previous byte has been transmitted.
>
>
>
> For the behaviour you are expecting you would need the flag to be Transmit
> FIFO Not Full, but there is not such flag.
>
>
>
> Unfortunately this is a problem with 16550 type UARTS, they need to be
> driven a character at a time, or from an ISR when the FIFO is empty, then
> you can use a counter to limit the Tx to 16 byte bursts.
>
>
>
> Generally the 16550 UART architecture is flawed, it was designed many years
> ago for a PC to be driven under interrupts, usually when designing embedded
> systems I tend to add the additional flags to make polling possible.
>
>
>
> Ideally the UART should make the Tx and Rx fifo levels visible, but sadly
> NXP did not think to add this capability.
>
>
>
> Regards
>
>
>
> Phil.
>
>
>
> From: l... [mailto:l...] On Behalf Of
> fhriley
> Sent: 31 July 2011 05:23
> To: l...
> Subject: [lpc2000] can't get uart tx fifo to work
>
>
>
>
>
> 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 this loop to be
> fast for the first 16 bytes, 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?
>
> I'm using a LPC11C24.
>

--- In l..., "fhriley" wrote:
>
> Thanks guys, 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?
>

I don't know anything about the chip you are using - I couldn't find a user manual.

However, for the LPC2148, the User Manual is very specific about the conditions under which a THRE interrupt is withheld.

Richard

That is correct. To start the process you need to "prime" it
first by sending a byte. If in the interrupt you have no more
bytes to send, you ack the interrupt, and will never get another
one until you prime it again. It is a royal pain, and takes some
careful coding to get it to work well.

Mike
> -----Original Message-----
> From: l...
> [mailto:l...]On Behalf
> Of fhriley
> Sent: Sunday, July 31, 2011 10:21 AM
> To: l...
> Subject: [lpc2000] Re: can't get uart tx fifo to work

> 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?
On Sun, 31 Jul 2011 16:20:56 -0000, you wrote:

>Thanks guys, 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?

You can use the VIC SoftInt register to force an interrupt - this can be a useful way to get the tx
process going - just need to clear both the softint and UART int bits on exit from the ISR - no need
to detect which -just clear both.
You aren't kidding. The hardest part for me was understanding how the uart in this chip actually works. I have an implementation now that works great and I think is as efficient as it can be. Thanks much everyone for the help.

--- In l..., "Michael Anton" wrote:
>
> That is correct. To start the process you need to "prime" it
> first by sending a byte. If in the interrupt you have no more
> bytes to send, you ack the interrupt, and will never get another
> one until you prime it again. It is a royal pain, and takes some
> careful coding to get it to work well.
>
> Mike
> > -----Original Message-----
> > From: l...
> > [mailto:l...]On Behalf
> > Of fhriley
> > Sent: Sunday, July 31, 2011 10:21 AM
> > To: l...
> > Subject: [lpc2000] Re: can't get uart tx fifo to work
> >
> >
>
> > 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?
> >
>

I find that an easier solution for me is to run a timer interrupt at just
longer than the time taken to empty the fifo, then I always know that I can
transfer 16 byte into the uart without checking any status flags.

Generally if I have a regular interrupt I chain the uart ISR to this and
adjust the amount I transfer according to the ISR rate, so long as you don't
need flow control this is fine.

Works much better than trying to code for a broken UART architecture,
who-ever architected the 16550 should have been shot!.

Regards

Phil.

From: l... [mailto:l...] On Behalf Of
fhriley
Sent: 01 August 2011 02:00
To: l...
Subject: [lpc2000] Re: can't get uart tx fifo to work

You aren't kidding. The hardest part for me was understanding how the uart
in this chip actually works. I have an implementation now that works great
and I think is as efficient as it can be. Thanks much everyone for the help.

--- In l... , "Michael
Anton" wrote:
>
> That is correct. To start the process you need to "prime" it
> first by sending a byte. If in the interrupt you have no more
> bytes to send, you ack the interrupt, and will never get another
> one until you prime it again. It is a royal pain, and takes some
> careful coding to get it to work well.
>
> Mike
> > -----Original Message-----
> > From: l...
> > [mailto:l... ]On
Behalf
> > Of fhriley
> > Sent: Sunday, July 31, 2011 10:21 AM
> > To: l...
> > Subject: [lpc2000] Re: can't get uart tx fifo to work
> >
> >
>
> > 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?
> >
>
It's the person who wrote the documentation that made it hard for me! Now that I understand how it works and have a good implementation (only 6 lines of code for putting a byte and only 5 lines in the interrupt), I actually find it rather elegant. I can do arbitrary message lengths with hw flow control, and I don't have to interrupt for every byte in the message. Very nice.

--- In l..., "Phil Young" wrote:

> Works much better than trying to code for a broken UART architecture,
> who-ever architected the 16550 should have been shot!.