EmbeddedRelated.com
Forums

UART TX FIFO and INTs problem

Started by forum_microbit February 17, 2004
At 06:38 AM 2/19/04 +1100, you wrote:
> > FIFO. When you get an interrupt you can sit in a loop and stuff the FIFO
> > full before returning. That nicely lowers the interrupt overhead by a
> > factor of 15 or 16. On the down side the main service body will take
> > longer, maybe not a full 15x longer but longer so that each individual
> > interrupt may be longer and increase your latency. If you just put in one
> > character and exit the interrupt it will probably act just as you say.
>
>How do you then know when the FIFO is full ? There is nothing
>accessible to tell you.
>Do you maintain a counter loop that lets you only write up to 16 chars
>in the FIFO ?
>The description on page 89 is really ambiguous, it implies that if 2 or more
>chars are in the FIFO _and_ the shiftregister has just flushed out a char,
>that THRE will set too.
>THRE when FIFO empty "provided" certain init conditions have been met.
>Is this referring to the char delay so no INTs will issue straight away at
>start up ?
>I guess so.

I don't see another way than maintaining a counter. From National's data
sheet pg 19

When the XMIT FIFO and transmitter interrupts are enabled
(FCR0e1, IER1e1), XMIT interrupts will occur as follows:

A. The transmitter holding register interrupt (02) occurs
when the XMIT FIFO is empty; it is cleared as soon as
the transmitter holding register is written to (1 to 16 characters
may be written to the XMIT FIFO while servicing
this interrupt) or the IIR is read.

B. The transmitter FIFO empty indications will be delayed 1
character time minus the last stop bit time whenever the
following occurs: THREe1 and there have not been at
least two bytes at the same time in the transmit FIFO,
since the last THREe1. The first transmitter interrupt after
changing FCR0 will be immediate, if it is enabled.

Character timeout and RCVR FIFO trigger level interrupts
have the same priority as the current received data available
interrupt; XMIT FIFO empty has the same priority as
the current transmitter holding register empty interrupt.

It's a little easier to follow in the datasheet.

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


An Engineer's Guide to the LPC2100 Series

Thanks Robert,

I had downloaded it in the meantime, and had gone through it.
Bitmaps etc. seemed identical to LPC2000, so I guess it's
a true 16C550 "industry-standard" like the datasheet claims.

BTW : Maybe I should clarify that when I mentioned about disabling
global INTs instead of U0IER.THRE, that I was referring to the IRQs
of course.
The program that caused resets before has been running for over an
hour now, and no problems anymore.
It might also pay to note that I use the ldr pc, [pc,-0xFF0] instruction
for immediate vectoring.

I really studied the VIC part, and there was no mention anywhere that you
can't disable/re-enable specific IRQs the way I did.
Still got more studying to do I guess, if anyone has any ideas why this was
happening, I'd love to hear about it.

Re. doign prologue/epilogue in ASM, I totally agree that it's a good way
to learn the ins and outs better of the CPU. That was going to be the next
thing I did.

-- Kris
----- Original Message -----
From: "Robert Adsett" <>
To: <>
Sent: Thursday, February 19, 2004 7:34 AM
Subject: Re: [lpc2000] UART TX FIFO and INTs problem > At 06:38 AM 2/19/04 +1100, you wrote:
> > > FIFO. When you get an interrupt you can sit in a loop and stuff the
FIFO
> > > full before returning. That nicely lowers the interrupt overhead by a
> > > factor of 15 or 16. On the down side the main service body will take
> > > longer, maybe not a full 15x longer but longer so that each individual
> > > interrupt may be longer and increase your latency. If you just put in
one
> > > character and exit the interrupt it will probably act just as you say.
> >
> >How do you then know when the FIFO is full ? There is nothing
> >accessible to tell you.
> >Do you maintain a counter loop that lets you only write up to 16 chars
> >in the FIFO ?
> >The description on page 89 is really ambiguous, it implies that if 2 or
more
> >chars are in the FIFO _and_ the shiftregister has just flushed out a
char,
> >that THRE will set too.
> >THRE when FIFO empty "provided" certain init conditions have been met.
> >Is this referring to the char delay so no INTs will issue straight away
at
> >start up ?
> >I guess so.
>
> I don't see another way than maintaining a counter. From National's data
> sheet pg 19
>
> When the XMIT FIFO and transmitter interrupts are enabled
> (FCR0e1, IER1e1), XMIT interrupts will occur as follows:
>
> A. The transmitter holding register interrupt (02) occurs
> when the XMIT FIFO is empty; it is cleared as soon as
> the transmitter holding register is written to (1 to 16 characters
> may be written to the XMIT FIFO while servicing
> this interrupt) or the IIR is read.
>
> B. The transmitter FIFO empty indications will be delayed 1
> character time minus the last stop bit time whenever the
> following occurs: THREe1 and there have not been at
> least two bytes at the same time in the transmit FIFO,
> since the last THREe1. The first transmitter interrupt after
> changing FCR0 will be immediate, if it is enabled.
>
> Character timeout and RCVR FIFO trigger level interrupts
> have the same priority as the current received data available
> interrupt; XMIT FIFO empty has the same priority as
> the current transmitter holding register empty interrupt.
>
> It's a little easier to follow in the datasheet.
>
> " '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 >
> --
------
> Yahoo! Groups Links
>
> a.. To





