Forums

UART TX FIFO, INTs problem

Started by microbit February 17, 2004
Hi all,
 
I'm a bit stuck with this one, and hope someone has some advice,
I must be overlooking something and I just don't see it.......
 
I'm using Two 256 byte circular buffers for RX and TX Interrupts on UART0.
 
Putchar() writes a char to the TX buffer's current head pointer and post
increments it (auto wrap on index byte). It then increments the # of TX chars
in the buffer (tx_chars) and enables the THRE Interrupt.
 
The THRE handler part takes a character from the tail pointer, and post increments.
It then decrements tx_chars.
If TX buffer tail equals TX buffer Head, the THRE Interrupt is disabled.
 
Of course in case I write too fast to the TX buffer and it overflows (to simplify for the time being)
at the end of Putchar() I check if tx_chars is larger than say, 200 Chars.
If it is, I wait in a while loop for tx_chars to drop below a threshold, say 32.
 
I've used this principle on many MCUs, and never had a problem.
 
The problem is that if I write a _constant_ flow of characters much faster than the Baudrate
after quite some time the transmission INTs stop.
[ NO other interrupts are running during this test ]
To test it, I set a pin HIGH when Putchar() is waiting for the TX buffer to empty a bit,
and clear it when buffer filling resumes - a bit like this :
 
volatile unsigned char tx_chars;
 
.....                      /* write char to buffer */
++tx_chars ;        /* another char in TX buffer */
if ( tx_chars > 200 )
    {   
    /* set test pin HIGH */   
    while ( tx_chars > 32 ) ;    /* let TX buffer flush out a bit */
    }
/* set test pin LOW */
}
 
I can see all is fine, the TEST pin spends time HIGH while the buffer is being flushed,
and is then LOW for a few mS (printf() is re-filling up the buffer from 32 or less to > 200 chars)
 
When the transmit out of UART0 TX stops, tx_chars is set to one more than the threshold
(for example - here 33 ), and Tail and Head Pointer of TX buffer are equal, hence the THRE
interrupt is disabled.
The code of course is stuck in the while ( tx_chars > 32 ) loop ......
 
A plausible explanation would be that at times, the TX FIFO holds more than one byte, and
when the THRE interrupt occurs, more than one char should be subtracted from tx_chars.
This could explain why tx_chars isn't <Zero> when TX Head and TX Tail become equal and
THRE INTs turn OFF.
On the other hand this doesn't make sense, as the TX FIFO should be transparent to that
process. Also, if this was a simple FIFO issue, that process should lock up after a few hundred
characters are transmitted.
 
