Page 1 of 1

ISO GPIO pins 41-x expander

Posted: Thu Apr 12, 2018 9:53 pm
by rhinotekmn
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?

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 8:52 am
by scotty101
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.

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 9:08 am
by DougieLawson
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

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 11:09 am
by scotty101
Is there an echo in here? :D

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 11:24 am
by DougieLawson
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

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 11:48 am
by SteveSpencer
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.

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 4:45 pm
by rhinotekmn
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)?

Re: ISO GPIO pins 41-x expander

Posted: Fri Apr 13, 2018 4:52 pm
by DougieLawson
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