I just uploaded a ZIP file containing my UART and
elapsed system timer code. It is a simple program
which uses some very helpful support routines. The
code is configured for the Nohau LPC2106 TESTER eval
board but is easily reconfigurable for other LPC
processors.

Regards
-Bill Knight
R O SoftWare


Hi all,

This s a hairy one - ARM Gurus, please read this !!!
(Bill, this will cause a problem in your UART package too, since you
set VicDefVectAddr to the Reset Vector, and you also use a RMW
operation on UxIER)

I figured out why I was getting "resets" while UART0 is TXing
interrupt driven.
The problem only occurs when I disable the THE interrupt by masking :

U0IER &= ~ 0x02;    /* Disable THE */
......
U0IER |= 0x02;

When I disable and then re-enable THE interrupts with a direct write :

U0IER = 0x01;        /* Disable THE, leave RDA enabled */
.....
U0IER = 0x03;        /* Reenable THE */

I didn't get these "resets".

This is the problem :
-----------------------

I didn't have VicDefVectAddr specified, so it was set to its default 0x00000000
address. (All IRQs are disabled, except for VIC Channel # 6)
While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the THE
is disabled, BUT the interrupt asserts at the right moment, hence causing a non-vectored
assertion.... (which of course vectors to 0x000000, and ultimately results in a RESET)
Is this a known problem on the VIC ?
Is this normal on the VIC ?

I put in a "dummy" function default_IRQ_handler() so I can break on it, and when it hits
that function, VicRawIntr reads 0x3008.
If I merely indicate on a LED when that function is hit, but then return from interrupt, the
execution happpily picks up after the U0IER &=~0x02; statement, and things run as good as gold.
NO TX interrupts were missed by the looks of it, since the non-vectored dummy function doesn't
service or alter anything, the pending interrupt must be serviced when THE is re-emabled.

Are there any ARM gurus here that can shed some light on this ?
I've been just about driven to tears over this problem.
I can't just use a direct write (I have an interrupt on the other UART in RX, and that operates on
a CRC function, the RF transmit function needs to operate on the same CRC function, so I need
masking of the Interrupt Enables, rather than directly setting/clearing all INT sources on UxIER)

As far as I'm concerned this classifies as a silicon BUG, since UxIER bits cannot assert themselves,
and it is indeed a R/W register.

BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int is asserted ?
I can't find a bitmap on it.

Best regards,
Kris

> BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int
is asserted ?
> I can't find a bitmap on it.

Thinking about this again,
I presume that the bit # in VicRawIntr corresponds to the VIC Slot # ?
That would mean that ARM Core, Embedded ICE - DbgCommTX
and PLL Locl, RTCCIF are always asserted when I have the break point in
the Default IRQ handler ?

-- Kris


Kris
Thanks for spotting this. It's the old spurious interrupt problem.
The fix is to disable global interrupts around the first read-modify-write
instruction. Doing the direct write (U0IER = xxx) can still allow the problem
to happen. What happens is the interrupt occurs and is recognized while
the masking instruction is executing but before it has completed. Then
when the instruction does complete, the interrupt can't find the vector
so uses the default. So to fix:

