/ adafruit_mcp230xx / mcp23017.py
mcp23017.py
  1  # SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries
  2  # SPDX-FileCopyrightText: 2019 Carter Nelson
  3  #
  4  # SPDX-License-Identifier: MIT
  5  
  6  """
  7  `mcp23017`
  8  ====================================================
  9  
 10  CircuitPython module for the MCP23017 I2C I/O extenders.
 11  
 12  * Author(s): Tony DiCola
 13  """
 14  
 15  from micropython import const
 16  from .mcp230xx import MCP230XX
 17  from .digital_inout import DigitalInOut
 18  
 19  __version__ = "0.0.0-auto.0"
 20  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx.git"
 21  
 22  # pylint: disable=bad-whitespace
 23  _MCP23017_ADDRESS = const(0x20)
 24  _MCP23017_IODIRA = const(0x00)
 25  _MCP23017_IODIRB = const(0x01)
 26  _MCP23017_IPOLA = const(0x02)
 27  _MCP23017_GPINTENA = const(0x04)
 28  _MCP23017_DEFVALA = const(0x06)
 29  _MCP23017_INTCONA = const(0x08)
 30  _MCP23017_IOCON = const(0x0A)
 31  _MCP23017_GPPUA = const(0x0C)
 32  _MCP23017_GPPUB = const(0x0D)
 33  _MCP23017_GPIOA = const(0x12)
 34  _MCP23017_GPIOB = const(0x13)
 35  _MCP23017_INTFA = const(0x0E)
 36  _MCP23017_INTFB = const(0x0F)
 37  _MCP23017_INTCAPA = const(0x10)
 38  _MCP23017_INTCAPB = const(0x11)
 39  
 40  
 41  class MCP23017(MCP230XX):
 42      """Supports MCP23017 instance on specified I2C bus and optionally
 43      at the specified I2C address.
 44      """
 45  
 46      def __init__(self, i2c, address=_MCP23017_ADDRESS):
 47          super().__init__(i2c, address)
 48          # Reset to all inputs with no pull-ups and no inverted polarity.
 49          self.iodir = 0xFFFF
 50          self.gppu = 0x0000
 51          self.iocon = 0x4  # turn on IRQ Pins as open drain
 52          self._write_u16le(_MCP23017_IPOLA, 0x0000)
 53  
 54      @property
 55      def gpio(self):
 56          """The raw GPIO output register.  Each bit represents the
 57          output value of the associated pin (0 = low, 1 = high), assuming that
 58          pin has been configured as an output previously.
 59          """
 60          return self._read_u16le(_MCP23017_GPIOA)
 61  
 62      @gpio.setter
 63      def gpio(self, val):
 64          self._write_u16le(_MCP23017_GPIOA, val)
 65  
 66      @property
 67      def gpioa(self):
 68          """The raw GPIO A output register.  Each bit represents the
 69          output value of the associated pin (0 = low, 1 = high), assuming that
 70          pin has been configured as an output previously.
 71          """
 72          return self._read_u8(_MCP23017_GPIOA)
 73  
 74      @gpioa.setter
 75      def gpioa(self, val):
 76          self._write_u8(_MCP23017_GPIOA, val)
 77  
 78      @property
 79      def gpiob(self):
 80          """The raw GPIO B output register.  Each bit represents the
 81          output value of the associated pin (0 = low, 1 = high), assuming that
 82          pin has been configured as an output previously.
 83          """
 84          return self._read_u8(_MCP23017_GPIOB)
 85  
 86      @gpiob.setter
 87      def gpiob(self, val):
 88          self._write_u8(_MCP23017_GPIOB, val)
 89  
 90      @property
 91      def iodir(self):
 92          """The raw IODIR direction register.  Each bit represents
 93          direction of a pin, either 1 for an input or 0 for an output mode.
 94          """
 95          return self._read_u16le(_MCP23017_IODIRA)
 96  
 97      @iodir.setter
 98      def iodir(self, val):
 99          self._write_u16le(_MCP23017_IODIRA, val)
