EmbeddedRelated.com
Forums

LPC2138 UART bug or docs problem?

Started by Stephen Pelc July 10, 2006
Quoting brendanmurphy37 :
>> >was going by what the Philips documentation says, which fairly
>> >unambiguously says the bit is set when the THR (which it defines to be
>> >the top of the FIFO) is empty.
>>
>> Ahh, I think I see where the problem has arisen. I do believe it's a
>> recent documentation bug. The interrupt and status definitions refer to
>> the 'actual' THR, the one that holds a single character for transmission
>> just before the shift register. The FIFO documentation refers to the 'user
>> visible' THR that a program can write to. I think they used one term when
>> they should have used two.
>>
>> We had a discussion about this some time back. The user manual at that
>> time didn't appear to have the statement you refer to, indeed as I remember
>> it more or less punted to existing 16550 documentation. At that time
>> someone(s) wanted to know how tell if the FIFO is full. Answer: you count
>> the number of characters you put in.
>
> That makes a lot of sense. Regardless of how it's defined though, I
> can't imagine this to be the root cause of the original problem
> described. To my mind, it should be safe to poll THRE to see if it's
> OK to write a character, and to assume it is set at the correct
> point (i.e. with no delays), otherwise there would be little point
> in having it.

Agreed, although since it bypasses the FIFO I can't think of many cases where
you should be polling immediately after writing.

Robert

An Engineer's Guide to the LPC2100 Series

Quoting Robert Adsett :

> Quoting brendanmurphy37 :
>> That makes a lot of sense. Regardless of how it's defined though, I
>> can't imagine this to be the root cause of the original problem
>> described. To my mind, it should be safe to poll THRE to see if it's
>> OK to write a character, and to assume it is set at the correct
>> point (i.e. with no delays), otherwise there would be little point
>> in having it.
>
> Agreed, although since it bypasses the FIFO I can't think of many cases where
> you should be polling immediately after writing.

Did a little more searching

From ST/Exar ST16C550

This bit is the Transmit Holding Register Empty indicator.
This bit indicates that the UART is ready to
accept a new character for transmission. In addition,this bit causes
the UART to
issue an interrupt to CPU
when the THR interrupt enable is set. The THR bit is set
to a logic 1 when a character is transferred from the
transmit holding register into the transmitter shift register.
The bit is reset to logic 0 concurrently with the
loading of the transmitter holding register by the CPU.
In the FIFO mode this bit is set when the transmit FIFO
is empty; it is cleared when at least 1 byte is written to
the transmit FIFO.
From Philips SC16550B

The THR empty flag in the LSR register will
be set to a logic 1 when the transmitter is empty or when data is
transferred to
the TSR.
Note that a write operation can be performed when the THR empty flag is set
(logic 0 = FIFO full; logic 1 = at least one FIFO location available).

Two notes on that, First it contradicts Exar's documentation, second it can be
read as contradicting itself!

From the same Philips data sheet

When FCR[0] = logic 1, resetting IER[0:3] enables the SC16C550B in the FIFO
polled
mode of operation. Since the receiver and transmitter have separate
bits in the
LSR,
either or both can be used in the polled mode by selecting respective transmit
or receive
control bit(s).
LSR[0] will be a logic 1 as long as there is one byte in the receive FIFO.
LSR[1:4] will provide the type of errors encountered, if any.
LSR[5] will indicate when the transmit FIFO is empty.

This time it definitly agrees with the ST/Exar Data sheet

And again from Philips

THR empty. This bit is the Transmit Holding Register Empty indicator. This bit
indicates that the UART is ready to accept a new character for
transmission. In
addition, this bit causes the UART to issue an interrupt to CPU when the THR
interrupt enable is set. The THR bit is set to a logic 1 when a character is
transferred from the transmit holding register into the transmitter shift
register.
The bit is reset to a logic 0 concurrently with the loading of the transmitter
holding register by the CPU. In the FIFO mode, this bit is set when the
transmit
FIFO is empty; it is cleared when at least 1 byte is written to the transmit
FIFO.

Clearly this documentation issue has been with Philips for a while.

I didn't see any indication of time delays from write to THRE clear but it's
possible I overlooked something in one of the data sheets.

As I recall the OP was checking for THRE before each character write. In that
case I would expect
- THRE to clear on any character being written.
- THRE will set when last character is moved to the transmit shift register
- Thus a tight loop on THRE will bypass the FIFO
- If there is a delay in clearing THRE I would expect that to just result in
an extra character or two in the FIFO

Something's odd.

Robert





--- In l..., Robert Adsett
wrote:
> Clearly this documentation issue has been with Philips for a while.
>
> I didn't see any indication of time delays from write to THRE clear
but it's
> possible I overlooked something in one of the data sheets.
>
> As I recall the OP was checking for THRE before each character
write. In that
> case I would expect
> - THRE to clear on any character being written.
> - THRE will set when last character is moved to the transmit
shift register
> - Thus a tight loop on THRE will bypass the FIFO
> - If there is a delay in clearing THRE I would expect that to
just result in
> an extra character or two in the FIFO
>
> Something's odd.