Disable global interrupts
mask interrupt
Enable global interrupts

do your stuff
unmask interrupt

NOTE: I don't think this last modification of the mask register needs
protection. Someone correct me if I am wrong. Regards
-Bill Knight
R O SoftWare
On Mon, 23 Feb 2004 02:09:38 +1100, microbit wrote:

Hi all,

This s a hairy one - ARM Gurus, please read this !!!
(Bill, this will cause a problem in your UART package too, since you
set VicDefVectAddr to the Reset Vector, and you also use a RMW
operation on UxIER)

I figured out why I was getting "resets" while UART0 is TXing
interrupt driven.
The problem only occurs when I disable the THE interrupt by masking :

U0IER &= ~ 0x02; /* Disable THE */
......
U0IER |= 0x02;

When I disable and then re-enable THE interrupts with a direct write :

U0IER = 0x01; /* Disable THE, leave RDA enabled */
.....
U0IER = 0x03; /* Reenable THE */

I didn't get these "resets".

This is the problem :
-----------------------

I didn't have VicDefVectAddr specified, so it was set to its default 0x00000000
address. (All IRQs are disabled, except for VIC Channel # 6)
While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the THE
is disabled, BUT the interrupt asserts at the right moment, hence causing a non-vectored
assertion.... (which of course vectors to 0x000000, and ultimately results in a RESET)
Is this a known problem on the VIC ?
Is this normal on the VIC ?

I put in a "dummy" function default_IRQ_handler() so I can break on it, and when it hits
that function, VicRawIntr reads 0x3008.
If I merely indicate on a LED when that function is hit, but then return from interrupt, the
execution happpily picks up after the U0IER &=~0x02; statement, and things run as good as gold.
NO TX interrupts were missed by the looks of it, since the non-vectored dummy function doesn't
service or alter anything, the pending interrupt must be serviced when THE is re-emabled.

Are there any ARM gurus here that can shed some light on this ?
I've been just about driven to tears over this problem.
I can't just use a direct write (I have an interrupt on the other UART in RX, and that operates on
a CRC function, the RF transmit function needs to operate on the same CRC function, so I need
masking of the Interrupt Enables, rather than directly setting/clearing all INT sources on UxIER)

As far as I'm concerned this classifies as a silicon BUG, since UxIER bits cannot assert themselves,
and it is indeed a R/W register.

BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int is asserted ?
I can't find a bitmap on it.

Best regards,
Kris



Hi Bill,

Thanks for the prompt response.
This has actually been my main problem.
It's not my "style" when I develop to just change my SW, and go
"oh, yeah, well it works like that but not like that, so what".
If I write code a particular way, then I expect it to work a particular way,
and if it doesn't - I want to know why !

Anywho, I'm glad I persisted with this.
I had indeed noticed that I didn't have this weird problems either when I
used
Gloabl enable/disable on IRQ. Bah,what a pain.

I'll use your workaround, it sounds plausible.
I can't believe that this problem didn't show up when just printing away
with printf(), but ONLY when running the BASIC interpreter, and with a
specific
program running !

Do you think I should maintain a Default_IRQ handler (I don't plan to use
non-vectored
INTs), case this happens again ?

I'm naturally concerned that if I write to ViCVectAddr at end of Default_IRQ
handler,
that I'll miss actual INTs, as opposed to spurious INTs.

Your summary must be dead-on, because I found that different optimisations
would
exhibit the problem or not.

Thanks a lot !
Kris
Bill wrote :

