Skip to content
This repository was archived by the owner on Sep 30, 2019. It is now read-only.
This repository was archived by the owner on Sep 30, 2019. It is now read-only.

patch for Adafruit_MCP230xx/Adafruit_MCP230xx.py #141

@lmamakos

Description

@lmamakos

I had problem using this library with an MCP23017 device, and made some bugfix changes and I think some robustness improvements.

I think the design of the library needs to change a bit; this notion of using the number of GPIOs to select between two different devices rather than explicit selection between an MCP23008 vs an MCP23017 is a bit confusing. I don't think it useful to have anything other than 8 or 16 as values for num_gpios..

If, for example, someone is only using a 2 GPIO pins on port A but they have an MCP23017 device, the library will malfunction because the register addresses will be wrong. This could be mitigated by changing the IOCON.BANK bit in the IOCON configuration register to 1 so that the register address for both devices match..

In any case, here are the changes I made if there's interest. I was attempting to use the write8 and readU16 methods, without success. In the write8 case, there seems to be an implicit assumption that the use will only use this with an MCP23008 device since that register address is hardcoded.

In the case of doing a readU16 or readS16 call, that code was just broken, apparently due to a cut-n-paste error and was referencing the wrong register entirely.

I also attempted to initialize the chip into a deterministic state (resetting input polarity registers), and set the interrupt output to open-drain to minimize damage if the outputs are connected together in whatever circuit the device might happened to be installed in.

--- a/Adafruit_MCP230xx.py
+++ b/Adafruit_MCP230xx.py
@@ -32,6 +32,13 @@ MCP23017_GPPUA  = 0x0C
 MCP23017_GPPUB  = 0x0D
 MCP23017_OLATA  = 0x14
 MCP23017_OLATB  = 0x15
+MCP23017_IPOLA  = 0x02
+MCP23017_IPOLB  = 0x03
+
+MCP23017_IOCON  = 0x0A
+MCP23017_IOCON_ALT = 0x05
+MCP23017_IOCON_INIT = 0x44   # mirror INT pins, INT pins are open-drain
+
 MCP23008_GPIOA  = 0x09
 MCP23008_GPPUA  = 0x06
 MCP23008_OLATA  = 0x0A
@@ -52,8 +59,15 @@ class Adafruit_MCP230XX(object):
             self.direction = self.i2c.readU8(MCP23017_IODIRA)
             self.i2c.write8(MCP23008_GPPUA, 0x00)
         elif num_gpios > 8 and num_gpios <= 16:
+            self.i2c.write8(MCP23017_IOCON_ALT, 0x00)   # clear BANK bit if device in other mode
+                                                        # if device is in correct mode, this register
+                                                        # is aliased by GPINTENB and this will disable interrupts
+            self.i2c.write8(MCP23017_IOCON, MCP23017_IOCON_INIT)
+
             self.i2c.write8(MCP23017_IODIRA, 0xFF)  # all inputs on port A
             self.i2c.write8(MCP23017_IODIRB, 0xFF)  # all inputs on port B
+            self.i2c.write8(MCP23017_IPOLA, 0x00)   # normal input polarity (non-inverting) port A
+            self.i2c.write8(MCP23017_IPOLB, 0x00)   # normal input polarity (non-inverting) port B
             self.direction = self.i2c.readU8(MCP23017_IODIRA)
             self.direction |= self.i2c.readU8(MCP23017_IODIRB) << 8
             self.i2c.write8(MCP23017_GPPUA, 0x00)
@@ -80,9 +94,8 @@ class Adafruit_MCP230XX(object):
         if self.num_gpios <= 8:
             return self._readandchangepin(MCP23008_GPPUA, pin, value)
         if self.num_gpios <= 16:
-            lvalue = self._readandchangepin(MCP23017_GPPUA, pin, value)
             if (pin < 8):
-                return
+                return self._readandchangepin(MCP23017_GPPUA, pin, value)
             else:
                 return self._readandchangepin(MCP23017_GPPUB, pin-8, value) << 8

@@ -92,7 +105,7 @@ class Adafruit_MCP230XX(object):
             self.direction = self._readandchangepin(MCP23017_IODIRA, pin, mode)
         if self.num_gpios <= 16:
             if (pin < 8):
-                self.direction = self._readandchangepin(MCP23017_IODIRA, pin, mode)
+                self.direction = (self.direction & 0xff00) | (self._readandchangepin(MCP23017_IODIRA, pin, mode) & 0xff)
             else:
                 self.direction |= self._readandchangepin(MCP23017_IODIRB, pin-8, mode) << 8

@@ -125,29 +138,39 @@ class Adafruit_MCP230XX(object):
         return value & (1 << pin)

     def readU8(self):
-        result = self.i2c.readU8(MCP23008_OLATA)
+        if self.num_gpios > 8:
+            result = self.i2c.readU8(MCP23017_GPIOA)
+        else:
+            result = self.i2c.readU8(MCP23008_GPIOA)
         return(result)

     def readS8(self):
-        result = self.i2c.readU8(MCP23008_OLATA)
+        if self.num_gpios > 8:
+            result = self.i2c.readU8(MCP23017_GPIOA)
+        else:
+            result = self.i2c.readU8(MCP23008_GPIOA)
         if (result > 127): result -= 256
         return result

     def readU16(self):
         assert self.num_gpios >= 16, "16bits required"
-        lo = self.i2c.readU8(MCP23017_OLATA)
-        hi = self.i2c.readU8(MCP23017_OLATB)
+        lo = self.i2c.readU8(MCP23017_GPIOA)
+        hi = self.i2c.readU8(MCP23017_GPIOB)
         return((hi << 8) | lo)

     def readS16(self):
         assert self.num_gpios >= 16, "16bits required"
-        lo = self.i2c.readU8(MCP23017_OLATA)
-        hi = self.i2c.readU8(MCP23017_OLATB)
+        lo = self.i2c.readU8(MCP23017_GPIOA)
+        hi = self.i2c.readU8(MCP23017_GPIOB)
         if (hi > 127): hi -= 256
         return((hi << 8) | lo)

     def write8(self, value):
-        self.i2c.write8(MCP23008_OLATA, value)
+        if self.num_gpios > 8:
+            self.i2c.write8(MCP23017_OLATA, value)
+        else:
+            self.i2c.write8(MCP23008_OLATA, value)
+

     def write16(self, value):
         assert self.num_gpios >= 16, "16bits required"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions