Forums

Questions on the UART Interface

Started by Leighton Rowe November 17, 2004

Just for clarification on the UART Block Diagram (see UM)...
1. Do U0TSR & U0RSR actually representthe Tx & Rx FIFO buffers? I
only see U0TSR & U0RSR illustrated here and I can't find any other
documentation for it.

Now concerning U0THR & U0RBR (data registers)...
2. Why do they both share the same memory address? I'd really like
to know the purpose of this.

3. What will happen if the lpc receives a character while I'm
writing to the transmit register?

I ask this because currently, I'm having trouble running the serial
port both ways (with interrupts) while sending replies and receiving
command packets from the PC. Sometimes the protocol I'm using works.
However, while debugging I always notice the lpc losing receiver
bytes whenever communication goes wrong. I only observe this
happening if the lpc's replying to a command packet and another
command packet's coming in the same time.

best regards,
Leighton




An Engineer's Guide to the LPC2100 Series

At 08:55 PM 11/17/04 +0000, you wrote:
>Now concerning U0THR & U0RBR (data registers)...
>2. Why do they both share the same memory address? I'd really like
>to know the purpose of this.

Consider the R/W line an extra address bit if it helps. They don't share
the same physical memory. The idea (from the 8250 on) is that since you
never read the transmit register and never write the receive register that
they can be distinguished simply by the state of the read line and save all
that extra address space and decoding logic (also explains why the divisor
latch is a banked register). These would be from the same school of chip
designers that believe you never actually need to read setup registers. >3. What will happen if the lpc receives a character while I'm
>writing to the transmit register?

It's supposed to act just fine. >I ask this because currently, I'm having trouble running the serial
>port both ways (with interrupts) while sending replies and receiving
>command packets from the PC. Sometimes the protocol I'm using works.
>However, while debugging I always notice the lpc losing receiver
>bytes whenever communication goes wrong. I only observe this
>happening if the lpc's replying to a command packet and another
>command packet's coming in the same time.