> Kris
> Thanks for spotting this. It's the old spurious interrupt problem.
> The fix is to disable global interrupts around the first read-modify-write
> instruction. Doing the direct write (U0IER = xxx) can still allow the
problem
> to happen. What happens is the interrupt occurs and is recognized while
> the masking instruction is executing but before it has completed. Then
> when the instruction does complete, the interrupt can't find the vector
> so uses the default. So to fix:
>
> Disable global interrupts
> mask interrupt
> Enable global interrupts
>
> do your stuff
> unmask interrupt
>
> NOTE: I don't think this last modification of the mask register needs
> protection. Someone correct me if I am wrong. > Regards
> -Bill Knight
> R O SoftWare >
> On Mon, 23 Feb 2004 02:09:38 +1100, microbit wrote:
>
> Hi all,
>
> This s a hairy one - ARM Gurus, please read this !!!
> (Bill, this will cause a problem in your UART package too, since you
> set VicDefVectAddr to the Reset Vector, and you also use a RMW
> operation on UxIER)
>
> I figured out why I was getting "resets" while UART0 is TXing
> interrupt driven.
> The problem only occurs when I disable the THE interrupt by masking :
>
> U0IER &= ~ 0x02; /* Disable THE */
> ......
> U0IER |= 0x02;
>
> When I disable and then re-enable THE interrupts with a direct write :
>
> U0IER = 0x01; /* Disable THE, leave RDA enabled */
> .....
> U0IER = 0x03; /* Reenable THE */
>
> I didn't get these "resets".
>
> This is the problem :
> -----------------------
>
> I didn't have VicDefVectAddr specified, so it was set to its default
0x00000000
> address. (All IRQs are disabled, except for VIC Channel # 6)
> While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the
THE
> is disabled, BUT the interrupt asserts at the right moment, hence causing
a non-vectored
> assertion.... (which of course vectors to 0x000000, and ultimately results
in a RESET)
> Is this a known problem on the VIC ?
> Is this normal on the VIC ?
>
> I put in a "dummy" function default_IRQ_handler() so I can break on it,
and when it hits
> that function, VicRawIntr reads 0x3008.
> If I merely indicate on a LED when that function is hit, but then return
from interrupt, the
> execution happpily picks up after the U0IER &=~0x02; statement, and things
run as good as gold.
> NO TX interrupts were missed by the looks of it, since the non-vectored
dummy function doesn't
> service or alter anything, the pending interrupt must be serviced when THE
is re-emabled.
>
> Are there any ARM gurus here that can shed some light on this ?
> I've been just about driven to tears over this problem.
> I can't just use a direct write (I have an interrupt on the other UART in
RX, and that operates on
> a CRC function, the RF transmit function needs to operate on the same CRC
function, so I need
> masking of the Interrupt Enables, rather than directly setting/clearing
all INT sources on UxIER)
>
> As far as I'm concerned this classifies as a silicon BUG, since UxIER bits
cannot assert themselves,
> and it is indeed a R/W register.
>
> BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int
is asserted ?
> I can't find a bitmap on it.
>
> Best regards,
> Kris > --
------
> Yahoo! Groups Links
>
> a.. To





Version 2 of the UART, Blinky LED codeis now posted. I went ahead and
protected the code which re-enables the uart interrupt in addition to
when it is disabled. While the demo code does not have a preemptive
OS, if it did, it would be possible (not probable) for another process
to sneak in during the execution of the RMW sequence and modify the
mask. The protection closes that possibility.

As a side note. The disabling and restoring of the global interrupt
flag in the cpsr can has a similar problem. It has to do with the
processor actually having multiple psr's and preemptive processes
doing the same thing to it while the main line code thinks it is
either enabling or disabling the current IRQ bit. However, without
preemptive processes or ISR's which muck with the interrupt flag bits,
I don't believe there is a problem. For more info on this, Atmel has
an APP note discribing it on their web site in the AT91 ARM7 section.

Regards
-Bill Knight
R O SoftWare



I don't think using the default handler to mask the problem is
the answer. You might however, use it to inform the user &/or
yourself of an internal error so it can be corrected in the
next release of your code.

-Bill
On Mon, 23 Feb 2004 03:04:05 +1100, microbit wrote:

Hi Bill,

Thanks for the prompt response.
This has actually been my main problem.
It's not my "style" when I develop to just change my SW, and go
"oh, yeah, well it works like that but not like that, so what".
If I write code a particular way, then I expect it to work a particular way,
and if it doesn't - I want to know why !

Anywho, I'm glad I persisted with this.
I had indeed noticed that I didn't have this weird problems either when I
used
Gloabl enable/disable on IRQ. Bah,what a pain.

I'll use your workaround, it sounds plausible.
I can't believe that this problem didn't show up when just printing away
with printf(), but ONLY when running the BASIC interpreter, and with a
specific
program running !

