EmbeddedRelated.com
Forums

FIO and interrupt disabling

Started by brian_myers888 November 11, 2008
Hello all -

I have a short function which checks the state of a GPIO pin, and
returns TRUE or FALSE. Simple stuff. However, I was seeing this
function sometimes return TRUE, when I expected it to never do so
(TRUE is intended to indicate presence of a battery charger, and I
don't have one connected). I'm not able to view the pin on a scope
because of the nature of the pullup resistor (I'm not the hardware
guy, so I'm taking his word for it).

The odd thing is, if I disable interrupts around checking of the pin,
I don't see the unexpected behaviour. I'm using Rowley Crossworks, and
the processor is the LPC2136.

Here's the function, with the interrupt disable/enable commented out
(un-commenting those two lines appears to fix the problem) :

//////////////////////////////////////////////////////////////////
#define PIN_MASK 0x40000000 // P0_30 mask. Active-low.

bool chargerConnected( void )
{
bool retVal;
//int interrupt_state_holder = ctl_global_interrupts_disable();

FIO0MASK = ~PIN_MASK;
if ( FIO0PIN & PIN_MASK )
{
retVal = FALSE;
}
else
{
retVal = TRUE;
}
FIO0MASK = ~0;

//ctl_global_interrupts_set( interrupt_state_holder );
return retVal;
}
//////////////////////////////////////////////////////////////////

If I set a breakpoint on the "retVal = TRUE;" line, and then examine
registers, I see FIO0MASK is all F's, and FIO0PIN is zero.

All this leads me to believe that what's happening is that some
interrupt is occuring just after I set up FIO0MASK, and upon return
from the ISR, FIO0MASK is all F's again (fubar-ing my check of FIO0PIN).

So, I'm guessing that ISR's do not preserve FIO0MASK. Therefore,
either I need to protect every similar access involving FIOxMASK, or
else ensure that no ISR modifies it without restoring it.

Is this correct? I didn't think I needed to bracket simple pin-checks
with interrupt-disabling, but maybe I do - or maybe I need to be more
careful with what happens in ISRs. Or am I missing something obvious?

Thanks in advance,
Brian

An Engineer's Guide to the LPC2100 Series

On Mon, 10 Nov 2008 22:21:26 -0000, you wrote:

>Hello all -
>
>I have a short function which checks the state of a GPIO pin, and
>returns TRUE or FALSE. Simple stuff. However, I was seeing this
>function sometimes return TRUE, when I expected it to never do so
>(TRUE is intended to indicate presence of a battery charger, and I
>don't have one connected). I'm not able to view the pin on a scope
>because of the nature of the pullup resistor (I'm not the hardware
>guy, so I'm taking his word for it).
>
>The odd thing is, if I disable interrupts around checking of the pin,
>I don't see the unexpected behaviour. I'm using Rowley Crossworks, and
>the processor is the LPC2136.
>
>Here's the function, with the interrupt disable/enable commented out
>(un-commenting those two lines appears to fix the problem) :
>
>//////////////////////////////////////////////////////////////////
>#define PIN_MASK 0x40000000 // P0_30 mask. Active-low.
>
>bool chargerConnected( void )
>{
> bool retVal;
> //int interrupt_state_holder = ctl_global_interrupts_disable();
>
> FIO0MASK = ~PIN_MASK;
> if ( FIO0PIN & PIN_MASK )
> {
> retVal = FALSE;
> }
> else
> {
> retVal = TRUE;
> }
> FIO0MASK = ~0;
>
> //ctl_global_interrupts_set( interrupt_state_holder );
> return retVal;
>}

1) Why are you using the mask register? - there is no need to use FIOMASK when reading pins.
2) using the mask registers in general is a really really bad idea unless you are absolutely certain
that no interrupt will ever want to access FIO, now or in any future version.

> So, I'm guessing that ISR's do not preserve FIO0MASK. Therefore,
> either I need to protect every similar access involving FIOxMASK, or
> else ensure that no ISR modifies it without restoring it.

I would say that an interrupt should preserve any used the FIO masks,
but that's an application architecture decision. Note that you don't
preserve the mask either :)

> Is this correct?

sounds plausible

> I didn't think I needed to bracket simple pin-checks
> with interrupt-disabling, but maybe I do - or maybe I need to be more
> careful with what happens in ISRs.

That depends on what you and the interrupt have agreed.

> Or am I missing something obvious?

You are reading a single pin, so why use the mask at all?

--

Wouter van Ooijen

-- -------
Van Ooijen Technische Informatica: www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: www.voti.nl/hvu
As several people have pointed out, you don't need to use FIO0MASK to
read a pin state.

That being said, the only way FIO0MASK is going to change is if an
interrupt is changing it. But you should know what interrupts are
running in your system, and what resources you're using.

In this case, perhaps FIO0MASK is being changed by an interrupt.
While I would expect a well written interrupt routine to preserve
anything it needs, it's hard to imagine the compiler generated a
non-atomic instruction to write the value of FIO0MASK (maybe that's
not the case in Thumb mode, if you're using that. I don't know
anything about Thumb mode).

You also need to see if you're getting slammed by the MAM bug. I
don't have datasheets handy for the LPC2136, but I know it affected a
number of processors. It may well be the series of instructions
generated aligns perfectly to cause it.

All in all, you need to provide a bit more detail as to what else the
system is doing, what interrupts you have running, and perhaps a
disassembled version of your code below.

--jc

On Mon, Nov 10, 2008 at 5:21 PM, brian_myers888
wrote:
> Hello all -
>
> I have a short function which checks the state of a GPIO pin, and
> returns TRUE or FALSE. Simple stuff. However, I was seeing this
> function sometimes return TRUE, when I expected it to never do so
> (TRUE is intended to indicate presence of a battery charger, and I
> don't have one connected). I'm not able to view the pin on a scope
> because of the nature of the pullup resistor (I'm not the hardware
> guy, so I'm taking his word for it).
>
> The odd thing is, if I disable interrupts around checking of the pin,
> I don't see the unexpected behaviour. I'm using Rowley Crossworks, and
> the processor is the LPC2136.
>
> Here's the function, with the interrupt disable/enable commented out
> (un-commenting those two lines appears to fix the problem) :
>
> //////////////////////////////////////////////////////////////////
> #define PIN_MASK 0x40000000 // P0_30 mask. Active-low.
>
> bool chargerConnected( void )
> {
> bool retVal;
> //int interrupt_state_holder = ctl_global_interrupts_disable();
>
> FIO0MASK = ~PIN_MASK;
> if ( FIO0PIN & PIN_MASK )
> {
> retVal = FALSE;
> }
> else
> {
> retVal = TRUE;
> }
> FIO0MASK = ~0;
>
> //ctl_global_interrupts_set( interrupt_state_holder );
> return retVal;
> }
> //////////////////////////////////////////////////////////////////
>
> If I set a breakpoint on the "retVal = TRUE;" line, and then examine
> registers, I see FIO0MASK is all F's, and FIO0PIN is zero.
>
> All this leads me to believe that what's happening is that some
> interrupt is occuring just after I set up FIO0MASK, and upon return
> from the ISR, FIO0MASK is all F's again (fubar-ing my check of FIO0PIN).
>
> So, I'm guessing that ISR's do not preserve FIO0MASK. Therefore,
> either I need to protect every similar access involving FIOxMASK, or
> else ensure that no ISR modifies it without restoring it.
>
> Is this correct? I didn't think I needed to bracket simple pin-checks
> with interrupt-disabling, but maybe I do - or maybe I need to be more
> careful with what happens in ISRs. Or am I missing something obvious?
>
> Thanks in advance,
> Brian

Hi

You could also use SWI to set/read io pins in one atomic operation.

----- Original Message -----
From: J.C. Wren
To: l...
Sent: Tuesday, November 11, 2008 1:36 PM
Subject: Re: [lpc2000] FIO and interrupt disabling
As several people have pointed out, you don't need to use FIO0MASK to
read a pin state.

That being said, the only way FIO0MASK is going to change is if an
interrupt is changing it. But you should know what interrupts are
running in your system, and what resources you're using.

In this case, perhaps FIO0MASK is being changed by an interrupt.
While I would expect a well written interrupt routine to preserve
anything it needs, it's hard to imagine the compiler generated a
non-atomic instruction to write the value of FIO0MASK (maybe that's
not the case in Thumb mode, if you're using that. I don't know
anything about Thumb mode).

You also need to see if you're getting slammed by the MAM bug. I
don't have datasheets handy for the LPC2136, but I know it affected a
number of processors. It may well be the series of instructions
generated aligns perfectly to cause it.

All in all, you need to provide a bit more detail as to what else the
system is doing, what interrupts you have running, and perhaps a
disassembled version of your code below.

--jc

On Mon, Nov 10, 2008 at 5:21 PM, brian_myers888
wrote:
> Hello all -
>
> I have a short function which checks the state of a GPIO pin, and
> returns TRUE or FALSE. Simple stuff. However, I was seeing this
> function sometimes return TRUE, when I expected it to never do so
> (TRUE is intended to indicate presence of a battery charger, and I
> don't have one connected). I'm not able to view the pin on a scope
> because of the nature of the pullup resistor (I'm not the hardware
> guy, so I'm taking his word for it).
>
> The odd thing is, if I disable interrupts around checking of the pin,
> I don't see the unexpected behaviour. I'm using Rowley Crossworks, and
> the processor is the LPC2136.
>
> Here's the function, with the interrupt disable/enable commented out
> (un-commenting those two lines appears to fix the problem) :
>
> //////////////////////////////////////////////////////////////////
> #define PIN_MASK 0x40000000 // P0_30 mask. Active-low.
>
> bool chargerConnected( void )
> {
> bool retVal;
> //int interrupt_state_holder = ctl_global_interrupts_disable();
>
> FIO0MASK = ~PIN_MASK;
> if ( FIO0PIN & PIN_MASK )
> {
> retVal = FALSE;
> }
> else
> {
> retVal = TRUE;
> }
> FIO0MASK = ~0;
>
> //ctl_global_interrupts_set( interrupt_state_holder );
> return retVal;
> }
> //////////////////////////////////////////////////////////////////
>
> If I set a breakpoint on the "retVal = TRUE;" line, and then examine
> registers, I see FIO0MASK is all F's, and FIO0PIN is zero.
>
> All this leads me to believe that what's happening is that some
> interrupt is occuring just after I set up FIO0MASK, and upon return
> from the ISR, FIO0MASK is all F's again (fubar-ing my check of FIO0PIN).
>
> So, I'm guessing that ISR's do not preserve FIO0MASK. Therefore,
> either I need to protect every similar access involving FIOxMASK, or
> else ensure that no ISR modifies it without restoring it.
>
> Is this correct? I didn't think I needed to bracket simple pin-checks
> with interrupt-disabling, but maybe I do - or maybe I need to be more
> careful with what happens in ISRs. Or am I missing something obvious?
>
> Thanks in advance,
> Brian
>
>


--- In l..., Mike Harrison wrote:

> 1) Why are you using the mask register? - there is no need to use
FIOMASK when reading pins.
We are using two ARM chips, the 2136 and the 2103. Our user manual for
the 2136 (UM10120_1, old, but the latest available from the NXP web
site) appears to be out of date and does not mention FIO at all, so
I've been assuming (yes, I know ;-) that FIO works the same as on the
2103. My 2103 user manual (UM10161_2) has this to say about FIOMASK :

"Fast Mask register for port. Writes, sets,
clears, and reads to port (done via writes
to FIOPIN, FIOSET, and FIOCLR, and
reads of FIOPIN). alter or return Only the
bits enabled by zeroes in this register are
altered or returned."

So I've just assumed reads of FIOPIN require the mask.

Maybe someone can point me to newer documentation?

brian_myers888 wrote:
> --- In l..., Mike Harrison wrote:
>
>> 1) Why are you using the mask register? - there is no need to use
>> FIOMASK when reading pins.
> We are using two ARM chips, the 2136 and the 2103. Our user manual for
> the 2136 (UM10120_1, old, but the latest available from the NXP web
> site) appears to be out of date and does not mention FIO at all, so
> I've been assuming (yes, I know ;-) that FIO works the same as on the
> 2103. My 2103 user manual (UM10161_2) has this to say about FIOMASK :
>
> "Fast Mask register for port. Writes, sets,
> clears, and reads to port (done via writes
> to FIOPIN, FIOSET, and FIOCLR, and
> reads of FIOPIN). alter or return Only the
> bits enabled by zeroes in this register are
> altered or returned."
>
> So I've just assumed reads of FIOPIN require the mask.
>
> Maybe someone can point me to newer documentation?

IIRC, the mask is cleared upon reset. This puts it into the proper state so
that writes to FIOSET/FIOCLR and reads of FIOPIN transfer all the bits. You
don't need to keep messing with it. :-) The mask register is for those
really rare times that you might want the hardware to filter out bits that
you don't care about for maximum speed. Chances are that setting bits in
the mask is likely to lead to problems for you unless you do it everywhere
you access the port. This means if you have an ISR that reads or writes the
port, it needs to save the current mask and then restore it before exit.
--- In l..., "J.C. Wren" wrote:
>
> As several people have pointed out, you don't need to use FIO0MASK to
> read a pin state.
>
> That being said, the only way FIO0MASK is going to change is if an
> interrupt is changing it. But you should know what interrupts are
> running in your system, and what resources you're using.

Indeed I do, and I'm pretty sure that my SPI driver's ISR would be the
one changing FIOMASK on me (manual bit-banging of SPI slave select
line, most likely). However, if it's really true FIOMASK is irrelevant
to reading FIOPIN, then my guess at what's going wrong must be
incorrect, and I'm as puzzled as ever :-)

Disabling interrupts definitely fixes it though, so that's a powerful
clue.

>
> In this case, perhaps FIO0MASK is being changed by an interrupt.
> While I would expect a well written interrupt routine to preserve
> anything it needs, it's hard to imagine the compiler generated a
> non-atomic instruction to write the value of FIO0MASK (maybe that's
> not the case in Thumb mode, if you're using that. I don't know
> anything about Thumb mode).

Not using Thumb mode.
The problem as I described it does not require any non-atomic write to
FIOMASK. It only requires an interrupt (which trashes FIOMASK) to
occur after the main thread writes FIOMASK, and before FIOPIN is read.
However, if what you guys are saying about FIOMASK not being needed
for FIOPIN reads is right, as I said before, something else is happening.

>
> You also need to see if you're getting slammed by the MAM bug. I
> don't have datasheets handy for the LPC2136, but I know it affected a
> number of processors. It may well be the series of instructions
> generated aligns perfectly to cause it.

I'm using MAM mode 1, my errata sheet says MAM mode 2 is buggy, so we
avoid it.

On Tue, 11 Nov 2008 23:42:02 -0000, you wrote:

>--- In l..., "J.C. Wren" wrote:
>>
>> As several people have pointed out, you don't need to use FIO0MASK to
>> read a pin state.
>>
>> That being said, the only way FIO0MASK is going to change is if an
>> interrupt is changing it. But you should know what interrupts are
>> running in your system, and what resources you're using.
>
>Indeed I do, and I'm pretty sure that my SPI driver's ISR would be the
>one changing FIOMASK on me (manual bit-banging of SPI slave select
>line, most likely). However, if it's really true FIOMASK is irrelevant
>to reading FIOPIN, then my guess at what's going wrong must be
>incorrect, and I'm as puzzled as ever :-)

There is no reason to use FIOMASK for bit-banging as you have the FIOSET/CLR registers to twiddle
bits with.

About the only time FIOMASK can be useful is where you want to write simultaneous arbitary 0 and 1
values to a subset of port bits, AND maximum possible speed is essential.
Unless performance is critical, even this is better done with a combination of FIOSET and FIOCLR
operations, as FIOMASK is fraught with the sort of dangers you appear to be experiencing, and its
use should be avoided unless there really is no alternative.

> -----Original Message-----
> From: l...
> [mailto:l...]On Behalf
> Of brian_myers888
> Sent: Tuesday, November 11, 2008 4:42 PM
> To: l...
> Subject: [lpc2000] Re: FIO and interrupt disabling
> --- In l..., "J.C. Wren" wrote:
> >
> > As several people have pointed out, you don't need to use
> FIO0MASK to
> > read a pin state.
> >
> > That being said, the only way FIO0MASK is going to change is if an
> > interrupt is changing it. But you should know what interrupts are
> > running in your system, and what resources you're using.
>
> Indeed I do, and I'm pretty sure that my SPI driver's ISR would be the
> one changing FIOMASK on me (manual bit-banging of SPI slave select
> line, most likely). However, if it's really true FIOMASK is irrelevant
> to reading FIOPIN, then my guess at what's going wrong must be
> incorrect, and I'm as puzzled as ever :-)

FIOMASK is definitely relevant to the reading of FIOPIN, in that it does
affect it. What people are suggesting though, is to NOT use FIOMASK
at all. Write zero to it at startup, and then leave it alone.

Mike