Skip to content

Commit c05ae62

Browse files
authored
Merge pull request #29 from Flameeyes/mcp23016
Add support for the old, deprecated MCP23016 expander, too.
2 parents fc934c1 + 0d3ee70 commit c05ae62

File tree

2 files changed

+163
-13
lines changed

2 files changed

+163
-13
lines changed

adafruit_mcp230xx/digital_inout.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ def _clear_bit(val, bit):
3232

3333
class DigitalInOut:
3434
"""Digital input/output of the MCP230xx. The interface is exactly the
35-
same as the digitalio.DigitalInOut class (however the MCP230xx does not
36-
support pull-down resistors and an exception will be thrown
37-
attempting to set one).
35+
same as the digitalio.DigitalInOut class, however:
36+
37+
* MCP230xx family does not support pull-down resistors;
38+
* MCP23016 does not support pull-up resistors.
39+
40+
Exceptions will be thrown when attempting to set unsupported pull
41+
configurations.
3842
"""
3943

4044
def __init__(self, pin_number, mcp230xx):
@@ -105,17 +109,25 @@ def pull(self):
105109
value of digitalio.Pull.UP will enable a pull-up resistor, and None will
106110
disable it. Pull-down resistors are NOT supported!
107111
"""
108-
if _get_bit(self._mcp.gppu, self._pin):
109-
return digitalio.Pull.UP
112+
try:
113+
if _get_bit(self._mcp.gppu, self._pin):
114+
return digitalio.Pull.UP
115+
except AttributeError:
116+
# MCP23016 doesn't have a `gppu` register.
117+
raise ValueError("Pull-up/pull-down resistors not supported.")
110118
return None
111119

112120
@pull.setter
113121
def pull(self, val):
114-
if val is None:
115-
self._mcp.gppu = _clear_bit(self._mcp.gppu, self._pin)
116-
elif val == digitalio.Pull.UP:
117-
self._mcp.gppu = _enable_bit(self._mcp.gppu, self._pin)
118-
elif val == digitalio.Pull.DOWN:
119-
raise ValueError("Pull-down resistors are not supported!")
120-
else:
121-
raise ValueError("Expected UP, DOWN, or None for pull state!")
122+
try:
123+
if val is None:
124+
self._mcp.gppu = _clear_bit(self._mcp.gppu, self._pin)
125+
elif val == digitalio.Pull.UP:
126+
self._mcp.gppu = _enable_bit(self._mcp.gppu, self._pin)
127+
elif val == digitalio.Pull.DOWN:
128+
raise ValueError("Pull-down resistors are not supported!")
129+
else:
130+
raise ValueError("Expected UP, DOWN, or None for pull state!")
131+
except AttributeError:
132+
# MCP23016 doesn't have a `gppu` register.
133+
raise ValueError("Pull-up/pull-down resistors not supported.")

adafruit_mcp230xx/mcp23016.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries
2+
# SPDX-FileCopyrightText: 2019 Carter Nelson
3+
# SPDX-FileCopyrightText: 2020 Facebook Inc.
4+
#
5+
# SPDX-License-Identifier: MIT
6+
7+
"""
8+
`mcp23016`
9+
====================================================
10+
11+
CircuitPython module for the MCP23016 I2C I/O extenders.
12+
13+
* Author(s): Diego Elio Pettenò (based on MCP23017.py)
14+
15+
Notes
16+
-----
17+
18+
While the datasheet refers to the two 8-bit ports as port 0 and 1,
19+
for API compatibility with more recent expanders, these are exposed as
20+
ports A and B.
21+
"""
22+
23+
from micropython import const
24+
from .mcp230xx import MCP230XX
25+
from .digital_inout import DigitalInOut
26+
27+
__version__ = "0.0.0-auto.0"
28+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx.git"
29+
30+
# pylint: disable=bad-whitespace
31+
_MCP23016_ADDRESS = const(0x20)
32+
_MCP23016_GPIO0 = const(0x00)
33+
_MCP23016_GPIO1 = const(0x01)
34+
_MCP23016_IPOL0 = const(0x04)
35+
_MCP23016_IPOL1 = const(0x05)
36+
_MCP23016_IODIR0 = const(0x06)
37+
_MCP23016_IODIR1 = const(0x07)
38+
_MCP23016_INTCAP0 = const(0x08)
39+
_MCP23016_INTCAP1 = const(0x09)
40+
_MCP23016_IOCON0 = const(0x0A)
41+
_MCP23016_IOCON1 = const(0x0B)
42+
43+
44+
class MCP23016(MCP230XX):
45+
"""Supports MCP23016 instance on specified I2C bus and optionally
46+
at the specified I2C address.
47+
"""
48+
49+
def __init__(self, i2c, address=_MCP23016_ADDRESS):
50+
super().__init__(i2c, address)
51+
52+
# Reset to all inputs and no inverted polarity.
53+
self.iodir = 0xFFFF
54+
self._write_u16le(_MCP23016_IPOL0, 0x0000)
55+
56+
@property
57+
def gpio(self):
58+
"""The raw GPIO output register. Each bit represents the
59+
output value of the associated pin (0 = low, 1 = high), assuming that
60+
pin has been configured as an output previously.
61+
"""
62+
return self._read_u16le(_MCP23016_GPIO0)
63+
64+
@gpio.setter
65+
def gpio(self, val):
66+
self._write_u16le(_MCP23016_GPIO0, val)
67+
68+
@property
69+
def gpioa(self):
70+
"""The raw GPIO 0 output register. Each bit represents the
71+
output value of the associated pin (0 = low, 1 = high), assuming that
72+
pin has been configured as an output previously.
73+
"""
74+
return self._read_u8(_MCP23016_GPIO0)
75+
76+
@gpioa.setter
77+
def gpioa(self, val):
78+
self._write_u8(_MCP23016_GPIO0, val)
79+
80+
@property
81+
def gpiob(self):
82+
"""The raw GPIO 1 output register. Each bit represents the
83+
output value of the associated pin (0 = low, 1 = high), assuming that
84+
pin has been configured as an output previously.
85+
"""
86+
return self._read_u8(_MCP23016_GPIO1)
87+
88+
@gpiob.setter
89+
def gpiob(self, val):
90+
self._write_u8(_MCP23016_GPIO1, val)
91+
92+
@property
93+
def iodir(self):
94+
"""The raw IODIR direction register. Each bit represents
95+
direction of a pin, either 1 for an input or 0 for an output mode.
96+
"""
97+
return self._read_u16le(_MCP23016_IODIR0)
98+
99+
@iodir.setter
100+
def iodir(self, val):
101+
self._write_u16le(_MCP23016_IODIR0, val)
102+
103+
@property
104+
def iodira(self):
105+
"""The raw IODIR0 direction register. Each bit represents
106+
direction of a pin, either 1 for an input or 0 for an output mode.
107+
"""
108+
return self._read_u8(_MCP23016_IODIR0)
109+
110+
@iodira.setter
111+
def iodira(self, val):
112+
self._write_u8(_MCP23016_IODIR0, val)
113+
114+
@property
115+
def iodirb(self):
116+
"""The raw IODIR0 direction register. Each bit represents
117+
direction of a pin, either 1 for an input or 0 for an output mode.
118+
"""
119+
return self._read_u8(_MCP23016_IODIR1)
120+
121+
@iodirb.setter
122+
def iodirb(self, val):
123+
self._write_u8(_MCP23016_IODIR1, val)
124+
125+
def get_pin(self, pin):
126+
"""Convenience function to create an instance of the DigitalInOut class
127+
pointing at the specified pin of this MCP23016 device.
128+
"""
129+
assert 0 <= pin <= 15
130+
return DigitalInOut(pin, self)
131+
132+
def clear_inta(self):
133+
"""Clears port 0 interrupts."""
134+
self._read_u8(_MCP23016_INTCAP0)
135+
136+
def clear_intb(self):
137+
"""Clears port 1 interrupts."""
138+
self._read_u8(_MCP23016_INTCAP1)

0 commit comments

Comments
 (0)