Reply by brian_myers888 November 11, 20082008-11-11
Thanks to all for your input.

The issue is resolved - I chopped out the masking and un-masking
everywhere GPIO pins were set, cleared or checked, and removed the
accompanying interrupt disable/enable code - much nicer. Mask
registers are now set up once at startup and not touched again. Thanks
all for the advice.

I'll get a small speedup, and code size reduction in the deal too :-)

An Engineer's Guide to the LPC2100 Series

Reply by Mike Harrison November 11, 20082008-11-11
On Wed, 12 Nov 2008 00:19:08 -0000, you wrote:

>--- In l..., Mike Harrison wrote:
>
>>
>> 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.
>>Yes, I understand what you're saying - but, just to be clear, you're
>talking about writing FIOPIN in conjunction with FIOMASK (as opposed
>to FIOSET and FIOCLR).

Yes - if you really need to write the 1's and 0's simultaneously then you'd set up FIOMASK and write
to FIOPIN, otherwise in most cases it would be better to use FIOSET and FIOCLR.

Reply by brian_myers888 November 11, 20082008-11-11
--- In l..., Mike Harrison wrote:

>
> 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.
>

Yes, I understand what you're saying - but, just to be clear, you're
talking about writing FIOPIN in conjunction with FIOMASK (as opposed
to FIOSET and FIOCLR). Because as you say, you can't simultaneously
set and clear different pins at the exact same time without using
FIOPIN. I don't have any requirement to do that.

Reply by Michael Anton November 11, 20082008-11-11
> -----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
Reply by Mike Harrison November 11, 20082008-11-11
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.

Reply by brian_myers888 November 11, 20082008-11-11
--- 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.

Reply by michael brown November 11, 20082008-11-11
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.
Reply by brian_myers888 November 11, 20082008-11-11
--- 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?

Reply by Sagaert Johan November 11, 20082008-11-11
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
>
>


Reply by "J.C. Wren" November 11, 20082008-11-11
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