There is nothing in the user guide on LPC2106 that clarifies how exactly the TX FIFO and
the THRE interact.
Although the guide says that FIFOs should be enabled for proper UART operation, leaving
U0FCR to ZERO makes no difference, nor does changing the FIFO trigger level (again wording
is ambiguous here, left column implies RX FIFO only , right column bitmap implies both RX and
TX FIFOs.
 
In fact I don't see the point of the TX FIFO if your THRE/TEMT can't tell you whether you just
flushed out 1 or <trigger level> bytes.
 
Is anyone seeing what the problem is ?
I'm stumped.
 
Best regards,
Kris
 
 
 



An Engineer's Guide to the LPC2100 Series

I am just wondering.... are you using GCC compiler?
if yes, from what i have heard, it is not very good in context switches....
ie. it can mess up when storing registers R0 to R12 in ISRs. A nice way
arroung is to have an interrupt wrapper.

Regards,

Musharraf >From: "microbit" <>
>Reply-To:
>To: "LPC2000_group" <>
>Subject: [lpc2000] UART TX FIFO, INTs problem
>Date: Wed, 18 Feb 2004 05:16:39 +1100
>
>Hi all,
>
>I'm a bit stuck with this one, and hope someone has some advice,
>I must be overlooking something and I just don't see it.......
>
>I'm using Two 256 byte circular buffers for RX and TX Interrupts on UART0.
>
>Putchar() writes a char to the TX buffer's current head pointer and post
>increments it (auto wrap on index byte). It then increments the # of TX
>chars
>in the buffer (tx_chars) and enables the THRE Interrupt.
>
>The THRE handler part takes a character from the tail pointer, and post
>increments.
>It then decrements tx_chars.
>If TX buffer tail equals TX buffer Head, the THRE Interrupt is disabled.
>
>Of course in case I write too fast to the TX buffer and it overflows (to
>simplify for the time being)
>at the end of Putchar() I check if tx_chars is larger than say, 200 Chars.
>If it is, I wait in a while loop for tx_chars to drop below a threshold,
>say 32.
>
>I've used this principle on many MCUs, and never had a problem.
>
>The problem is that if I write a _constant_ flow of characters much faster
>than the Baudrate
>after quite some time the transmission INTs stop.
>[ NO other interrupts are running during this test ]
>To test it, I set a pin HIGH when Putchar() is waiting for the TX buffer to
>empty a bit,
>and clear it when buffer filling resumes - a bit like this :
>
>volatile unsigned char tx_chars;
>
>..... /* write char to buffer */
>++tx_chars ; /* another char in TX buffer */
>if ( tx_chars > 200 )
> {
> /* set test pin HIGH */
> while ( tx_chars > 32 ) ; /* let TX buffer flush out a bit */
> }
>/* set test pin LOW */
>}
>
>I can see all is fine, the TEST pin spends time HIGH while the buffer is
>being flushed,
>and is then LOW for a few mS (printf() is re-filling up the buffer from 32
>or less to > 200 chars)
>
>When the transmit out of UART0 TX stops, tx_chars is set to one more than
>the threshold
>(for example - here 33 ), and Tail and Head Pointer of TX buffer are equal,
>hence the THRE
>interrupt is disabled.
>The code of course is stuck in the while ( tx_chars > 32 ) loop ......
>
>A plausible explanation would be that at times, the TX FIFO holds more than
>one byte, and
>when the THRE interrupt occurs, more than one char should be subtracted
>from tx_chars.
>This could explain why tx_chars isn't <Zero> when TX Head and TX Tail
>become equal and
>THRE INTs turn OFF.
>On the other hand this doesn't make sense, as the TX FIFO should be
>transparent to that
>process. Also, if this was a simple FIFO issue, that process should lock up
>after a few hundred
>characters are transmitted.
>
>There is nothing in the user guide on LPC2106 that clarifies how exactly
>the TX FIFO and
>the THRE interact.
>Although the guide says that FIFOs should be enabled for proper UART
>operation, leaving
>U0FCR to ZERO makes no difference, nor does changing the FIFO trigger level
>(again wording
>is ambiguous here, left column implies RX FIFO only , right column bitmap
>implies both RX and
>TX FIFOs.
>
>In fact I don't see the point of the TX FIFO if your THRE/TEMT can't tell
>you whether you just
>flushed out 1 or <trigger level> bytes.
>
>Is anyone seeing what the problem is ?
>I'm stumped.
>
>Best regards,
>Kris

_________________________________________________________________
Add photos to your e-mail with MSN 8. Get 2 months FREE*.
http://join.msn.com/?pageatures/featuredemail


Thanks Musharraf,

In the meantime I learnt the hard way :-)
Yes, I have run into a problem where the GCC based part screws up
the context, reducing optimisation fixed it.
This threw me out for quite some time. grrrr :-(

B rgds
Kris

----- Original Message -----
From: "Musharraf Hanif" <>
To: <>
Sent: Wednesday, February 18, 2004 7:39 PM
Subject: RE: [lpc2000] UART TX FIFO, INTs problem > I am just wondering.... are you using GCC compiler?
> if yes, from what i have heard, it is not very good in context
switches....
> ie. it can mess up when storing registers R0 to R12 in ISRs. A nice way
> arroung is to have an interrupt wrapper.
>
> Regards,
>
> Musharraf > >From: "microbit" <>
> >Reply-To:
> >To: "LPC2000_group" <>
> >Subject: [lpc2000] UART TX FIFO, INTs problem
> >Date: Wed, 18 Feb 2004 05:16:39 +1100
> >
> >Hi all,
> >
> >I'm a bit stuck with this one, and hope someone has some advice,
> >I must be overlooking something and I just don't see it.......
> >
> >I'm using Two 256 byte circular buffers for RX and TX Interrupts on
UART0.
> >
> >Putchar() writes a char to the TX buffer's current head pointer and post
> >increments it (auto wrap on index byte). It then increments the # of TX
> >chars
> >in the buffer (tx_chars) and enables the THRE Interrupt.
> >
> >The THRE handler part takes a character from the tail pointer, and post
> >increments.
> >It then decrements tx_chars.
> >If TX buffer tail equals TX buffer Head, the THRE Interrupt is disabled.
> >
> >Of course in case I write too fast to the TX buffer and it overflows (to
> >simplify for the time being)
> >at the end of Putchar() I check if tx_chars is larger than say, 200
Chars.
> >If it is, I wait in a while loop for tx_chars to drop below a threshold,
> >say 32.
> >
> >I've used this principle on many MCUs, and never had a problem.
> >
> >The problem is that if I write a _constant_ flow of characters much
faster
> >than the Baudrate
> >after quite some time the transmission INTs stop.
> >[ NO other interrupts are running during this test ]
> >To test it, I set a pin HIGH when Putchar() is waiting for the TX buffer
to
> >empty a bit,
> >and clear it when buffer filling resumes - a bit like this :
> >
> >volatile unsigned char tx_chars;
> >
> >..... /* write char to buffer */
> >++tx_chars ; /* another char in TX buffer */
> >if ( tx_chars > 200 )
> > {
> > /* set test pin HIGH */
> > while ( tx_chars > 32 ) ; /* let TX buffer flush out a bit */
> > }
> >/* set test pin LOW */
> >}
> >
> >I can see all is fine, the TEST pin spends time HIGH while the buffer is
> >being flushed,
> >and is then LOW for a few mS (printf() is re-filling up the buffer from
32
> >or less to > 200 chars)
> >
> >When the transmit out of UART0 TX stops, tx_chars is set to one more than
> >the threshold
> >(for example - here 33 ), and Tail and Head Pointer of TX buffer are
equal,
> >hence the THRE
> >interrupt is disabled.
> >The code of course is stuck in the while ( tx_chars > 32 ) loop ......
> >
> >A plausible explanation would be that at times, the TX FIFO holds more
than
> >one byte, and
> >when the THRE interrupt occurs, more than one char should be subtracted
> >from tx_chars.
> >This could explain why tx_chars isn't <Zero> when TX Head and TX Tail
> >become equal and
> >THRE INTs turn OFF.
> >On the other hand this doesn't make sense, as the TX FIFO should be
> >transparent to that
> >process. Also, if this was a simple FIFO issue, that process should lock
up
> >after a few hundred
> >characters are transmitted.
> >
> >There is nothing in the user guide on LPC2106 that clarifies how exactly
> >the TX FIFO and
> >the THRE interact.
> >Although the guide says that FIFOs should be enabled for proper UART
> >operation, leaving
> >U0FCR to ZERO makes no difference, nor does changing the FIFO trigger
level
> >(again wording
> >is ambiguous here, left column implies RX FIFO only , right column bitmap
> >implies both RX and
> >TX FIFOs.
> >
> >In fact I don't see the point of the TX FIFO if your THRE/TEMT can't tell
> >you whether you just
> >flushed out 1 or <trigger level> bytes.
> >
> >Is anyone seeing what the problem is ?
> >I'm stumped.
> >
> >Best regards,
> >Kris
> >
> >
>
> _________________________________________________________________
> Add photos to your e-mail with MSN 8. Get 2 months FREE*.
> http://join.msn.com/?pageatures/featuredemail >
> --
------
> Yahoo! Groups Links
>
> a.. To





Well, go figure.
 
Is there something wrong with directly writing to UOIER
to turn THRE INts on and off ?
 
This is what I sed :
 
Write 0x01 to U0IER    (disable THRE Int, leave RDA)
Write to tx_chars
Write 0x03 to U0IER    (THRE and RDA enabled again)
 
The first line, 0x01 -> U0IER was causing the resets.
 
When I globally disable and then re-enable INTs in CPSR instead, it works
perfect, I should have tried that first... hmm
I'm not using any other Interrupts, so I can't see why the writes to
turn THRE on and off directly in U0IER shouldn't work.
 
Anyone ?
 
-- Kris
 


At 02:37 AM 2/19/04 +1100, you wrote:
>In the meantime I learnt the hard way :-)
>Yes, I have run into a problem where the GCC based part screws up
>the context, reducing optimisation fixed it.
>This threw me out for quite some time. grrrr :-(

I gave up on using C directly for interrupts long ago. I've run into too
many compiler failures where they either produced wrong code or were so
pessimistic they increased the overhead by several multiples. I'll often
do my own prolog and epilog and then call the C myself. If nothing else
it's a good way to learn the ins & outs of the processor. Just as often
(probably more often) I'm using an interrupt for performance reasons and I
want to minimize the context switch overhead and/or access chip features
that are not (easily) accessible in C (particularly standard C). In that
case asm can sometimes be an order of magnitude faster.

" '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