100  
101      @property
102      def iodira(self):
103          """The raw IODIR A direction register.  Each bit represents
104          direction of a pin, either 1 for an input or 0 for an output mode.
105          """
106          return self._read_u8(_MCP23017_IODIRA)
107  
108      @iodira.setter
109      def iodira(self, val):
110          self._write_u8(_MCP23017_IODIRA, val)
111  
112      @property
113      def iodirb(self):
114          """The raw IODIR B direction register.  Each bit represents
115          direction of a pin, either 1 for an input or 0 for an output mode.
116          """
117          return self._read_u8(_MCP23017_IODIRB)
118  
119      @iodirb.setter
120      def iodirb(self, val):
121          self._write_u8(_MCP23017_IODIRB, val)
122  
123      @property
124      def gppu(self):
125          """The raw GPPU pull-up register.  Each bit represents
126          if a pull-up is enabled on the specified pin (1 = pull-up enabled,
127          0 = pull-up disabled).  Note pull-down resistors are NOT supported!
128          """
129          return self._read_u16le(_MCP23017_GPPUA)
130  
131      @gppu.setter
132      def gppu(self, val):
133          self._write_u16le(_MCP23017_GPPUA, val)
134  
135      @property
136      def gppua(self):
137          """The raw GPPU A pull-up register.  Each bit represents
138          if a pull-up is enabled on the specified pin (1 = pull-up enabled,
139          0 = pull-up disabled).  Note pull-down resistors are NOT supported!
140          """
141          return self._read_u8(_MCP23017_GPPUA)
142  
143      @gppua.setter
144      def gppua(self, val):
145          self._write_u8(_MCP23017_GPPUA, val)
146  
147      @property
148      def gppub(self):
149          """The raw GPPU B pull-up register.  Each bit represents
150          if a pull-up is enabled on the specified pin (1 = pull-up enabled,
151          0 = pull-up disabled).  Note pull-down resistors are NOT supported!
152          """
153          return self._read_u8(_MCP23017_GPPUB)
154  
155      @gppub.setter
156      def gppub(self, val):
157          self._write_u8(_MCP23017_GPPUB, val)
158  
159      def get_pin(self, pin):
160          """Convenience function to create an instance of the DigitalInOut class
161          pointing at the specified pin of this MCP23017 device.
162          """
163          assert 0 <= pin <= 15
164          return DigitalInOut(pin, self)
165  
166      @property
167      def interrupt_configuration(self):
168          """The raw INTCON interrupt control register. The INTCON register
169          controls how the associated pin value is compared for the
170          interrupt-on-change feature. If  a  bit  is  set,  the  corresponding
171          I/O  pin  is  compared against the associated bit in the DEFVAL
172          register. If a bit value is clear, the corresponding I/O pin is
173          compared against the previous value.
174          """
175          return self._read_u16le(_MCP23017_INTCONA)
176  
177      @interrupt_configuration.setter
178      def interrupt_configuration(self, val):
179          self._write_u16le(_MCP23017_INTCONA, val)
180  
181      @property
182      def interrupt_enable(self):
183          """The raw GPINTEN interrupt control register. The GPINTEN register
184          controls the interrupt-on-change feature for each pin. If a bit is
185          set, the corresponding pin is enabled for interrupt-on-change.
186          The DEFVAL and INTCON registers must also be configured if any pins
187          are enabled for interrupt-on-change.
188          """
189          return self._read_u16le(_MCP23017_GPINTENA)
190  
191      @interrupt_enable.setter
192      def interrupt_enable(self, val):
193          self._write_u16le(_MCP23017_GPINTENA, val)
194  
195      @property
196      def default_value(self):
197          """The raw DEFVAL interrupt control register. The default comparison
198          value is configured in the DEFVAL register. If enabled (via GPINTEN
199          and INTCON) to compare against the DEFVAL register, an opposite value
200          on the associated pin will cause an interrupt to occur.
201          """
202          return self._read_u16le(_MCP23017_DEFVALA)
203  
204      @default_value.setter
205      def default_value(self, val):
206          self._write_u16le(_MCP23017_DEFVALA, val)
207  
208      @property
209      def io_control(self):
210          """The raw IOCON configuration register. Bit 1 controls interrupt
211          polarity (1 = active-high, 0 = active-low). Bit 2 is whether irq pin
212          is open drain (1 = open drain, 0 = push-pull). Bit 3 is unused.
213          Bit 4 is whether SDA slew rate is enabled (1 = yes). Bit 5 is if I2C
214          address pointer auto-increments (1 = no). Bit 6 is whether interrupt
215          pins are internally connected (1 = yes). Bit 7 is whether registers
216          are all in one bank (1 = no).
217          """
218          return self._read_u8(_MCP23017_IOCON)
219  
220      @io_control.setter
221      def io_control(self, val):
222          self._write_u8(_MCP23017_IOCON, val)
223  
224      @property
225      def int_flag(self):
226          """Returns a list with the pin numbers that caused an interrupt
227          port A ----> pins 0-7
228          port B ----> pins 8-15
229          """
230          intf = self._read_u16le(_MCP23017_INTFA)
231          flags = [pin for pin in range(16) if intf & (1 << pin)]
232          return flags
233  
234      @property
235      def int_flaga(self):
236          """Returns a list of pin numbers that caused an interrupt in port A
237          pins: 0-7
238          """
239          intfa = self._read_u8(_MCP23017_INTFA)
240          flags = [pin for pin in range(8) if intfa & (1 << pin)]
241          return flags
242  
243      @property
244      def int_flagb(self):
245          """Returns a list of pin numbers that caused an interrupt in port B
246          pins: 8-15
247          """
248          intfb = self._read_u8(_MCP23017_INTFB)
249          flags = [pin + 8 for pin in range(8) if intfb & (1 << pin)]
250          return flags
251  
252      def clear_ints(self):
253          """Clears interrupts by reading INTCAP."""
254          self._read_u16le(_MCP23017_INTCAPA)
255  
256      def clear_inta(self):
257          """Clears port A interrupts."""
258          self._read_u8(_MCP23017_INTCAPA)
259  
260      def clear_intb(self):
261          """Clears port B interrupts."""
262          self._read_u8(_MCP23017_INTCAPB)