Forum rules
Talk about Adafruit Raspberry Pi® accessories! Please do not ask for Linux support, this is for Adafruit products only! For Raspberry Pi help please visit: http://www.raspberrypi.org/phpBB3/

MCP230XX library problem

by stefanet on Mon Feb 25, 2013 5:27 pm

Hi guys,

i have a problem with adafruit_mcp230xx python libraries from github.

My code is

Code: Select all
try:
    from Adafruit_MCP230xx import Adafruit_MCP230XX
    import sys, time
    """
    The MCP23017 has 16 pins - A0 thru A7 + B0 thru B7. A0 is called 0 in the library, and A7 is called 7, then B0 continues from there as is called 8 and finally B7 is pin 15

    """

    # Base variable settings
    OUTPUT = 0
    INPUT = 1
    DISABLE = 0
    ENABLE = 1

    sensor = 8 # GPB0
    door = 9 # GPB1
    door_led = 11 # GPB3

    mcp = Adafruit_MCP230XX( busnum = 1, address = 0x20, num_gpios = 16 )

    # GPIO MCP230xx OUTPUT settings
    mcp.config( door_led, OUTPUT)

    # GPIO MCP230xx Input settings with Pull-UP resistor
    mcp.pullup( sensor, 1 )
    mcp.pullup( door, 1 )

    while ( True ):
        # Pir Sensor
        if not mcp.input( sensor ):
            print "Sensor:" + str( mcp.input( sensor ) )

        # Magnetic Door switch
        if not mcp.input( door ):
            print "Door:" + str( mcp.input( door ) )
            mcp.output( door_led, ENABLE )

        time.sleep(0.3)
except KeyboardInterrupt:
    sys.exit(127)


When i run it I have the following error:

Code: Select all
Traceback (most recent call last):
  File "switch.py", line 31, in <module>
    if not mcp.input( sensor ):
  File "/root/Adafruit_MCP230xx.py", line 118, in input
    assert self.direction & (1 << pin) != 0, "Pin %s not set to input" % pin
AssertionError: Pin 8 not set to input


If I comment out the mcp output settings, it works fine.
Why? Where is my error?
It seems to loose the input settings. I'm confused.

Following another code correctly runned
Code: Select all
# -*- coding: iso-8859-15 -*-
try:
    from Adafruit_MCP230xx import Adafruit_MCP230XX
    import re, sys, time
    """
    The MCP23017 has 16 pins - A0 thru A7 + B0 thru B7. A0 is called 0 in the library, and A7 is called 7, then B0 continues from there as is called 8 and finally B7 is pin 15

    mapping
    pin1 = col2 = gpio7 => col[1] = 7
    pin3 = col1 = gpio5 => col[0] = 5
    pin5 = col3 = gpio3 => col[2] = 3
    pin2 = raw1 = gpio6 => raw[0] = 6
    pin4 = raw4 = gpio4 => raw[3] = 4
    pin6 = raw3 = gpio2 => raw[2] = 2
    pin7 = raw2 = gpio1 => raw[1] = 1

    """

    # Base variable settings
    OUTPUT = 0
    INPUT = 1
    code = ""

    # keypad array settings
    raw = [ 6, 1, 2, 4 ]
    col = [ 5, 7, 3 ]
    keypad = [ [ '1', '2', '3' ] , [ '4', '5', '6' ], [ '7', '8', '9' ], [ '*', '0', '#' ] ]

    mcp = Adafruit_MCP230XX( busnum = 1, address = 0x20, num_gpios = 16 )
    # GPIO MCP230xx OUTPUT settings
    for gp_out in col:
        mcp.config( gp_out, OUTPUT)

    # GPIO MCP230xx Input settings with Pull-UP resistor
    for gp_in in raw:
        mcp.pullup( gp_in, 1 )

    while ( True ):
        # Base column settings
        for gp_out in col:
            mcp.output( gp_out, 1) #
        # Column scans
        for col_sel in col:
            # set column to 0 value
            mcp.output(col_sel, 0)

            # Raw scans
            for raw_sel in raw:
                if mcp.input(raw_sel) == 0: # Key pressed
                    value = keypad [ raw.index(raw_sel)][ col.index(col_sel) ] # get key value
                    code += value # building code
                    #print "|" + code + "| - " + str(raw.index(raw_sel)) + ":" + str(col.index(col_sel))

                    if re.search( '^(\d|#)', code ): # If not start with '*' reset code variable: code must start with '*'
                        code = ""
                    if re.search( '(\*(\d+)#)', code ): # Ok code between '*' and '#'
                        print re.match( '.*(\*(\d+)#)', code ).group(2)
                        code = ""

                    while mcp.input(raw_sel) == 0: # wait until key released
                        time.sleep(0.1)

        time.sleep(0.1)