I'd agree with this last statement OK!

I was going by the "LPC213x User Manual" description, since that's
the part we use. It doesn't mention anything specific about FIFOs
when describing the THRE (which is what lead me to assume incorrectly
that the bit set meant "there's some space in the FIFO" rather than
the correct "the FIFO is empty").

The NS16550 data sheet (original of the species) mentions the FIFO in
the description of the THRE bit.

By the way, can you explain your statement that a "tight loop on THRE
will bypass the FIFO"? Do you mean that the following can fail:

Line 1: LOOP:
Line 2: THRE bit set?
Line 3: IF NOT SET GOTO LOOP
Line 4: OK to write THR here! (up to 16-bytes if FIFO enabled)

I'd assume that this would always work OK.

Please excuse my newly developed pseudo-language: I'm sure it gets
the point across...

Brendan.

>
> Agreed, although since it bypasses the FIFO I can't think of many
cases where
> you should be polling immediately after writing.
>
> Robert
>

I sure don't read the docs that way. The FIFO must be enabled to use
the UART. The THR is defined to be the top of the FIFO. The issue is
how does THRE work.

On page 90 of the 24 June 2005 edition of UM10120 (LPC2138 User
Manual) there is a description of the THRE interrupt.


The UART0 THRE interrupt (U0IIR[3:1] = 001) is a third level interrupt
and is activated when the UART0 THR FIFO is empty provided certain
initialization conditions have been met. These initialization
conditions are intended to give the UART0 THR FIFO a chance to
fill up with data to eliminate many THRE interrupts from occurring at
system start-up. The initialization conditions implement a one
character delay minus the stop bit whenever THRE=1 and there have not
been at least two characters in the U0THR at one time since
the last THRE = 1 event. This delay is provided to give the CPU time
to write data to U0THR without a THRE interrupt to decode and service.
A THRE interrupt is set immediately if the UART0 THR FIFO has held
two or more characters at one time and currently, the U0THR is empty.
The THRE interrupt is reset when a U0THR write occurs or a read of the
U0IIR occurs and the THRE is the highest interrupt (U0IIR[3:1] = 001).


Ignoring the startup conditions where there is an immediate THRE
interrupt because the entire FIFO is empty and the next interrupt is
delayed a bit to allow the FIFO to fill, the important part is the
next to the last sentence where is states that a THRE interrupt is set
if the FIFO has ever held 2 chars (the initial fill) and U0THR (the
top of the FIFO) is empty.

However, this is all about the THRE interrupt, not the THRE flag in
U0LSR. There is no reason to assume a one-to-one relationship between
the flag being set and the interrupt being generated. Clearly the
device diddles with the initial interrupts to allow the FIFO to fill.
That doesn't mean that the flag is altered. In fact, if the flag was
only set for the very first byte and then wasn't set again until more
characters had been written, code that polled the flag but could never
write a second byte.

I believe it is correct to test THRE before every character write
because it will reflect the status of the top of the FIFO regardless
of what is happening with the THRE interrupt. This according to Table
84 (page 92).

If you are writing a string, I think you are almost always testing and
writing in a tight loop. I haven't seen an error in doing it:

void UART0_putc(unsigned char c)
{
while (! (U0LSR & THRE))
;
U0THR = c;
}

int puts(const char *s)
{
while (*s)
{
UART0_putc(*s);
s++;
}
return 0;
}

Or, maybe I missed the entire point. I just don't think that after
the initial fill, the THRE interrupt does anything except indicate
that THR (top of FIFO) is empty.

Richard

--- In l..., "rtstofer" wrote:

> I believe it is correct to test THRE before every character write
> because it will reflect the status of the top of the FIFO regardless
> of what is happening with the THRE interrupt. This according to Table
> 84 (page 92).
>

Richard,

I'd agree: I read it that it's always correct to test THRE before every
character and that if it's set it's OK to write the FIFO.

The ambiguity comes from whether the bit set means "ther's space in the
FIFO", which is a natural interpretation of the Philips UM or "the FIFO
is empty", which is an explicit statement in the NS and similar data
sheets.

Which is it? or am I completely misreading what you and Robert are
saying?

Brendan.
Quoting brendanmurphy37 :

> By the way, can you explain your statement that a "tight loop on THRE
> will bypass the FIFO"? Do you mean that the following can fail:
>
> Line 1: LOOP:
> Line 2: THRE bit set?
> Line 3: IF NOT SET GOTO LOOP
> Line 4: OK to write THR here! (up to 16-bytes if FIFO enabled)
>
> I'd assume that this would always work OK.

So would I.

