diff --git a/README.rst b/README.rst index 269c644..e0d8830 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ Introduction :target: https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx/actions/ :alt: Build Status -CircuitPython module for the MCP23017 and MCP23008 I2C I/O extenders. +CircuitPython module for the MCP23017/08 I2C and MCP23S17/08 SPI I/O extenders. Dependencies ============= diff --git a/adafruit_mcp230xx/mcp23017.py b/adafruit_mcp230xx/mcp23017.py index 4ab3e1c..35a7fce 100644 --- a/adafruit_mcp230xx/mcp23017.py +++ b/adafruit_mcp230xx/mcp23017.py @@ -253,12 +253,13 @@ def io_control(self): Bit 4 is whether SDA slew rate is enabled (1 = yes). Bit 5 is if I2C address pointer auto-increments (1 = no). Bit 6 is whether interrupt pins are internally connected (1 = yes). Bit 7 is whether registers - are all in one bank (1 = no). + are all in one bank (1 = no), this is silently ignored if set to ``1``. """ return self._read_u8(_MCP23017_IOCON) @io_control.setter def io_control(self, val): + val &= ~0x80 self._write_u8(_MCP23017_IOCON, val) @property diff --git a/adafruit_mcp230xx/mcp230xx.py b/adafruit_mcp230xx/mcp230xx.py index d94154d..5993bca 100644 --- a/adafruit_mcp230xx/mcp230xx.py +++ b/adafruit_mcp230xx/mcp230xx.py @@ -1,5 +1,6 @@ # SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries # SPDX-FileCopyrightText: 2019 Carter Nelson +# SPDX-FileCopyrightText: 2021 Red_M # # SPDX-License-Identifier: MIT @@ -9,10 +10,10 @@ CircuitPython module for the MCP23017 and MCP23008 I2C I/O extenders. -* Author(s): Tony DiCola +* Author(s): Tony DiCola, Red_M (2021) """ -from adafruit_bus_device import i2c_device +from .mcp23xxx import MCP23XXX __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx.git" @@ -24,41 +25,42 @@ # pylint: disable=too-few-public-methods -class MCP230XX: +class MCP230XX(MCP23XXX): """Base class for MCP230xx devices.""" - def __init__(self, i2c, address): - self._device = i2c_device.I2CDevice(i2c, address) - def _read_u16le(self, register): # Read an unsigned 16 bit little endian value from the specified 8-bit # register. - with self._device as i2c: + with self._device as bus_device: _BUFFER[0] = register & 0xFF - i2c.write_then_readinto(_BUFFER, _BUFFER, out_end=1, in_start=1, in_end=3) + bus_device.write_then_readinto( + _BUFFER, _BUFFER, out_end=1, in_start=1, in_end=3 + ) return (_BUFFER[2] << 8) | _BUFFER[1] def _write_u16le(self, register, val): # Write an unsigned 16 bit little endian value to the specified 8-bit # register. - with self._device as i2c: + with self._device as bus_device: _BUFFER[0] = register & 0xFF _BUFFER[1] = val & 0xFF _BUFFER[2] = (val >> 8) & 0xFF - i2c.write(_BUFFER, end=3) + bus_device.write(_BUFFER, end=3) def _read_u8(self, register): # Read an unsigned 8 bit value from the specified 8-bit register. - with self._device as i2c: + with self._device as bus_device: _BUFFER[0] = register & 0xFF - i2c.write_then_readinto(_BUFFER, _BUFFER, out_end=1, in_start=1, in_end=2) + bus_device.write_then_readinto( + _BUFFER, _BUFFER, out_end=1, in_start=1, in_end=2 + ) return _BUFFER[1] def _write_u8(self, register, val): # Write an 8 bit value to the specified 8-bit register. - with self._device as i2c: + with self._device as bus_device: _BUFFER[0] = register & 0xFF _BUFFER[1] = val & 0xFF - i2c.write(_BUFFER, end=2) + bus_device.write(_BUFFER, end=2) diff --git a/adafruit_mcp230xx/mcp23s08.py b/adafruit_mcp230xx/mcp23s08.py new file mode 100644 index 0000000..06b7472 --- /dev/null +++ b/adafruit_mcp230xx/mcp23s08.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-FileCopyrightText: 2019 Carter Nelson +# SPDX-FileCopyrightText: 2021 Red_M +# +# SPDX-License-Identifier: MIT + +""" +`MCP23S08` +==================================================== + +CircuitPython module for the MCP23S08 I2C I/O extenders. + +* Author(s): Tony DiCola, Romy Bompart (2020), Red_M (2021) +""" + +from micropython import const +from .mcp23sxx import MCP23SXX +from .digital_inout import DigitalInOut + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP23Sxx.git" + +_MCP23S08_ADDRESS = const(0x20) +_MCP23S08_IODIR = const(0x00) +_MCP23S08_IPOL = const(0x01) +_MCP23S08_GPINTEN = const(0x02) +_MCP23S08_DEFVAL = const(0x03) +_MCP23S08_INTCON = const(0x04) +_MCP23S08_IOCON = const(0x05) +_MCP23S08_GPPU = const(0x06) +_MCP23S08_INTF = const(0x07) +_MCP23S08_INTCAP = const(0x08) +_MCP23S08_GPIO = const(0x09) + +# pylint: disable=too-many-arguments +class MCP23S08(MCP23SXX): + """Supports MCP23S08 instance on specified I2C bus and optionally + at the specified I2C address. + """ + + def __init__( + self, spi, chip_select, address=_MCP23S08_ADDRESS, reset=True, baudrate=100000 + ): + super().__init__(spi, address, chip_select, baudrate=baudrate) + # For user information + self.address = address + if reset: + # Reset to all inputs with no pull-ups and no inverted polarity. + self.iodir = 0xFF + self.gppu = 0x00 + self._write_u8(_MCP23S08_IPOL, 0x00) + + @property + def gpio(self): + """The raw GPIO output register. Each bit represents the + output value of the associated pin (0 = low, 1 = high), assuming that + pin has been configured as an output previously. + """ + return self._read_u8(_MCP23S08_GPIO) + + @gpio.setter + def gpio(self, val): + self._write_u8(_MCP23S08_GPIO, val) + + @property + def iodir(self): + """The raw IODIR direction register. Each bit represents + direction of a pin, either 1 for an input or 0 for an output mode. + """ + return self._read_u8(_MCP23S08_IODIR) + + @iodir.setter + def iodir(self, val): + self._write_u8(_MCP23S08_IODIR, val) + + @property + def gppu(self): + """The raw GPPU pull-up register. Each bit represents + if a pull-up is enabled on the specified pin (1 = pull-up enabled, + 0 = pull-up disabled). Note pull-down resistors are NOT supported! + """ + return self._read_u8(_MCP23S08_GPPU) + + @gppu.setter + def gppu(self, val): + self._write_u8(_MCP23S08_GPPU, val) + + def get_pin(self, pin): + """Convenience function to create an instance of the DigitalInOut class + pointing at the specified pin of this MCP23S08 device. + """ + if not 0 <= pin <= 7: + raise ValueError("Pin number must be 0-7.") + return DigitalInOut(pin, self) diff --git a/adafruit_mcp230xx/mcp23s17.py b/adafruit_mcp230xx/mcp23s17.py new file mode 100644 index 0000000..0d77b9b --- /dev/null +++ b/adafruit_mcp230xx/mcp23s17.py @@ -0,0 +1,307 @@ +# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-FileCopyrightText: 2019 Carter Nelson +# SPDX-FileCopyrightText: 2021 Red_M +# +# SPDX-License-Identifier: MIT + +""" +`MCP23S17` +==================================================== + +CircuitPython module for the MCP23S17 SPI I/O extenders. + +* Author(s): Tony DiCola, Romy Bompart (2020), Red_M (2021) +""" + +from micropython import const +from .mcp23sxx import MCP23SXX +from .digital_inout import DigitalInOut + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx.git" + +_MCP23S17_ADDRESS = const(0x20) +_MCP23S17_IODIRA = const(0x00) +_MCP23S17_IODIRB = const(0x01) +_MCP23S17_IPOLA = const(0x02) +_MCP23S17_IPOLB = const(0x03) +_MCP23S17_GPINTENA = const(0x04) +_MCP23S17_DEFVALA = const(0x06) +_MCP23S17_INTCONA = const(0x08) +_MCP23S17_IOCON = const(0x0A) +_MCP23S17_GPPUA = const(0x0C) +_MCP23S17_GPPUB = const(0x0D) +_MCP23S17_GPIOA = const(0x12) +_MCP23S17_GPIOB = const(0x13) +_MCP23S17_INTFA = const(0x0E) +_MCP23S17_INTFB = const(0x0F) +_MCP23S17_INTCAPA = const(0x10) +_MCP23S17_INTCAPB = const(0x11) + +# pylint: disable=too-many-arguments +# pylint: disable=too-many-public-methods +class MCP23S17(MCP23SXX): + """Supports MCP23S17 instance on specified SPI bus and optionally + at the specified SPI address. + """ + + def __init__( + self, spi, chip_select, address=_MCP23S17_ADDRESS, reset=True, baudrate=100000 + ): + super().__init__(spi, address, chip_select, baudrate=baudrate) + # For user information + self.address = address + if reset: + # Reset to all inputs with no pull-ups and no inverted polarity. + self.iodir = 0xFFFF + self.gppu = 0x0000 + self.iocon = 0x4 # turn on IRQ Pins as open drain + self._write_u16le(_MCP23S17_IPOLA, 0x0000) + + @property + def gpio(self): + """The raw GPIO output register. Each bit represents the + output value of the associated pin (0 = low, 1 = high), assuming that + pin has been configured as an output previously. + """ + return self._read_u16le(_MCP23S17_GPIOA) + + @gpio.setter + def gpio(self, val): + self._write_u16le(_MCP23S17_GPIOA, val) + + @property + def gpioa(self): + """The raw GPIO A output register. Each bit represents the + output value of the associated pin (0 = low, 1 = high), assuming that + pin has been configured as an output previously. + """ + return self._read_u8(_MCP23S17_GPIOA) + + @gpioa.setter + def gpioa(self, val): + self._write_u8(_MCP23S17_GPIOA, val) + + @property + def gpiob(self): + """The raw GPIO B output register. Each bit represents the + output value of the associated pin (0 = low, 1 = high), assuming that + pin has been configured as an output previously. + """ + return self._read_u8(_MCP23S17_GPIOB) + + @gpiob.setter + def gpiob(self, val): + self._write_u8(_MCP23S17_GPIOB, val) + + @property + def iodir(self): + """The raw IODIR direction register. Each bit represents + direction of a pin, either 1 for an input or 0 for an output mode. + """ + return self._read_u16le(_MCP23S17_IODIRA) + + @iodir.setter + def iodir(self, val): + self._write_u16le(_MCP23S17_IODIRA, val) + + @property + def iodira(self): + """The raw IODIR A direction register. Each bit represents + direction of a pin, either 1 for an input or 0 for an output mode. + """ + return self._read_u8(_MCP23S17_IODIRA) + + @iodira.setter + def iodira(self, val): + self._write_u8(_MCP23S17_IODIRA, val) + + @property + def iodirb(self): + """The raw IODIR B direction register. Each bit represents + direction of a pin, either 1 for an input or 0 for an output mode. + """ + return self._read_u8(_MCP23S17_IODIRB) + + @iodirb.setter + def iodirb(self, val): + self._write_u8(_MCP23S17_IODIRB, val) + + @property + def gppu(self): + """The raw GPPU pull-up register. Each bit represents + if a pull-up is enabled on the specified pin (1 = pull-up enabled, + 0 = pull-up disabled). Note pull-down resistors are NOT supported! + """ + return self._read_u16le(_MCP23S17_GPPUA) + + @gppu.setter + def gppu(self, val): + self._write_u16le(_MCP23S17_GPPUA, val) + + @property + def gppua(self): + """The raw GPPU A pull-up register. Each bit represents + if a pull-up is enabled on the specified pin (1 = pull-up enabled, + 0 = pull-up disabled). Note pull-down resistors are NOT supported! + """ + return self._read_u8(_MCP23S17_GPPUA) + + @gppua.setter + def gppua(self, val): + self._write_u8(_MCP23S17_GPPUA, val) + + @property + def gppub(self): + """The raw GPPU B pull-up register. Each bit represents + if a pull-up is enabled on the specified pin (1 = pull-up enabled, + 0 = pull-up disabled). Note pull-down resistors are NOT supported! + """ + return self._read_u8(_MCP23S17_GPPUB) + + @gppub.setter + def gppub(self, val): + self._write_u8(_MCP23S17_GPPUB, val) + + def get_pin(self, pin): + """Convenience function to create an instance of the DigitalInOut class + pointing at the specified pin of this MCP23S17 device. + """ + if not 0 <= pin <= 15: + raise ValueError("Pin number must be 0-15.") + return DigitalInOut(pin, self) + + @property + def ipol(self): + """The raw IPOL output register. Each bit represents the + polarity value of the associated pin (0 = normal, 1 = inverted), assuming that + pin has been configured as an input previously. + """ + return self._read_u16le(_MCP23S17_IPOLA) + + @ipol.setter + def ipol(self, val): + self._write_u16le(_MCP23S17_IPOLA, val) + + @property + def ipola(self): + """The raw IPOL A output register. Each bit represents the + polarity value of the associated pin (0 = normal, 1 = inverted), assuming that + pin has been configured as an input previously. + """ + return self._read_u8(_MCP23S17_IPOLA) + + @ipola.setter + def ipola(self, val): + self._write_u8(_MCP23S17_IPOLA, val) + + @property + def ipolb(self): + """The raw IPOL B output register. Each bit represents the + polarity value of the associated pin (0 = normal, 1 = inverted), assuming that + pin has been configured as an input previously. + """ + return self._read_u8(_MCP23S17_IPOLB) + + @ipolb.setter + def ipolb(self, val): + self._write_u8(_MCP23S17_IPOLB, val) + + @property + def interrupt_configuration(self): + """The raw INTCON interrupt control register. The INTCON register + controls how the associated pin value is compared for the + interrupt-on-change feature. If a bit is set, the corresponding + I/O pin is compared against the associated bit in the DEFVAL + register. If a bit value is clear, the corresponding I/O pin is + compared against the previous value. + """ + return self._read_u16le(_MCP23S17_INTCONA) + + @interrupt_configuration.setter + def interrupt_configuration(self, val): + self._write_u16le(_MCP23S17_INTCONA, val) + + @property + def interrupt_enable(self): + """The raw GPINTEN interrupt control register. The GPINTEN register + controls the interrupt-on-change feature for each pin. If a bit is + set, the corresponding pin is enabled for interrupt-on-change. + The DEFVAL and INTCON registers must also be configured if any pins + are enabled for interrupt-on-change. + """ + return self._read_u16le(_MCP23S17_GPINTENA) + + @interrupt_enable.setter + def interrupt_enable(self, val): + self._write_u16le(_MCP23S17_GPINTENA, val) + + @property + def default_value(self): + """The raw DEFVAL interrupt control register. The default comparison + value is configured in the DEFVAL register. If enabled (via GPINTEN + and INTCON) to compare against the DEFVAL register, an opposite value + on the associated pin will cause an interrupt to occur. + """ + return self._read_u16le(_MCP23S17_DEFVALA) + + @default_value.setter + def default_value(self, val): + self._write_u16le(_MCP23S17_DEFVALA, val) + + @property + def io_control(self): + """The raw IOCON configuration register. Bit 1 controls interrupt + polarity (1 = active-high, 0 = active-low). Bit 2 is whether irq pin + is open drain (1 = open drain, 0 = push-pull). Bit 3 is unused. + Bit 4 is whether SDA slew rate is enabled (1 = yes). Bit 5 is if SPI + address pointer auto-increments (1 = no). Bit 6 is whether interrupt + pins are internally connected (1 = yes). Bit 7 is whether registers + are all in one bank (1 = no), this is silently ignored if set to ``1``. + """ + return self._read_u8(_MCP23S17_IOCON) + + @io_control.setter + def io_control(self, val): + val &= ~0x80 + self._write_u8(_MCP23S17_IOCON, val) + + @property + def int_flag(self): + """Returns a list with the pin numbers that caused an interrupt + port A ----> pins 0-7 + port B ----> pins 8-15 + """ + intf = self._read_u16le(_MCP23S17_INTFA) + flags = [pin for pin in range(16) if intf & (1 << pin)] + return flags + + @property + def int_flaga(self): + """Returns a list of pin numbers that caused an interrupt in port A + pins: 0-7 + """ + intfa = self._read_u8(_MCP23S17_INTFA) + flags = [pin for pin in range(8) if intfa & (1 << pin)] + return flags + + @property + def int_flagb(self): + """Returns a list of pin numbers that caused an interrupt in port B + pins: 8-15 + """ + intfb = self._read_u8(_MCP23S17_INTFB) + flags = [pin + 8 for pin in range(8) if intfb & (1 << pin)] + return flags + + def clear_ints(self): + """Clears interrupts by reading INTCAP.""" + self._read_u16le(_MCP23S17_INTCAPA) + + def clear_inta(self): + """Clears port A interrupts.""" + self._read_u8(_MCP23S17_INTCAPA) + + def clear_intb(self): + """Clears port B interrupts.""" + self._read_u8(_MCP23S17_INTCAPB) diff --git a/adafruit_mcp230xx/mcp23sxx.py b/adafruit_mcp230xx/mcp23sxx.py new file mode 100644 index 0000000..34a43a6 --- /dev/null +++ b/adafruit_mcp230xx/mcp23sxx.py @@ -0,0 +1,71 @@ +# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-FileCopyrightText: 2019 Carter Nelson +# SPDX-FileCopyrightText: 2021 Red_M +# +# SPDX-License-Identifier: MIT + +""" +`mcp23sxx` +==================================================== + +CircuitPython module for the MCP23S17 SPI I/O extenders. + +* Author(s): Romy Bompart (2020), Red_M (2021) +""" + +from .mcp23xxx import MCP23XXX + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx.git" + +# shared between both the MCP23S17 class to reduce memory allocations. +# However this is explicitly not thread safe or re-entrant by design! +# Header to start a reading or writting operation +_OUT_BUFFER = bytearray(4) +_IN_BUFFER = bytearray(4) +MCP23SXX_CODE_READ = 0x41 +MCP23SXX_CODE_WRITE = 0x40 + +# pylint: disable=too-few-public-methods +class MCP23SXX(MCP23XXX): + """Base class for MCP23Sxx devices.""" + + def __init__(self, spi, address, chip_select, baudrate=100000): + self.cmd_write = MCP23SXX_CODE_WRITE | (address << 1) + self.cmd_read = MCP23SXX_CODE_READ | (address << 1) + super().__init__(spi, address, chip_select, baudrate=baudrate) + + def _read_u16le(self, register): + # Read an unsigned 16 bit little endian value from the specified 8-bit + # register. + _OUT_BUFFER[0] = self.cmd_read + _OUT_BUFFER[1] = register & 0xFF + with self._device as bus_device: + bus_device.write_readinto(_OUT_BUFFER, _IN_BUFFER) + return (_IN_BUFFER[3] << 8) | _IN_BUFFER[2] + + def _write_u16le(self, register, value): + # Write an unsigned 16 bit little endian value to the specified 8-bit + # register. + _OUT_BUFFER[0] = self.cmd_write + _OUT_BUFFER[1] = register & 0xFF + _OUT_BUFFER[2] = value & 0xFF + _OUT_BUFFER[3] = (value >> 8) & 0xFF + with self._device as bus_device: + bus_device.write(_OUT_BUFFER) + + def _read_u8(self, register): + # Read an unsigned 8 bit value from the specified 8-bit register. + _OUT_BUFFER[0] = self.cmd_read + _OUT_BUFFER[1] = register & 0xFF + with self._device as bus_device: + bus_device.write_readinto(_OUT_BUFFER, _IN_BUFFER) + return _IN_BUFFER[2] + + def _write_u8(self, register, value): + # Write an 8 bit value to the specified 8-bit register. + _OUT_BUFFER[0] = self.cmd_write + _OUT_BUFFER[1] = register & 0xFF + _OUT_BUFFER[2] = value & 0xFF + with self._device as bus_device: + bus_device.write(_OUT_BUFFER, end=3) diff --git a/adafruit_mcp230xx/mcp23xxx.py b/adafruit_mcp230xx/mcp23xxx.py new file mode 100644 index 0000000..d92aa7e --- /dev/null +++ b/adafruit_mcp230xx/mcp23xxx.py @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2021 Red_M +# +# SPDX-License-Identifier: MIT + +""" +`mcp230xx` +==================================================== + +CircuitPython module for the MCP23017, MCP23008 I2C and MCP23S17, MCP23S08 SPI I/O extenders. + +* Author(s): Red_M +""" + +from adafruit_bus_device import i2c_device, spi_device + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx.git" + +# pylint: disable=too-few-public-methods +class MCP23XXX: + """Base class for MCP23xxx devices.""" + + def __init__(self, bus_device, address, chip_select=None, baudrate=100000): + if chip_select is None: + self._device = i2c_device.I2CDevice(bus_device, address) + else: + self._device = spi_device.SPIDevice( + bus_device, chip_select, baudrate=baudrate + ) diff --git a/docs/api.rst b/docs/api.rst index ec0dcb8..f92e30a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -13,5 +13,14 @@ .. automodule:: adafruit_mcp230xx.mcp23017 :members: +.. automodule:: adafruit_mcp230xx.mcp23sxx + :members: + +.. automodule:: adafruit_mcp230xx.mcp23s08 + :members: + +.. automodule:: adafruit_mcp230xx.mcp23s17 + :members: + .. automodule:: adafruit_mcp230xx.digital_inout :members: diff --git a/docs/examples.rst b/docs/examples.rst index b62fb52..56a9367 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -6,3 +6,7 @@ Ensure your device works with this simple test. .. literalinclude:: ../examples/mcp230xx_simpletest.py :caption: examples/mcp230xx_simpletest.py :linenos: + +.. literalinclude:: ../examples/mcp23Sxx_simpletest.py + :caption: examples/mcp23Sxx_simpletest.py + :linenos: diff --git a/examples/mcp23Sxx_event_detect_interrupt.py b/examples/mcp23Sxx_event_detect_interrupt.py new file mode 100644 index 0000000..bf4d11c --- /dev/null +++ b/examples/mcp23Sxx_event_detect_interrupt.py @@ -0,0 +1,77 @@ +# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-FileCopyrightText: 2021 Red_M +# +# SPDX-License-Identifier: MIT + +from time import sleep + +import board +import busio +from digitalio import Direction, Pull +from RPi import GPIO +from adafruit_mcp230xx.mcp23s17 import MCP23S17 + +# Initialize the SPI bus: +spi = busio.SPI(board.SCK_1, MOSI=board.MOSI_1, MISO=board.MISO_1) +cs = digitalio.DigitalInOut(board.CS0) + +# Initialize the MCP23S17 chip on the bonnet +mcp = MCP23S17(spi, cs) + +# Optionally change the address of the device if you set any of the A0, A1, A2 +# pins. Specify the new address with a keyword parameter: +# mcp = MCP23S17(spi, cs, address=0x21) # MCP23S17 w/ A0 set + +# Make a list of all the pins (a.k.a 0-16) +pins = [] +for pin in range(0, 16): + pins.append(mcp.get_pin(pin)) + +# Set all the pins to input +for pin in pins: + pin.direction = Direction.INPUT + pin.pull = Pull.UP + +# Set up to check all the port B pins (pins 8-15) w/interrupts! +mcp.interrupt_enable = 0xFFFF # Enable Interrupts in all pins +# If intcon is set to 0's we will get interrupts on +# both button presses and button releases +mcp.interrupt_configuration = 0x0000 # interrupt on any change +mcp.io_control = 0x44 # Interrupt as open drain and mirrored +mcp.clear_ints() # Interrupts need to be cleared initially + +# Or, we can ask to be notified CONTINUOUSLY if a pin goes LOW (button press) +# we won't get an IRQ pulse when the pin is HIGH! +# mcp.interrupt_configuration = 0xFFFF # notify pin value +# mcp.default_value = 0xFFFF # default value is 'high' so notify whenever 'low' + + +def print_interrupt(port): + """Callback function to be called when an Interrupt occurs.""" + for pin_flag in mcp.int_flag: + print("Interrupt connected to Pin: {}".format(port)) + print("Pin number: {} changed to: {}".format(pin_flag, pins[pin_flag].value)) + mcp.clear_ints() + + +# connect either interrupt pin to the Raspberry pi's pin 17. +# They were previously configured as mirrored. +GPIO.setmode(GPIO.BCM) +interrupt = 17 +GPIO.setup(interrupt, GPIO.IN, GPIO.PUD_UP) # Set up Pi's pin as input, pull up + +# The add_event_detect fuction will call our print_interrupt callback function +# every time an interrupt gets triggered. +GPIO.add_event_detect(interrupt, GPIO.FALLING, callback=print_interrupt, bouncetime=10) + +# The following lines are so the program runs for at least 60 seconds, +# during that time it will detect any pin interrupt and print out the pin number +# that changed state and its current state. +# The program can be terminated using Ctrl+C. It doesn't matter how it +# terminates it will always run GPIO.cleanup(). +try: + print("When button is pressed you'll see a message") + sleep(60) # You could run your main while loop here. + print("Time's up. Finished!") +finally: + GPIO.cleanup() diff --git a/examples/mcp23Sxx_simpletest.py b/examples/mcp23Sxx_simpletest.py new file mode 100644 index 0000000..94312ac --- /dev/null +++ b/examples/mcp23Sxx_simpletest.py @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-FileCopyrightText: 2021 Red_M +# +# SPDX-License-Identifier: MIT + +# Simple demo of reading and writing the digital I/O of the MCP2300xx as if +# they were native CircuitPython digital inputs/outputs. +# Author: Tony DiCola +import time + +import board +import busio +import digitalio + +from adafruit_mcp230xx.mcp23s08 import MCP23S08 + +# from adafruit_mcp230xx.mcp23s17 import MCP23S17 + + +# Initialize the SPI bus with a chip select pin: +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +cs = digitalio.DigitalInOut(board.A1) + +# Create an instance of either the MCP23S08 or MCP23S17 class depending on +# which chip you're using: +mcp = MCP23S08(spi, cs) # MCP23S08 +# mcp = MCP23S17(spi, cs) # MCP23S17 + +# Optionally change the address of the device if you set any of the A0, A1, A2 +# pins. Specify the new address with a keyword parameter: +# mcp = MCP23S17(spi, cs, address=0x21) # MCP23S17 w/ A0 set + +# Now call the get_pin function to get an instance of a pin on the chip. +# This instance will act just like a digitalio.DigitalInOut class instance +# and has all the same properties and methods (except you can't set pull-down +# resistors, only pull-up!). For the MCP23S08 you specify a pin number from 0 +# to 7 for the GP0...GP7 pins. For the MCP23S17 you specify a pin number from +# 0 to 15 for the GPIOA0...GPIOA7, GPIOB0...GPIOB7 pins (i.e. pin 12 is GPIOB4). +pin0 = mcp.get_pin(0) +pin1 = mcp.get_pin(1) + +# Setup pin0 as an output that's at a high logic level. +pin0.switch_to_output(value=True) + +# Setup pin1 as an input with a pull-up resistor enabled. Notice you can also +# use properties to change this state. +pin1.direction = digitalio.Direction.INPUT +pin1.pull = digitalio.Pull.UP + +# Now loop blinking the pin 0 output and reading the state of pin 1 input. +while True: + # Blink pin 0 on and then off. + pin0.value = True + time.sleep(0.5) + pin0.value = False + time.sleep(0.5) + # Read pin 1 and print its state. + print("Pin 1 is at a high level: {0}".format(pin1.value))