# LPC2131 problem reading IO pins

I need to read a value from a DIP switch. It is connected to ports P1.16 till P1.21. I use following code:

to initialize:

#define PORT_ADDRESS                    0x003F0000



int value = (IOPIN1 & PORT_ADDRESS) >> PORT_ADDRESS_OFFSET;


The problem is that no matter what the DIP switch settings are, the value read is always zero. The code worked earlier, but it stopped, and I have no idea why.

-
now it works again! –  Bogi Jul 14 '10 at 13:51
it behaves completely random –  Bogi Jul 14 '10 at 14:02

Function of the pins was not correctly selected. When microcontroller reset, value of P1.20 determines how the pins P1.16 till P1.23 will behave. In my case, when P1.20 was set to zero, it didn't work, and when set to one it worked.

Fix: manually set pin functions using PINSEL2 register:

    PINSEL2 &= ~(0x8);

-
If this solves your problem, you should tick this as the accepted answer. –  Toby Jaffey Jul 14 '10 at 14:37

You didn't mention where IOPIN1 is declared but make sure its declared volatile or the compiler can optimize out reading the value if it doesn't think it has changed leading to intermittent functionality.

If its declared in some vendor supplied header file this is probably already done for you.

-
Yeah, I'd assumed his header files were fine... #define FOO (*(volatile unsigned int *)0x12345678) should be how his register defines should look, or he will have all manner of strangeness, you're absolutely right. –  akohlsmith Jul 20 '10 at 20:56

Your #defines are very confusing. You're not defining a port address at all; you're giving a bitmask for your switch. Also you do not show whether you are putting these port pins in GPIO mode. The default state of PINSEL1 is to have everything in GPIO mode, but you should never make assumptions.

#define SW_MASK 0x3f
#define SW_OFFSET 16

PINSEL1 &= ~(0x00ffffff);
int sw = (IO1PIN >> SW_OFFSET) & SW_MASK;


This is basically the code you have, although with the PINSEL1 code, and arranged to be a little less confusing (to me).

Jobi's right -- you better have a pull-up resistor on P0.20 so that the chip doesn't force these pins into their "trace port" function. See page 70 of the LPC213x user manual.

Take care -- you have put one of the DIP switch switches on P0.20. Either isolate that pin on a reset (a little transistor with an RCD timer on the base which disconnects the switch from P0.20 when you reset the CPU will do the trick), or make sure that you never leave the DIP switch on P0.20 "on" (connected to ground) when resetting. Better yet: just move that switch over to a different I/O and recombine it in code so that your application never knows the difference.

e.g. if you move that switch from P0.20 to P0.22, you can get your "clean" value back thusly:

#define SW_MASK 0x6f
#define SW_OFFSET 16

PINSEL1 &= ~(0x03ffffff);

int sw;
sw = (IO1PIN >> SW_OFFSET) & SW_MASK;
if(sw & (1 << 6)) sw |= (1 << 4);
sw &= ~(1 << 6);


(there are slicker ways to do this, but I'm trying to show you what's going on, not be slick.)

I've altered the mask so that you don't read in P0.20 (SW_MASK change), and that you set P0.22 to GPIO as well (PINSEL1 change). The block that calculates 'sw' will set bit 4 if bit 6 is set (this is P0.20 which was moved to P0.22). It will then "clear out" bit 6, which is now in bit 4's position. The value of your switch will thus be correct.

(most embedded systems don't care for actual bit positions, but you may, which is why I suggested this.)

-