I meant something like

Line 1: LOOP:
Line 2: THRE bit set?
Line 3: IF NOT SET GOTO LOOP
Line 4: Write to THR
Line 5: GOTO LOOP

should never write more than one character to the FIFO, thus bypassing it (at
least its fuctionality).

Even if THRE remained set for an extra character or two it shouldn't have much
of an effect, you would have to really be looking for it to find it. In order
for a delay in setting THRE setting to have an effect it woul have to be
delayed by the time it takes to overflow an empty FIFO.

That doesn't 'feel' right to me, I think something else is going on.

Robert

Quoting rtstofer :

>>
>> Agreed, although since it bypasses the FIFO I can't think of many
> cases where
>> you should be polling immediately after writing.
>>
>> Robert
>> I sure don't read the docs that way. The FIFO must be enabled to use
> the UART. The THR is defined to be the top of the FIFO. The issue is
> how does THRE work.
>
> On page 90 of the 24 June 2005 edition of UM10120 (LPC2138 User
> Manual) there is a description of the THRE interrupt.

It does work the way I mentioned at least on the early variants since I
do put a full FIFOs worth into the FIFO on THRE. I'd lose characters
if the interrupt
occured when the FIFO was partially empty.

>
>
> The UART0 THRE interrupt (U0IIR[3:1] = 001) is a third level interrupt
> and is activated when the UART0 THR FIFO is empty provided certain

Note when FIFO is empty. 'THR FIFO' refers to the entire FIFO not the
top entry
in the FIFO.

> If you are writing a string, I think you are almost always testing and
> writing in a tight loop. I haven't seen an error in doing it:

And you shouldn't. You are just not using the FIFO.

Robert

Quoting brendanmurphy37 :

> --- In l..., "rtstofer" wrote:
>
>> I believe it is correct to test THRE before every character write
>> because it will reflect the status of the top of the FIFO regardless
>> of what is happening with the THRE interrupt. This according to Table
>> 84 (page 92).
>> I'd agree: I read it that it's always correct to test THRE before every
> character and that if it's set it's OK to write the FIFO.

Well, it's not wrong to test THRE, just inefficient.
> The ambiguity comes from whether the bit set means "ther's space in the
> FIFO", which is a natural interpretation of the Philips UM or "the FIFO
> is empty", which is an explicit statement in the NS and similar data
> sheets.
>
> Which is it? or am I completely misreading what you and Robert are
> saying?

I don't think so. I do believe it's following stand '550 practice. If for no
other reason than if it didn't I'd expect to see evidence of overflows from
stuffing 16 characters into a partially full FIFO.

Also it seems odd they would claim '550 compatibility and then break it
in that
fashion. Not that that's ever happed before of course :)

Robert

--- In l..., Robert Adsett
wrote:
>
> Quoting brendanmurphy37 :
>
> > By the way, can you explain your statement that a "tight loop on
THRE
> > will bypass the FIFO"? Do you mean that the following can fail:
> >
> > Line 1: LOOP:
> > Line 2: THRE bit set?
> > Line 3: IF NOT SET GOTO LOOP
> > Line 4: OK to write THR here! (up to 16-bytes if FIFO enabled)
> >
> > I'd assume that this would always work OK.
>
> So would I.
>
> I meant something like
>
> Line 1: LOOP:
> Line 2: THRE bit set?
> Line 3: IF NOT SET GOTO LOOP
> Line 4: Write to THR
> Line 5: GOTO LOOP
>
> should never write more than one character to the FIFO, thus
bypassing it (at
> least its fuctionality).
>

OK - I understand your comment on bypassing the FIFO now.

Rather than continue with this thread, can I suggest we all agree
with the following conclusions:

- THRE bit set means "FIFO is empty"
- Therefore testing for it being set means its OK to write up to 16
bytes to the THR
- The Philips UM is at best ambiguous in its description of THRE
- None of us has actaully verified the exact behaviour, but we've no
reason to doubt it doesn't behave this way (i.e. same as "standard"
16550)

Brendan.
Quoting brendanmurphy37 :
> Rather than continue with this thread, can I suggest we all agree
> with the following conclusions:
>
> - THRE bit set means "FIFO is empty"
> - Therefore testing for it being set means its OK to write up to 16
> bytes to the THR
> - The Philips UM is at best ambiguous in its description of THRE

Sounds right.

> - None of us has actaully verified the exact behaviour, but we've no
> reason to doubt it doesn't behave this way (i.e. same as "standard"
> 16550)

I've done some since I'm assuming in my code that THRE flag means the FIFO is
empty and stuff multiple characters in. I'm not losing any characters
so there
has to be room available. Nothing definitive though, for that I'd want
to do a
specific test filling the FIFO with 16 characters on each interrupt or THRE
flag setting at a slow baud rate (so no characters can be completely
sent while
the FIFO is being filled).

Robert