Are you sure it's not the other way around? I have seen a similar problem
but I keep losing THRE interrupts. It appears they 'disappear' if the LPC
receives a byte while the interrupt identification register was being
read. I have a work-around that appears to at least reduce the problem
(I've not had it reappear) that only reads the IIR once per interrupt.

It behaves similarly to the documented race conditions on the LPC
(particularly the timers) but I've not seen anybody report duplicating it yet.

Needless to say, I'd like to know for sure what's going on with it and you
seem to have come closest to duplicating the conditions I see it under
(both interrupts active, transmit and receive happening simultaneously).

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III



--- In , "Leighton Rowe" <leightonsrowe@y...>
wrote:
>
> Just for clarification on the UART Block Diagram (see UM)...
> 1. Do U0TSR & U0RSR actually representthe Tx & Rx FIFO buffers? I
> only see U0TSR & U0RSR illustrated here and I can't find any other
> documentation for it.

No, they are the actual shift registers. U0TSR can be checked with
U0LSR bit 6, TEMT. TEMT=0 => U0TSR is shifting out a byte, TEMT=1 =>
U0TSR is idle. The 16-byte FIFOs aren't shown in the figure, but
would rather correspond to U0THR and U0RBR. For better
documentation, Google for 16C550. > Now concerning U0THR & U0RBR (data registers)...
> 2. Why do they both share the same memory address? I'd really like
> to know the purpose of this.

Writing to the address means writing to U0THR, and reading from the
address means reading from U0RBR. They occupy the same address
because Philips chose to be software compatible with the 16C550,
which was designed to be hardware and software compatible with the
8250, which was designed at a time when I/O addresses apparently were
very precious. For an even worse example of this mindset, see the
Intel 8259 interrupt controller which occupies two(!) I/O addresses. > 3. What will happen if the lpc receives a character while I'm
> writing to the transmit register?

Nothing special, the receiver and transmitter work independently.
But make sure that you don't miss any of them in your interrupt
handler. > I ask this because currently, I'm having trouble running the serial
> port both ways (with interrupts) while sending replies and
receiving
> command packets from the PC. Sometimes the protocol I'm using
works.
> However, while debugging I always notice the lpc losing receiver
> bytes whenever communication goes wrong. I only observe this
> happening if the lpc's replying to a command packet and another
> command packet's coming in the same time.

When you enable more than one interrupt in U0IER (such as both
receive and transmit interrupt), you should in your interrupt handler
check U0IIR to see what caused the interrupt. More than one
interrupt can occur at a time, and the highest priority one is
indicated in U0IIR.

Pay close attention to the "Interrupt Reset" column in the UART0
Interrupt Handling table. When you have seen in U0IIR what caused
the interrupt, you should handle it, and then do the action in
the "Interrupt Reset" column to tell the UART that you have handled
it. For a receive interrupt, the Interrupt Reset action is to
read U0RBR, so it is a quite normal part of handling a receive
interrupt. For a transmit interrupt, the reset action is simply
reading U0IIR, which you have already done since you know it is a
transmit interrupt.

If you don't do the Interrupt Reset action in your interrupt handler
for a pending interrupt, the UART will immediately interrupt again.
So you can write your interrupt handler in two ways:

a. Check U0IIR, handle the highest-priority pending interrupt,
thereby doing the Interrupt Reset action, and return. If more than
one interrupt was pending, the UART will immediately interrupt again,
and then present the next-highest priority interrupt in U0IIR, and so
on. This way is the easiest, and the best one if multiple
simultaneous interrupts are rare.

b. Check U0IIR, handle the highest-priority pending interrupt,
thereby doing the Interrupt Reset action. Re-check U0IIR, and loop
around if another interrupt is pending. When no more interrupts are
pending, return. This way is better if multiple simultaneous
interrupts are so likely that it pays off to save the multiple
interrupt entry/exit code. Regards,
Karl Olsen



At 10:07 PM 11/17/04 +0000, you wrote:
>b. Check U0IIR, handle the highest-priority pending interrupt,
>thereby doing the Interrupt Reset action. Re-check U0IIR, and loop
>around if another interrupt is pending. When no more interrupts are
>pending, return. This way is better if multiple simultaneous
>interrupts are so likely that it pays off to save the multiple
>interrupt entry/exit code.

That's certainly the way it's supposed to work (and the way I have done it
on 'real' 16550s) but when I do this on an LPC2106 with both transmit and
receive interrupts I occasionally miss THRE interrupts (they just never
occur). This only happens when receive is occurring at the same time as
transmit (I used a simple echo test) and it only occurs infrequently
(several 100K up to a megabyte or more of transmitted bytes before it would
halt). The only explanation I have is an undocumented race condition in
updating the IIR as it is being read but as I said in an earlier post I
haven't seen any duplication. Changing to the less conventional one IIR
read per interrupt seems to eliminate the problem but maybe all it does is
reduce the probability.

Leighton's symptoms appear to be similar to (but not the same as) what I've
seen so I'm wondering if he hasn't run across the same underlying problem I
have.

The THRE interrupts are the only serial interrupts that do not re-assert if
they are not serviced so they are particularly vulnerable.

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III




Sorry for the delay guys,

Point taken for the answers to 1,2, and 3. Thanks Karl & Robert.

> Leighton's symptoms appear to be similar to (but not the same as)
what I've
> seen so I'm wondering if he hasn't run across the same underlying
problem I
> have.
>
> The THRE interrupts are the only serial interrupts that do not re-
assert if
> they are not serviced so they are particularly vulnerable.
>

Robert, I haven't yet seen the problem you described that's
interestingly the opposite to what I'm getting. Debugging through
the JTAG and using a serial port data logger I see all the receiver
bytes coming in from the PC. I usually send up to 16 bytes per THRE
& for the most part the lpc sends the reply packet correctly. But
only in that special case I see the lpc not respond to the last
command packet. It came across the receive line ok (logger) so the
PC's ok. However on the lpc side I debug and see the packet looking
truncated. Like some bytes got lost while receiving, which looks
kinda wierd. I haven't yet seen the opposite happen b4.

> a. Check U0IIR, handle the highest-priority pending interrupt,
> thereby doing the Interrupt Reset action, and return. If more
than
> one interrupt was pending, the UART will immediately interrupt
again,
> and then present the next-highest priority interrupt in U0IIR, and
so
> on. This way is the easiest, and the best one if multiple
> simultaneous interrupts are rare.
>
> b. Check U0IIR, handle the highest-priority pending interrupt,
> thereby doing the Interrupt Reset action. Re-check U0IIR, and
loop
> around if another interrupt is pending. When no more interrupts
are
> pending, return. This way is better if multiple simultaneous
> interrupts are so likely that it pays off to save the multiple
> interrupt entry/exit code.

Interesting stuff Karl. I wasn't really paying attention to the IIR
table. So, I'll have to review my code just incase I did a bit too
much for RDA & THRE. Basically, the code I'm using is following Plan
B. Bill Knight's code follows the same concept too. I'll give Plan A
a try though, since my PC <-> lpc communication is on a small scale,
and Robert's having more success with it.




At 02:15 PM 11/18/04 +0000, you wrote:
> > Leighton's symptoms appear to be similar to (but not the same as)
>what I've
> > seen so I'm wondering if he hasn't run across the same underlying
>problem I
> > have.
> >
> > The THRE interrupts are the only serial interrupts that do not re-
>assert if
> > they are not serviced so they are particularly vulnerable.
> >
>
>Robert, I haven't yet seen the problem you described that's
>interestingly the opposite to what I'm getting. Debugging through
>the JTAG and using a serial port data logger I see all the receiver
>bytes coming in from the PC. I usually send up to 16 bytes per THRE
>& for the most part the lpc sends the reply packet correctly. But
>only in that special case I see the lpc not respond to the last
>command packet. It came across the receive line ok (logger) so the
>PC's ok. However on the lpc side I debug and see the packet looking
>truncated. Like some bytes got lost while receiving, which looks
>kinda wierd. I haven't yet seen the opposite happen b4.

I had a thought. If my speculation about a race condition in IIR is
correct it may well explain both our problems. In my case I lose the THRE
interrupt and thus stop transmitting. In your case you lose a receive
interrupt and drop a character. My test wouldn't catch a dropped character
since I wasn't running any sort of check or comparison so all I would see
is if the echo stopped cold (if a receive interrupt was missed it would
just pick up the next one).

Do you know (and can you tell) if the packet is truncated or maybe just
missing characters from its body? If it always just characters at the end
I'm less optimistic about the race condition.

If it is a race in the IIR then a single read per interrupt might help (or
it might not) depending on the details of the race and the timing (ICK).

In any case let us know how changing to a single IIR read per interrupt
affects the problem. Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III




> Do you know (and can you tell) if the packet is truncated or maybe
just
> missing characters from its body? If it always just characters at
the end
> I'm less optimistic about the race condition.

Well after double checking & changing my code to the single IIR read
concept, things remained the same. The affected packet I receive
always get's somewhat truncated in the middle, with the last bytes
showing up a few bytes earlier than expected.

I however notice LSR interrupt occuring at the point where the
problem occurs but I don't see any signs of any LSR errors.

Just a crazy question though...can the UART ISR interrupt itself?
(eg. while processing a THRE an RDA interrupt comes in)

Should I enable the FIFOs (write 1 to U0FCR) before running the
interrupts? I seem to be getting by without this up until this point.

Thanks again,
Leighton




At 07:00 PM 11/18/04 +0000, you wrote:
> > Do you know (and can you tell) if the packet is truncated or maybe
>just
> > missing characters from its body? If it always just characters at
>the end
> > I'm less optimistic about the race condition.
>
>Well after double checking & changing my code to the single IIR read
>concept, things remained the same. The affected packet I receive
>always get's somewhat truncated in the middle, with the last bytes
>showing up a few bytes earlier than expected.

Well that fits with the speculation of an IIR race condition. Doesn't
prove it but it does fit. You may have duplicated what I've been seeing. >I however notice LSR interrupt occuring at the point where the
>problem occurs but I don't see any signs of any LSR errors.

Hmmm... Doesn't make much sense to me either. Maybe instead of a simple
race the source is being miss-classified? My own test would not have seen
a difference between that and the interrupt simply dissappearing. >Just a crazy question though...can the UART ISR interrupt itself?
>(eg. while processing a THRE an RDA interrupt comes in)

At the very least that would require that you re-enable the associated
interrupt (IRQ or FIQ) and if vectored through the VIC you would also have
to acknowledge the vectored interrupt with the appropriate write to the VIC
first as well. If you've done that, try it again w/o re-enabling the
interrupts. >Should I enable the FIFOs (write 1 to U0FCR) before running the
>interrupts? I seem to be getting by without this up until this point.

I don't see why that would eliminate the problem. Worse it might hide it
so that it showed up later under less benign conditions.

Curiouser and curiouser
Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III




> >Should I enable the FIFOs (write 1 to U0FCR) before running the
> >interrupts? I seem to be getting by without this up until this
point.
>
> I don't see why that would eliminate the problem. Worse it might
hide it
> so that it showed up later under less benign conditions.
>

Good news...I got communication running alot better after enabling
FIFOs (U0FCR = 1) at startup. So far, no Rx & Tx glitches yet. Try
doing the same to see what happens.

For now the LSR mystery is worth forgetting. Leighton




At 08:02 PM 11/18/04 +0000, you wrote:
> > >Should I enable the FIFOs (write 1 to U0FCR) before running the
> > >interrupts? I seem to be getting by without this up until this
>point.
> >
> > I don't see why that would eliminate the problem. Worse it might
>hide it
> > so that it showed up later under less benign conditions.
> >
>
>Good news...I got communication running alot better after enabling
>FIFOs (U0FCR = 1) at startup. So far, no Rx & Tx glitches yet. Try
>doing the same to see what happens.

That rather worries me. I will give it try and see what it does on my code
though (I've got a few other items to take care of first). I place it in
the same category as my read-IIR-only-once-per-interrupt 'fix' though. I
strongly suspect it's only masking temporarily whatever the underlying
cause is.

I suspect there is something similar going on here as happens with the SPI
and the timers. We've now got two independent reports of missing
interrupts on the UART with no clear source of the problem.

Robert " 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III