WARNING: problem reading state of external interrupt lines.

Started by brendanmurphy37 December 8, 2005

Hi,

We've just discovered come characteristics of the external interrupt
lines on the LPC213x parts (probably other parts as well, though not
on the newer ones like the LPC214x), which I think is worth sharing
with people here.

Our basic requirement is to have an external signal generate an
interrupt to signal a once-off event. We configured P0.20 as EINT3 to
generate an edge-triggered interrupt on a falling edge. This works
just fine. The problem is that we also want to be able to read the
state of the pin at any time.

The first point to note is that you can't read the state of a pin
when it's configured as an external interrupt: we read it
consistently as 0, even though it is normally held high. This is
indicated in a statement in the User Manual, in the section on the
Pin Connect Block ("Selection of a single function on a port pin
completely excludes all other functions otherwise available on the
same pin"), though we only spotted this after we'd spent a while on
figuring out what was wrong (maybe an additional statement in the
External Interrupt description would help here?).

Anyway, our work around was to temporarily reconfigure the pin as
GPIO, read its value, and reconfigure back as EINT3 whenever we
wanted to read it. This works just fine.

However, it introduced problem number two: depending on the mode of
the interrupt and the state of the pin, the action of changing it to
GPIO and back again can itself generate a (spurious) interrupt. That
is, you can get an interrupt even though there's been no transition
on the actual pin. We then changed the function to do the read, so
that it disabled interrupts, switched the pin to GPIO, read the
value, switched to EINT3, reset the pending interrupt generated and
re-enabled interrupts. Again, this works, if a bit long-winded.

However, on thinking about it, what would happen if a real state
transition happened when all this was going on? My strong suspicion
is that there's potential for a race-condition to exist, even if only
for a short time.

Because of pressure of time, we've had to rethink how we're handling
this, and for now, we're not using interrupts for the function any
more: we now poll the pin, leaving it as a GPIO input. I'm sure there
is some other work around to this issue (it's probably preferable to
use level sensitive interrupts in any case).

My main reason for mentioning this here is to make others aware of
the issue, and hopefully save some time.
Brendan Murphy



An Engineer's Guide to the LPC2100 Series

--- In lpc2000@lpc2..., "brendanmurphy37"
<brendan.murphy@i...> wrote:
>
> We've just discovered come characteristics of the external
> interrupt lines on the LPC213x parts (probably other parts as well,
> though not on the newer ones like the LPC214x), which I think is
> worth sharing with people here.
>
> Our basic requirement is to have an external signal generate an
> interrupt to signal a once-off event. We configured P0.20 as EINT3
> to generate an edge-triggered interrupt on a falling edge. This
> works just fine. The problem is that we also want to be able to
> read the state of the pin at any time.
>
> The first point to note is that you can't read the state of a pin
> when it's configured as an external interrupt: we read it
> consistently as 0, even though it is normally held high. This is
> indicated in a statement in the User Manual, in the section on the
> Pin Connect Block ("Selection of a single function on a port pin
> completely excludes all other functions otherwise available on the
> same pin"), though we only spotted this after we'd spent a while on
> figuring out what was wrong (maybe an additional statement in the
> External Interrupt description would help here?).
>
> Anyway, our work around was to temporarily reconfigure the pin as
> GPIO, read its value, and reconfigure back as EINT3 whenever we
> wanted to read it. This works just fine.
>
> However, it introduced problem number two: depending on the mode of
> the interrupt and the state of the pin, the action of changing it
> to GPIO and back again can itself generate a (spurious) interrupt.
> That is, you can get an interrupt even though there's been no
> transition on the actual pin. We then changed the function to do
> the read, so that it disabled interrupts, switched the pin to GPIO,
> read the value, switched to EINT3, reset the pending interrupt
> generated and re-enabled interrupts. Again, this works, if a bit
> long-winded.
>
> However, on thinking about it, what would happen if a real state
> transition happened when all this was going on? My strong suspicion
> is that there's potential for a race-condition to exist, even if
> only for a short time.
>
> Because of pressure of time, we've had to rethink how we're
> handling this, and for now, we're not using interrupts for the
> function any more: we now poll the pin, leaving it as a GPIO input.
> I'm sure there is some other work around to this issue (it's
> probably preferable to use level sensitive interrupts in any case).

Or route the signal to a GPIO pin in addition to the EINT pin.

Or use a timer capture pin, and let it generate a capture interrupt
on both rising and falling edges of the pin, and keep track of the
pin value in the interrupt handler. (And be aware of the TIMER.1
errata.)

Karl Olsen



Good suggestions.

Routing to a 2nd pin is probably safest. Problem is we're short on
pins and also would prefer not to re-spin the board at this late
stage of our development.

On the 2nd suggetsion, I'd be curious to know if the capture pins
behave the same as the EINT pins (i.e. you can't read their state
when configured as a capture pin). My guess (and it's only a guess)
is that it's likely they would.

Best option is probably to use one of the later devices: aparently on
these the IOPIN register always reflects the actual pin state.

Brendan

--- In lpc2000@lpc2..., "Karl Olsen" <kro@p...> wrote:
>
> --- In lpc2000@lpc2..., "brendanmurphy37"
> <brendan.murphy@i...> wrote:
> >
> > We've just discovered come characteristics of the external
> > interrupt lines on the LPC213x parts (probably other parts as
well,
> > though not on the newer ones like the LPC214x), which I think is
> > worth sharing with people here.
> >
> > Our basic requirement is to have an external signal generate an
> > interrupt to signal a once-off event. We configured P0.20 as
EINT3
> > to generate an edge-triggered interrupt on a falling edge. This
> > works just fine. The problem is that we also want to be able to
> > read the state of the pin at any time.
> >
> > The first point to note is that you can't read the state of a pin
> > when it's configured as an external interrupt: we read it
> > consistently as 0, even though it is normally held high. This is
> > indicated in a statement in the User Manual, in the section on
the
> > Pin Connect Block ("Selection of a single function on a port pin
> > completely excludes all other functions otherwise available on
the
> > same pin"), though we only spotted this after we'd spent a while
on
> > figuring out what was wrong (maybe an additional statement in the
> > External Interrupt description would help here?).
> >
> > Anyway, our work around was to temporarily reconfigure the pin as
> > GPIO, read its value, and reconfigure back as EINT3 whenever we
> > wanted to read it. This works just fine.
> >
> > However, it introduced problem number two: depending on the mode
of
> > the interrupt and the state of the pin, the action of changing it
> > to GPIO and back again can itself generate a (spurious)
interrupt.
> > That is, you can get an interrupt even though there's been no
> > transition on the actual pin. We then changed the function to do
> > the read, so that it disabled interrupts, switched the pin to
GPIO,
> > read the value, switched to EINT3, reset the pending interrupt
> > generated and re-enabled interrupts. Again, this works, if a bit
> > long-winded.
> >
> > However, on thinking about it, what would happen if a real state
> > transition happened when all this was going on? My strong
suspicion
> > is that there's potential for a race-condition to exist, even if
> > only for a short time.
> >
> > Because of pressure of time, we've had to rethink how we're
> > handling this, and for now, we're not using interrupts for the
> > function any more: we now poll the pin, leaving it as a GPIO
input.
> > I'm sure there is some other work around to this issue (it's
> > probably preferable to use level sensitive interrupts in any
case).
>
> Or route the signal to a GPIO pin in addition to the EINT pin.
>
> Or use a timer capture pin, and let it generate a capture interrupt
> on both rising and falling edges of the pin, and keep track of the
> pin value in the interrupt handler. (And be aware of the TIMER.1
> errata.)
>
> Karl Olsen
>




Hello Brendan Murphy,

On our LPC2138-based design, we noticed too that you cannot use a pin
as EINT and GPIO at the same time, and we used the same work-around:
reconfigure the pin to GPIO after detecting the interrupt.

So far, only one board (out of approximately 20) gave the "spurious
interrupt" that you described, and on this board, the spurious
interrupt goes away when we bend the board (very) slightly. Our
hypothesis was that there is a problem in the PCB, and that perhaps
some ground or power wire is floating.

In your message, you mention that the spurious interrupt occurs
"depending on the mode of the interrupt and the state of the pin". I
am interested in the conditions that the interrupt does and does not
appear.

If your hypothesis (that this spurious interrupt is a feature/property
of the LPC2000 series) is correct, then I will have to consider
implementing a work-around in the firmware. But if our hypothesis
(that this is due to a broken PCB or a design error in the PCB) is
correct, you may want to review your PCB.

Kind regards,
Thiadmer Riemersma




Thiadmer,

Thanks for the suggestion. However, we've determined that it's
definitely a "feature" of the LPC213x. The reason I phrased it as I
did was that we didn't investigate all possible variations. However,
the following definitely produces a "spurious" interrupt:

- place a high value on the P0.20 pin (and don't change it)
- configure EINT3 on P0.20 to generate an interrupt on a rising edge
- change the pin from EINT3 to GPIO
- read the pin value
- change it back to EINT3
- result: unexpected interrupt

There are many possible work-arounds for this: a simple and obvious
one is just to take the interrupt (knowing it's spurious).

The points I was warning against are that:

- you can't read a pin value on the LPC213x without changing it to
GPIO

- it can give an unexpected interrupt (unexpected in this case as no
rising edge has happened on the pin and yet you get an interrupt)

As I said, we haven't investigated all possible combinations (e.g.
rising/falling edge; edge/level; high/low value on i/p pin). There
may or may not be other combinations where you see this.

It sounds like you have a separate problem with your PCB.

Regards
Brendan

--- In lpc2000@lpc2..., "Thiadmer Riemersma (ITB
CompuPhase)" <go@c...> wrote:
>
> Hello Brendan Murphy,
>
> On our LPC2138-based design, we noticed too that you cannot use a
pin
> as EINT and GPIO at the same time, and we used the same work-
around:
> reconfigure the pin to GPIO after detecting the interrupt.
>
> So far, only one board (out of approximately 20) gave the "spurious
> interrupt" that you described, and on this board, the spurious
> interrupt goes away when we bend the board (very) slightly. Our
> hypothesis was that there is a problem in the PCB, and that perhaps
> some ground or power wire is floating.
>
> In your message, you mention that the spurious interrupt occurs
> "depending on the mode of the interrupt and the state of the pin".
I
> am interested in the conditions that the interrupt does and does
not
> appear.
>
> If your hypothesis (that this spurious interrupt is a
feature/property
> of the LPC2000 series) is correct, then I will have to consider
> implementing a work-around in the firmware. But if our hypothesis
> (that this is due to a broken PCB or a design error in the PCB) is
> correct, you may want to review your PCB.
>
> Kind regards,
> Thiadmer Riemersma
>




Hello Brendan,

> It sounds like you have a separate problem with your PCB.

We DO have a problem with one particular board (we have tested only 20
so far, but this fault is only present on one of these).

However, we doubt that this is an unrelated problem. To explain it, I
need a little detour.

In normal operation, the board gets an interrupt every 25 ms
(roughly). This is an interrupt on the rising flank of a "data
request" line of an external chip. On an interrupt, the ISR toggles an
semaphore so that a high priority task will run. This high priority
task must push data over a serial link until the external chip drops
the data request line.

There is no way of knowing beforehand how many bytes to push,
monitoring the data request line is the only option. Which is why the
task toggles the pin from EINT0 to GPIO. When it is done pushing the
data, it toggles it back.

What we experienced on the one faulthy board were watchdog resets. We
traced this back to the high priority task running continously (the
watchdog is "tickled" by a lower priority task). We traced that back
to the ISR getting a flank interrupt even though the data request line
was low. This was our spurious interrupt. Our hypothesis is that
toggling GPIO to EINT0 caused this interrupt.

So your forum message rang a bell.

That said,...

1) such a failure could hardly be missed on the other 19 boards that
we tested: watchdog resets are quite noticible;

2) when we exerted pressure on the board (bending the PCB slightly)
the board functioned normally: the spurious interrupts went away (and
no other disfunctionality was detected).

We will still keep an eye on this "spurious interrupt" issue. For
instance, I am implementing a test in the firmware that checks
specifically for this issue. But for the moment, we are unconvinced
that spurious interrupts (under these conditions) are "by design" for
the LPC2000 series.

Kind regards,
Thiadmer