except KeyboardInterrupt:
    sys.exit(127)


Why?

Regards,
Stefano
stefanet
 
Posts: 6
Joined: Mon Feb 25, 2013 4:37 pm

Re: MCP230XX library problem

by tldr on Mon Feb 25, 2013 10:02 pm

i would guess that you were previously using pin 8 as an output. if the mcp23017 has not been powered down it will remember that. either get in the habit of explicitly setting your inputs to input or modify your copy of the library so that the mcp230xx constructor clears the data direction registers.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: MCP230XX library problem

by stefanet on Tue Feb 26, 2013 1:18 am

But I never set pin 8 to OUTPUT as you can see...

It's the same if I change the output pin ^_^
stefanet
 
Posts: 6
Joined: Mon Feb 25, 2013 4:37 pm

Re: MCP230XX library problem

by tldr on Tue Feb 26, 2013 2:53 pm

actually, i can't see. i have no idea what code you were running day before yesterday. if you haven't turned off the power the mcp23017 will remember its state. have you tried explicitly setting the input to input? this would be good programming practice.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: MCP230XX library problem

by stefanet on Wed Feb 27, 2013 2:50 am

Yes, i turned off the power and I never set OUTPUT for this pin. So I don't known how it can remember this.

Yes, I set initial state to INPUT by mcp.pullup( pin ).

I don't understand. :cry:

Regard,

Stefano
stefanet
 
Posts: 6
Joined: Mon Feb 25, 2013 4:37 pm

Re: MCP230XX library problem

by tldr on Wed Feb 27, 2013 7:49 am

mcp.pullup sets the pullup for the pin, it does not set the pin to input. you need a call to mcp.config to do that, although it's true that the startup state for the pins is supposed to be input.

you could try reading the control registers on the mcp23017 to see what's going on.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: MCP230XX library problem

by stefanet on Wed Feb 27, 2013 8:25 am

Yes, I'll try it as possible.

I follow an adafruit guide:

http://learn.adafruit.com/mcp230xx-gpio-expander-on-the-raspberry-pi/using-the-library

It shows thant pullup function set pin to input mode.
stefanet
 
Posts: 6
Joined: Mon Feb 25, 2013 4:37 pm

Re: MCP230XX library problem

by tldr on Wed Feb 27, 2013 4:36 pm

ah, but i read the datasheet. setting the pullup has no effect on the data direction register. as near as i can tell the adafruit library does not set the data direction pin when the pullup is enabled.

it is true, however, that the power up state of the data direction register is all pins set to input, but i don't understand why people do not want to bother with something as simple as

Code: Select all
    mcp.config( 8, INPUT)


it's just good practice to not make assumptions about the state of the registers. it also makes your code somewhat self documenting.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: MCP230XX library problem

by tldr on Wed Feb 27, 2013 7:09 pm

damn. i've been soooooo wrong. the adafruit library does initialize all of the gpios to inputs.

i didn't notice when i looked at the code. i didn't notice as i was adding a dump function to the mcp230xx class.

but when i ran my new dump function, sure enough, everything started out as inputs even though i had left some pins set as outputs. so i looked at the library, again. boy, do i feel stupid.

i was right, however, that enabling pullups has nothing to do with setting a pin as input. it would be an input even if you didn't enable the pullup.

here's the function i added to the Adafruit_MCP230xx class...