Do you think I should maintain a Default_IRQ handler (I don't plan to use
non-vectored
INTs), case this happens again ?

I'm naturally concerned that if I write to ViCVectAddr at end of Default_IRQ
handler,
that I'll miss actual INTs, as opposed to spurious INTs.

Your summary must be dead-on, because I found that different optimisations
would
exhibit the problem or not.

Thanks a lot !
Kris
Bill wrote :

> Kris
> Thanks for spotting this. It's the old spurious interrupt problem.
> The fix is to disable global interrupts around the first read-modify-write
> instruction. Doing the direct write (U0IER = xxx) can still allow the
problem
> to happen. What happens is the interrupt occurs and is recognized while
> the masking instruction is executing but before it has completed. Then
> when the instruction does complete, the interrupt can't find the vector
> so uses the default. So to fix:

> Disable global interrupts
> mask interrupt
> Enable global interrupts

> do your stuff
> unmask interrupt

> NOTE: I don't think this last modification of the mask register needs
> protection. Someone correct me if I am wrong.


> Regards
> -Bill Knight
> R O SoftWare
> On Mon, 23 Feb 2004 02:09:38 +1100, microbit wrote:

> Hi all,

> This s a hairy one - ARM Gurus, please read this !!!
> (Bill, this will cause a problem in your UART package too, since you
> set VicDefVectAddr to the Reset Vector, and you also use a RMW
> operation on UxIER)

> I figured out why I was getting "resets" while UART0 is TXing
> interrupt driven.
> The problem only occurs when I disable the THE interrupt by masking :

> U0IER &= ~ 0x02; /* Disable THE */
> ......
> U0IER |= 0x02;

> When I disable and then re-enable THE interrupts with a direct write :

> U0IER = 0x01; /* Disable THE, leave RDA enabled */
> .....
> U0IER = 0x03; /* Reenable THE */

> I didn't get these "resets".

> This is the problem :
> -----------------------

> I didn't have VicDefVectAddr specified, so it was set to its default
0x00000000
> address. (All IRQs are disabled, except for VIC Channel # 6)
> While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the
THE
> is disabled, BUT the interrupt asserts at the right moment, hence causing
a non-vectored
> assertion.... (which of course vectors to 0x000000, and ultimately results
in a RESET)
> Is this a known problem on the VIC ?
> Is this normal on the VIC ?

> I put in a "dummy" function default_IRQ_handler() so I can break on it,
and when it hits
> that function, VicRawIntr reads 0x3008.
> If I merely indicate on a LED when that function is hit, but then return
from interrupt, the
> execution happpily picks up after the U0IER &=~0x02; statement, and things
run as good as gold.
> NO TX interrupts were missed by the looks of it, since the non-vectored
dummy function doesn't
> service or alter anything, the pending interrupt must be serviced when THE
is re-emabled.

> Are there any ARM gurus here that can shed some light on this ?
> I've been just about driven to tears over this problem.
> I can't just use a direct write (I have an interrupt on the other UART in
RX, and that operates on
> a CRC function, the RF transmit function needs to operate on the same CRC
function, so I need
> masking of the Interrupt Enables, rather than directly setting/clearing
all INT sources on UxIER)

> As far as I'm concerned this classifies as a silicon BUG, since UxIER bits
cannot assert themselves,
> and it is indeed a R/W register.

> BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int
is asserted ?
> I can't find a bitmap on it.

> Best regards,
> Kris


>


> --
------
> Yahoo! Groups Links

> a.. To
Yahoo! Groups Links


Bill Knight wrote:

> Kris
> Thanks for spotting this. It's the old spurious interrupt problem.
> The fix is to disable global interrupts around the first read-modify-write
> instruction. Doing the direct write (U0IER = xxx) can still allow the
> problem
> to happen. What happens is the interrupt occurs and is recognized while
> the masking instruction is executing but before it has completed. Then
> when the instruction does complete, the interrupt can't find the vector
> so uses the default. So to fix:
>
[snip]

Why should the direct write cause this problem? The issue with
read-modify-write makes perfect sense, but the write should be an atomic
operation. How would you get an interrupt between <nothing> and the write?

--jc