rhinotekmn
Posts: 20
Joined: Thu Aug 27, 2015 1:07 pm
Location: Minneapolis, MN, USA

ISO GPIO pins 41-x expander

Thu Apr 12, 2018 9:53 pm

I have done some googling in an attempt to find a GPIO "expander", I am coming up with things like MCP230XX but that seems to be designed for the Pi 1. I am looking for an expander that will give me pins 41 and beyond(in total I need 65 unique [i.e. not a multiplexer] generic I/O pins) for the raspberry pi 2 and beyond (40 pin GPIO style) any products available?

scotty101
Posts: 3774
Joined: Fri Jun 08, 2012 6:03 pm

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 8:52 am

rhinotekmn wrote:
Thu Apr 12, 2018 9:53 pm
I have done some googling in an attempt to find a GPIO "expander", I am coming up with things like MCP230XX but that seems to be designed for the Pi 1. I am looking for an expander that will give me pins 41 and beyond(in total I need 65 unique [i.e. not a multiplexer] generic I/O pins) for the raspberry pi 2 and beyond (40 pin GPIO style) any products available?
The MCP230XX series was certainly not designed specifically for the Pi 1. Whilst many tutorials may use a Pi 1, it will work just as well with any other version of the Pi (and thousands of other microcontrollers/processors).

8 MCP230XX chips can share an I2C bus meaning that with the following parts you can have a large number of GPIO pins
8x MCP23008 = 64 GPIO pins
8x MCP23017 = 128 GPIO pins.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

User avatar
DougieLawson
Posts: 36829
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website Twitter

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 9:08 am

The MCP23017 or MCP23008 is an I2C device that works on every model of RPi (26 pin or 40 pin). You can stack up to eight MCP23017s on a single bus to give you an extra 128 GPIO pins.

https://pinout.xyz/pinout/i2c
Note: Having anything humorous in your signature is completely banned on this forum. Wear a tin-foil hat and you'll get a ban.

Any DMs sent on Twitter will be answered next month.

This is a doctor free zone.

scotty101
Posts: 3774
Joined: Fri Jun 08, 2012 6:03 pm

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 11:09 am

Is there an echo in here? :D
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

User avatar
DougieLawson
Posts: 36829
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website Twitter

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 11:24 am

scotty101 wrote:
Fri Apr 13, 2018 11:09 am
Is there an echo in here? :D
E C H O

Maybe, I didn't see your post when I wrote mine.

echo
Note: Having anything humorous in your signature is completely banned on this forum. Wear a tin-foil hat and you'll get a ban.

Any DMs sent on Twitter will be answered next month.

This is a doctor free zone.

SteveSpencer
Posts: 351
Joined: Thu Mar 28, 2013 9:19 am
Location: Nottingham, UK

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 11:48 am

As an aside, if you use the excellent wiringpi library, this will also let you address those pins using the same mechanism as you do for other pins.
This assumes you use C or C++. Can anyone tell me if there is a python/python3 wrapper for the library that allows the same functionality?

I am slowly coming to terms with learning Python, despite my initial misgivings about using an interpretive language on a (relatively) small system.
Steve S
No, I can't think of anything funny that won't offend someone if they want it to...

rhinotekmn
Posts: 20
Joined: Thu Aug 27, 2015 1:07 pm
Location: Minneapolis, MN, USA

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 4:45 pm

scotty101 wrote:
Fri Apr 13, 2018 8:52 am
rhinotekmn wrote:
Thu Apr 12, 2018 9:53 pm
I have done some googling in an attempt to find a GPIO "expander", I am coming up with things like MCP230XX but that seems to be designed for the Pi 1. I am looking for an expander that will give me pins 41 and beyond(in total I need 65 unique [i.e. not a multiplexer] generic I/O pins) for the raspberry pi 2 and beyond (40 pin GPIO style) any products available?
The MCP230XX series was certainly not designed specifically for the Pi 1. Whilst many tutorials may use a Pi 1, it will work just as well with any other version of the Pi (and thousands of other microcontrollers/processors).

8 MCP230XX chips can share an I2C bus meaning that with the following parts you can have a large number of GPIO pins
8x MCP23008 = 64 GPIO pins
8x MCP23017 = 128 GPIO pins.
Thank you for the clarification! I am thinking I will go with the MCP23017. However, I am very new to Python coding. The following code is what I worked out (with the help of my contributors on this forum) using the original 40 pins(3 of which I am using here)...