Code: Select all
    def dump (self) :
       if self.num_gpios == 8 :
          return {'IODIRA' : self.i2c.readU8 (0),
                  'IPOLA' : self.i2c.readU8 (1),
                  'GPINTENA' : self.i2c.readU8 (2),
                  'GPPUA' : self.i2c.readU8 (6),
                  'GPIOA' : self.i2c.readU8 (9),
                  'GPOLATA' : self.i2c.readU8 (10)}
       else :
          iocon = self.i2c.readU8 (10)
          return {'IODIRA' : self.i2c.readU8 (0),
                  'IPOLA' : self.i2c.readU8 (2),
                  'INTENA' : self.i2c.readU8 (4),
                  'DEFVALA' : self.i2c.readU8 (6),
                  'INTCONA' : self.i2c.readU8 (8),
                  'IOCON' : {'bank' : iocon >> 7 & 1, 'mirror' : iocon >> 6 & 1,
                             'seqop' : iocon >> 5 & 1, 'disslw' : iocon >> 4 & 1,
                             'haen' : iocon >> 3 & 1, 'odr' : iocon >> 2 & 1,
                             'intpol' : iocon >> 1 & 1},
                  'PUA' : self.i2c.readU8 (12),
                  'INTFA' : self.i2c.readU8 (14),
                  'INTCAPA' : self.i2c.readU8 (16),
                  'GPIOA' : self.i2c.readU8 (18),
                  'OLATA' : self.i2c.readU8 (20),
                  'IODIRB' : self.i2c.readU8 (1),
                  'IPOLB' : self.i2c.readU8 (3),
                  'INTENB' : self.i2c.readU8 (5),
                  'DEFVALB' : self.i2c.readU8 (7),
                  'INTCONB' : self.i2c.readU8 (9),
                  'IOCON2' : self.i2c.readU8 (11),
                  'PUB' : self.i2c.readU8 (13),
                  'INTFB' : self.i2c.readU8 (15),
                  'INTCAPB' : self.i2c.readU8 (17),
                  'GPIOB' : self.i2c.readU8 (19),
                  'OLATB' : self.i2c.readU8 (21)}


here's what i stuck at the end of the file to test my new function...

Code: Select all
    from time import sleep
    mcp = Adafruit_MCP230XX(address = 0x20, num_gpios = 16, busnum = 1)
    print "mcp230017 initialized"
    print mcp.dump ()
    mcp.config(0, mcp.OUTPUT)
    mcp.config(1, mcp.OUTPUT)
    mcp.config(2, mcp.OUTPUT)
    mcp.config(7, mcp.INPUT)
    mcp.pullup(3,1)
    print "PORTA 0,1,2 set as output. PORTA 3 set as input with PUP enabled.
    print mcp.dump ()
    while mcp.input(3) :
      pass
    print "Button on PORTA pin 3 pressed.
    print mcp.dump ()
    for i in range (5) :
      mcp.output (0, 1)
      sleep (1)
      mcp.output (0, 0)
      sleep (1)


here's the output...

Code: Select all
pi@raspberrypi ~/Adafruit-Raspberry-Pi-Python-Code/Adafruit_MCP230xx $ sudo ./Adafruit_MCP230xx.py           
mcp230017 initialized                                                                                         
{'OLATA': 8, 'INTCAPA': 0, 'INTCAPB': 0, 'IODIRA': 255, 'IODIRB': 255, 'INTCONA': 0, 'INTCONB': 0, 'IOCON2': 0, 'IOB': 0, 'INTENA': 0, 'INTENB': 0, 'OLATB': 0, 'INTFB': 0, 'GPIOA': 8, 'IPOLB': 0, 'IPOLA': 0, 'DEFVALA': 0, 'DEFVALB': 0, 'IOCON': {'haen': 0, 'odr': 0, 'intpol': 0, 'seqop': 0, 'mirror': 0, 'disslw': 0, 'bank': 0}, 'INTFA': 0, 'PUA': 0, 'PUB': 0}                                                           
PORTA 0,1,2 set as output. PORTA 3 set as input with PUP enabled.                                                                                 
{'OLATA': 8, 'INTCAPA': 0, 'INTCAPB': 0, 'IODIRA': 248, 'IODIRB': 255, 'INTCONA': 0, 'INTCONB': 0, 'IOCON2': 0, 'IOB': 0, 'INTENA': 0, 'INTENB': 0, 'OLATB': 0, 'INTFB': 0, 'GPIOA': 8, 'IPOLB': 0, 'IPOLA': 0, 'DEFVALA': 0, 'DEFVALB': 0, 'IOCON': {'haen': 0, 'odr': 0, 'intpol': 0, 'seqop': 0, 'mirror': 0, 'disslw': 0, 'bank': 0}, 'INTFA': 0, 'PUA': 8, 'PUB': 0}                                                                               
Button on PORTA pin 3 pressed.                                                                                                                     
{'OLATA': 8, 'INTCAPA': 0, 'INTCAPB': 0, 'IODIRA': 248, 'IODIRB': 255, 'INTCONA': 0, 'INTCONB': 0, 'IOCON2': 0, 'IOB': 0, 'INTENA': 0, 'INTENB': 0, 'OLATB': 0, 'INTFB': 0, 'GPIOA': 0, 'IPOLB': 0, 'IPOLA': 0, 'DEFVALA': 0, 'DEFVALB': 0, 'IOCON': {'haen': 0, 'odr': 0, 'intpol': 0, 'seqop': 0, 'mirror': 0, 'disslw': 0, 'bank': 0}, 'INTFA': 0, 'PUA': 8, 'PUB': 0}


