Skip to content

Add interrupt support & examples to MCP23017 #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 67 additions & 9 deletions adafruit_mcp230xx.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@

* Author(s): Tony DiCola
"""
import digitalio

import adafruit_bus_device.i2c_device as i2c_device

from adafruit_bus_device import i2c_device
import digitalio
from micropython import const


Expand Down Expand Up @@ -60,12 +59,11 @@
_MCP23017_IPOLB = const(0x03)
_MCP23017_GPINTENA = const(0x04)
_MCP23017_GPINTENB = const(0x05)
_MCP23008_DEFVALA = const(0x06)
_MCP23008_DEFVALB = const(0x07)
_MCP23008_INTCONA = const(0x08)
_MCP23008_INTCONB = const(0x09)
_MCP23008_IOCONA = const(0x0A)
_MCP23008_IOCONB = const(0x0B)
_MCP23017_DEFVALA = const(0x06)
_MCP23017_DEFVALB = const(0x07)
_MCP23017_INTCONA = const(0x08)
_MCP23017_INTCONB = const(0x09)
_MCP23017_IOCON = const(0x0A)
_MCP23017_GPPUA = const(0x0C)
_MCP23017_GPPUB = const(0x0D)
_MCP23008_INTFA = const(0x0E)
Expand Down Expand Up @@ -267,6 +265,7 @@ def __init__(self, i2c, address=_MCP23017_ADDRESS):
# 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(_MCP23017_IPOLA, 0x0000)

def _read_u16le(self, register):
Expand Down Expand Up @@ -413,3 +412,62 @@ def get_pin(self, pin):
"""
assert 0 <= pin <= 15
return DigitalInOut(pin, self)

@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(_MCP23017_INTCONA)

@interrupt_configuration.setter
def interrupt_configuration(self, val):
self._write_u16le(_MCP23017_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(_MCP23017_GPINTENA)

@interrupt_enable.setter
def interrupt_enable(self, val):
self._write_u16le(_MCP23017_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(_MCP23017_DEFVALA)

@default_value.setter
def default_value(self, val):
self._write_u16le(_MCP23017_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 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).
"""
return self._read_u8(_MCP23017_IOCON)

@io_control.setter
def io_control(self, val):
self._write_u8(_MCP23017_IOCON, val)
49 changes: 49 additions & 0 deletions examples/mcp230xx_leds_and_buttons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import board
import busio
from digitalio import Direction, Pull
import adafruit_mcp230xx

# Initialize the I2C bus:
i2c = busio.I2C(board.SCL, board.SDA)

# Initialize the MCP23017 chip on the bonnet
mcp = adafruit_mcp230xx.MCP23017(i2c)

# 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 = adafruit_mcp230xx.MCP23017(i2c, address=0x21) # MCP23017 w/ A0 set

# Make a list of all the port A pins (a.k.a 0-7)
port_a_pins = []
for pin in range(0, 8):
port_a_pins.append(mcp.get_pin(pin))

# Make a list of all the port B pins (a.k.a 8-15)
port_b_pins = []
for pin in range(8, 16):
port_b_pins.append(mcp.get_pin(pin))

# Set all the port A pins to output
for pin in port_a_pins:
pin.direction = Direction.OUTPUT

# Set all the port B pins to input, with pullups!
for pin in port_b_pins:
pin.direction = Direction.INPUT
pin.pull = Pull.UP

# Turn on all port A pins for 1/10 of a second
#while True:
# for pin in port_a_pins:
# pin.value = True # turn LED on!
# time.sleep(0.1) # wait 0.1 seconds
# pin.value = False # turn LED off

while True:
for num, button in enumerate(port_b_pins):
if not button.value:
print("Button #", num, "pressed!")
# turn on matching port A pin
port_a_pins[num].value = True # turn LED on!
else:
port_a_pins[num].value = False # turn LED off
58 changes: 58 additions & 0 deletions examples/mcp230xx_leds_and_buttons_irq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import board
import busio
from digitalio import DigitalInOut, Direction, Pull
import adafruit_mcp230xx

# Initialize the I2C bus:
i2c = busio.I2C(board.SCL, board.SDA)

# Initialize the MCP23017 chip on the bonnet
mcp = adafruit_mcp230xx.MCP23017(i2c)

# 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 = adafruit_mcp230xx.MCP23017(i2c, address=0x21) # MCP23017 w/ A0 set

# Make a list of all the port A pins (a.k.a 0-7)
port_a_pins = []
for pin in range(0, 8):
port_a_pins.append(mcp.get_pin(pin))

# Make a list of all the port B pins (a.k.a 8-15)
port_b_pins = []
for pin in range(8, 16):
port_b_pins.append(mcp.get_pin(pin))

# Set all the port A pins to output
for pin in port_a_pins:
pin.direction = Direction.OUTPUT

# Set all the port B pins to input, with pullups!
for pin in port_b_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 = 0xFF00 # INTerrupt ENable top 8 bits
# 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

# 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 = 0xFF00 # notify pin value
#mcp.default_value = 0xFF00 # default value is 'high' so notify whenever 'low'

# connect the IRQ B pin to D4
irq_b = DigitalInOut(board.D4)

while True:
if not irq_b.value:
print("IRQ B went off")
for num, button in enumerate(port_b_pins):
if not button.value:
print("Button #", num, "pressed!")
# turn on matching port A pin
port_a_pins[num].value = True # turn LED on!
else:
port_a_pins[num].value = False # turn LED off