Code: Select all

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(xa1,GPIO.OUT)
GPIO.setup(xa2.GPIO.OUT)
GPIO.setup(xV,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
while True:
	if GPIO.input(xV):
		GPIO.output(xa1,GPIO.HIGH)
		GPIO.output(xa2,GPIO.LOW)
	else:
		GPIO.output(xa2,GPIO.HIGH)
		GPIO.output(xa1,GPIO.LOW)
	time.sleep(0.1)
the problem is I have to do this same code to evaluate 19 more circuits. Putting me at an even 60 I/O pins that are all independant. The MCP23017 will do the trick but how would I code it? Is there a different set mode? Is there a way in which I would be able to say GPIO.output(47,GPIO.HIGH)?

User avatar
DougieLawson
Posts: 36829
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website Twitter

Re: ISO GPIO pins 41-x expander

Fri Apr 13, 2018 4:52 pm

Here's a python class that makes driving a MCP23017 easier

Code: Select all

#!/usr/bin/python

# (C) 2017, 2018 Copyright Darkside Logic (One) Ltd. All rights reserved
# Version 0.9.3
import smbus
import syslog

class pinControl():

    def __init__(self, addr = 0x27, active='HIGH', aDir = 0x00, bDir = 0x00):

        self.ADDR = addr
        self.active = (True if active == 'HIGH' else False)

        self.IODIRA   = 0x00
        self.IODIRB   = 0x01
        self.IPOLA    = 0x02
        self.IPOLB    = 0x03
        self.GPINTENA = 0x04
        self.GPINTENB = 0x05
        self.DEFVALA  = 0x06
        self.DEFVALB  = 0x07
        self.INTCONA  = 0x08
        self.INTCONB  = 0x09
        self.IOCON1   = 0x0A
        self.IOCON2   = 0x0B
        self.GPPUA    = 0x0C
        self.GPPUB    = 0x0D
        self.INTFA    = 0x0E
        self.INTFB    = 0x0F
        self.INTCAPA  = 0x10
        self.INTCAPB  = 0x11
        self.GPIOA    = 0x12
        self.GPIOB    = 0x13
        self.OLATA    = 0x14
        self.OLATB    = 0x15

        self.bus=smbus.SMBus(1)

        self.valueA   = 0
        self.valueB   = 0
        self.ipolA    = 0
        self.ipolB    = 0
        self.gpintenA = 0
        self.gpintenB = 0
        self.defvalA  = 0
        self.defvalB  = 0
        self.intconA  = 0
        self.intconB  = 0
        self.gppuA    = 0
        self.gppuB    = 0

        try:
            self.bus.write_byte_data(self.ADDR,self.IODIRA,aDir)
            self.bus.write_byte_data(self.ADDR,self.IODIRB,bDir)
            self.chipOK = True
        except:
            self.chipOK = False

    def pinOn(self, bank, pin):

        if self.chipOK:
            #    print (bank,  pin, "On")
            bit = pin - 1
            if bank == 'B':
                if self.active:
                    self.valueB = self.valueB | (1 << bit)
                else:    
                    self.valueB = self.valueB & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.OLATB, self.valueB)
            else:
                if self.active:
                    self.valueA = self.valueA | (1 << bit)
                else:    
                    self.valueA = self.valueA & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.OLATA, self.valueA)

    def pinOff(self, bank, pin):

        if self.chipOK:
            #    print (bank, pin, "Off")
            bit = pin - 1
            if bank == 'B':
                if self.active:
                    self.valueB = self.valueB & (0xff - (1 << bit))
                else:    
                    self.valueB = self.valueB | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.OLATB, self.valueB)
            else:
                if self.active:
                    self.valueA = self.valueA & (0xff - (1 << bit))
                else:    
                    self.valueA = self.valueA | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.OLATA, self.valueA)

    def pinAllOff(self):

        if self.chipOK:
            #    print "All off called"
            if self.active:
                self.valueA = 0x00
            else:
                self.valueA = 0xFF
            self.bus.write_byte_data(self.ADDR, self.OLATA, self.valueA)
            if self.active:
                self.valueB = 0x00
            else:
                self.valueB = 0xFF
            self.bus.write_byte_data(self.ADDR, self.OLATB, self.valueB)

    def pinRead(self, bank, pin):
    
        if self.chipOK:
            bit = pin - 1
            if bank == 'B':
                busVal = self.bus.read_byte_data(self.ADDR, self.GPIOB)
                self.valueB = busVal
                state = ((busVal & (1 << bit)) != 0)
            else:
                busVal = self.bus.read_byte_data(self.ADDR, self.GPIOA)
                self.valueA = busVal
                state = ((busVal & ( 1<< bit)) != 0)
            return "pinRead Bank:", bank, " Pin:", pin, state
        else:
            return None

    def readIOCON(self):

        if self.chipOK:
            busVal1 = self.bus.read_byte_data(self.ADDR, self.IOCON1)
            busVal2 = self.bus.read_byte_data(self.ADDR, self.IOCON2)
            return busVal1, busVal2
        else:
            return None, None

    def setMIRROR(self, bit = 6):

        if self.chipOK:
            busVal1 = self.bus.read_byte_data(self.ADDR, self.IOCON1)
            busVal1 = busVal1 | (1 << bit)
            self.bus.write_byte_data(self.ADDR, self.IOCON1, busVal1)

            busVal2 = self.bus.read_byte_data(self.ADDR, self.IOCON2)
            busVal2 = busVal2 | (1 << bit)
            self.bus.write_byte_data(self.ADDR, self.IOCON1, busVal2)

    def resetMIRROR(self, bit = 6):

        if self.chipOK:
            busVal1 = self.bus.read_byte_data(self.ADDR, self.IOCON1)
            busVal1 = busVal1 & (0xff - (1 << bit))
            self.bus.write_byte_data(self.ADDR, self.IOCON1, busVal1)

            busVal2 = self.bus.read_byte_data(self.ADDR, self.IOCON2)
            busVal2 = busVal2 & (0xff - (1 << bit))
            self.bus.write_byte_data(self.ADDR, self.IOCON2, busVal2)

    def setIPOL(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.ipolB = self.ipolB | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.IPOLB, self.ipolB)
            else:
                self.ipolA = self.ipolA | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.IPOLA, self.ipolA)

    def resetIPOL(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.ipolB = self.ipolB & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.IPOLB, self.ipolB)
            else:
                self.ipolA = self.ipolA & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.IPOLA, self.ipolA)

    def setGPINTEN(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.gpintenB = self.gpintenB | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.GPINTENB, self.gpintenB)
            else:
                self.gpintenA = self.gpintenA | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.GPINTENA, self.gpintenA)

    def resetGPINTEN(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.gpintenB = self.gpintenB & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.GPINTENB, self.gpintenB)
            else:
                self.gpintenA = self.gpintenA & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.GPINTENA, self.gpintenA)

    def falseDEFVAL(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.defvalB = self.defvalB | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.DEFVALB, self.defvalB)
            else:
                self.defvalA = self.defvalA | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.DEFVALA, self.defvalA)

    def trueDEFVAL(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.defvalB = self.defvalB & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.DEFVALB, self.defvalB)
            else:
                self.defvalA = self.defvalA & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.DEFVALA, self.defvalA)

    def setINTCON(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.intconB = self.intconB | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.INTCONB, self.intconB)
            else:
                self.intconA = self.intconA | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.INTCONA, self.intconA)

    def resetINTCON(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.intconB = self.intconB & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.INTCONB, self.intconB)
            else:
                self.intconA = self.intconA & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.INTCONA, self.intconA)

    def setGPPU(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.gppuB = self.gppuB | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.GPPUB, self.gppuB)
            else:
                self.gppuA = self.gppuA | (1 << bit)
                self.bus.write_byte_data(self.ADDR, self.GPPUA, self.gppuA)

    def resetGPPU(self, bank, pin):

        if self.chipOK:
            bit = pin - 1
            if bank == 'B': 
                self.gppuB = self.gppuB & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.GPPUB, self.gppuB)
            else:
                self.gppuA = self.gppuA & (0xff - (1 << bit))
                self.bus.write_byte_data(self.ADDR, self.GPPUA, self.gppuA)

    def readINTF(self):

        if self.chipOK:
            busVal1 = self.bus.read_byte_data(self.ADDR, self.INTFA)
            busVal2 = self.bus.read_byte_data(self.ADDR, self.INTFB)
            return busVal1, busVal2
        else:
            return None, None

    def readINTCAP(self):

        if self.chipOK:
            busVal1 = self.bus.read_byte_data(self.ADDR, self.INTCAPA)
            busVal2 = self.bus.read_byte_data(self.ADDR, self.INTCAPB)
            return busVal1, busVal2
        else:
            return None, None
Note: Having anything humorous in your signature is completely banned on this forum. Wear a tin-foil hat and you'll get a ban.

Any DMs sent on Twitter will be answered next month.

This is a doctor free zone.

Return to “General discussion”