perhaps you'll find it helpful. sorry about my idiotic blathering.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: MCP230XX library problem

by stefanet on Thu Feb 28, 2013 6:10 pm

Well, i done some tests.

The Adafruit_MCP230XX library seems to be wrong in line 118. This line checks the direction.
If pin direction return 1 it's configured to INPUT else to OUTPUT. This check is inverted

I changed
Code: Select all
assert self.direction & (1 << pin) != 0, "Pin %s not set to input" % pin


to
Code: Select all
assert self.direction & (1 << pin) != 1, "Pin %s not set to input" % pin


and now it runs.

My "final" code is
Code: Select all
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
try:
    from Adafruit_MCP230xx import Adafruit_MCP230XX
    import sys, time, smbus
    """
    The MCP23017 has 16 pins - A0 thru A7 + B0 thru B7. A0 is called 0 in the library, and A7 is called 7, then B0 continues from there as is called 8 and finally B7 is pin 15

    """

    # Base variable settings
    OUTPUT = 0
    INPUT = 1
    DISABLE = 0
    ENABLE = 1

    sensor = 8 # GPB0
    door = 9 # GPB1
    door_led = 11 # GPB3

    mcp = Adafruit_MCP230XX( busnum = 1, address = 0x20, num_gpios = 16 )

    #print mcp.dump ()

    # MCP230xx GPIO Direction settings
    mcp.config ( sensor, INPUT)
    mcp.config ( door, INPUT)
    mcp.config( door_led, OUTPUT)

    # MCP230xx GPIOPull-UP resistor
    mcp.pullup( sensor, ENABLE )
    mcp.pullup( door, ENABLE )

    #print mcp.dump()

    while ( True ):
        if mcp.input( sensor ):
            print "Sensor:" + str( mcp.input( sensor ) )

        if mcp.input( door ):
            #print "Door:" + str( mcp.input( door ) )
            mcp.output( door_led, ENABLE )
        else:
            mcp.output( door_led, DISABLE )

        time.sleep(0.2)

except KeyboardInterrupt:
    sys.exit(127)


Sensor is PIR sensor and door is magnetic door switch. When I open door a red LED is on and when i close it the LED is off.
stefanet
 
Posts: 6
Joined: Mon Feb 25, 2013 4:37 pm

Re: MCP230XX library problem

by tldr on Thu Feb 28, 2013 10:27 pm

only problem is is that that's not an error. what assert does is say this condition has to be fulfilled and if it's not die horribly and print this message.

i can speak with some authority on this topic because i just looked it up in a book that probably outweighs my brain.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: MCP230XX library problem

by stefanet on Sat Mar 02, 2013 4:49 am

Hi,

The MCP230XX library have many bugs.
I found a patch by bbkiwi on github to solve the problem.

https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/pull/27

Thanks
Stefano
stefanet
 
Posts: 6
Joined: Mon Feb 25, 2013 4:37 pm