Skip to content

Commit da9480b

Browse files
authored
Merge pull request #7 from ladyada/master
Add interrupt support & examples to MCP23017
2 parents f3d9cbe + 3e28984 commit da9480b

File tree

3 files changed

+174
-9
lines changed

3 files changed

+174
-9
lines changed

adafruit_mcp230xx.py

+67-9
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,9 @@
2727
2828
* Author(s): Tony DiCola
2929
"""
30-
import digitalio
31-
32-
import adafruit_bus_device.i2c_device as i2c_device
3330

31+
from adafruit_bus_device import i2c_device
32+
import digitalio
3433
from micropython import const
3534

3635

@@ -60,12 +59,11 @@
6059
_MCP23017_IPOLB = const(0x03)
6160
_MCP23017_GPINTENA = const(0x04)
6261
_MCP23017_GPINTENB = const(0x05)
63-
_MCP23008_DEFVALA = const(0x06)
64-
_MCP23008_DEFVALB = const(0x07)
65-
_MCP23008_INTCONA = const(0x08)
66-
_MCP23008_INTCONB = const(0x09)
67-
_MCP23008_IOCONA = const(0x0A)
68-
_MCP23008_IOCONB = const(0x0B)
62+
_MCP23017_DEFVALA = const(0x06)
63+
_MCP23017_DEFVALB = const(0x07)
64+
_MCP23017_INTCONA = const(0x08)
65+
_MCP23017_INTCONB = const(0x09)
66+
_MCP23017_IOCON = const(0x0A)
6967
_MCP23017_GPPUA = const(0x0C)
7068
_MCP23017_GPPUB = const(0x0D)
7169
_MCP23008_INTFA = const(0x0E)
@@ -267,6 +265,7 @@ def __init__(self, i2c, address=_MCP23017_ADDRESS):
267265
# Reset to all inputs with no pull-ups and no inverted polarity.
268266
self.iodir = 0xFFFF
269267
self.gppu = 0x0000
268+
self.iocon = 0x4 # turn on IRQ Pins as open drain
270269
self._write_u16le(_MCP23017_IPOLA, 0x0000)
271270

272271
def _read_u16le(self, register):
@@ -413,3 +412,62 @@ def get_pin(self, pin):
413412
"""
414413
assert 0 <= pin <= 15
415414
return DigitalInOut(pin, self)
415+
416+
@property
417+
def interrupt_configuration(self):
418+
"""The raw INTCON interrupt control register. The INTCON register
419+
controls how the associated pin value is compared for the
420+
interrupt-on-change feature. If a bit is set, the corresponding
421+
I/O pin is compared against the associated bit in the DEFVAL
422+
register. If a bit value is clear, the corresponding I/O pin is
423+
compared against the previous value.
424+
"""
425+
return self._read_u16le(_MCP23017_INTCONA)
426+
427+
@interrupt_configuration.setter
428+
def interrupt_configuration(self, val):
429+
self._write_u16le(_MCP23017_INTCONA, val)
430+
431+
@property
432+
def interrupt_enable(self):
433+
"""The raw GPINTEN interrupt control register. The GPINTEN register
434+
controls the interrupt-on-change feature for each pin. If a bit is
435+
set, the corresponding pin is enabled for interrupt-on-change.
436+
The DEFVAL and INTCON registers must also be configured if any pins
437+
are enabled for interrupt-on-change.
438+
"""
439+
return self._read_u16le(_MCP23017_GPINTENA)
440+
441+
@interrupt_enable.setter
442+
def interrupt_enable(self, val):
443+
self._write_u16le(_MCP23017_GPINTENA, val)
444+
445+
@property
446+
def default_value(self):
447+
"""The raw DEFVAL interrupt control register. The default comparison
448+
value is configured in the DEFVAL register. If enabled (via GPINTEN
449+
and INTCON) to compare against the DEFVAL register, an opposite value
450+
on the associated pin will cause an interrupt to occur.
451+
"""
452+
return self._read_u16le(_MCP23017_DEFVALA)
453+
454+
@default_value.setter
455+
def default_value(self, val):
456+
self._write_u16le(_MCP23017_DEFVALA, val)
457+
458+
459+
@property
460+
def io_control(self):
461+
"""The raw IOCON configuration register. Bit 1 controls interrupt
462+
polarity (1 = active-high, 0 = active-low). Bit 2 is whether irq pin
463+
is open drain (1 = open drain, 0 = push-pull). Bit 3 is unused.
464+
Bit 4 is whether SDA slew rate is enabled (1 = yes). Bit 5 is if I2C
465+
address pointer auto-increments (1 = no). Bit 6 is whether interrupt
466+
pins are internally connected (1 = yes). Bit 7 is whether registers
467+
are all in one bank (1 = no).
468+
"""
469+
return self._read_u8(_MCP23017_IOCON)
470+
471+
@io_control.setter
472+
def io_control(self, val):
473+
self._write_u8(_MCP23017_IOCON, val)

examples/mcp230xx_leds_and_buttons.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import board
2+
import busio
3+
from digitalio import Direction, Pull
4+
import adafruit_mcp230xx
5+
6+
# Initialize the I2C bus:
7+
i2c = busio.I2C(board.SCL, board.SDA)
8+
9+
# Initialize the MCP23017 chip on the bonnet
10+
mcp = adafruit_mcp230xx.MCP23017(i2c)
11+
12+
# Optionally change the address of the device if you set any of the A0, A1, A2
13+
# pins. Specify the new address with a keyword parameter:
14+
#mcp = adafruit_mcp230xx.MCP23017(i2c, address=0x21) # MCP23017 w/ A0 set
15+
16+
# Make a list of all the port A pins (a.k.a 0-7)
17+
port_a_pins = []
18+
for pin in range(0, 8):
19+
port_a_pins.append(mcp.get_pin(pin))
20+
21+
# Make a list of all the port B pins (a.k.a 8-15)
22+
port_b_pins = []
23+
for pin in range(8, 16):
24+
port_b_pins.append(mcp.get_pin(pin))
25+
26+
# Set all the port A pins to output
27+
for pin in port_a_pins:
28+
pin.direction = Direction.OUTPUT
29+
30+
# Set all the port B pins to input, with pullups!
31+
for pin in port_b_pins:
32+
pin.direction = Direction.INPUT
33+
pin.pull = Pull.UP
34+
35+
# Turn on all port A pins for 1/10 of a second
36+
#while True:
37+
# for pin in port_a_pins:
38+
# pin.value = True # turn LED on!
39+
# time.sleep(0.1) # wait 0.1 seconds
40+
# pin.value = False # turn LED off
41+
42+
while True:
43+
for num, button in enumerate(port_b_pins):
44+
if not button.value:
45+
print("Button #", num, "pressed!")
46+
# turn on matching port A pin
47+
port_a_pins[num].value = True # turn LED on!
48+
else:
49+
port_a_pins[num].value = False # turn LED off
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import board
2+
import busio
3+
from digitalio import DigitalInOut, Direction, Pull
4+
import adafruit_mcp230xx
5+
6+
# Initialize the I2C bus:
7+
i2c = busio.I2C(board.SCL, board.SDA)
8+
9+
# Initialize the MCP23017 chip on the bonnet
10+
mcp = adafruit_mcp230xx.MCP23017(i2c)
11+
12+
# Optionally change the address of the device if you set any of the A0, A1, A2
13+
# pins. Specify the new address with a keyword parameter:
14+
#mcp = adafruit_mcp230xx.MCP23017(i2c, address=0x21) # MCP23017 w/ A0 set
15+
16+
# Make a list of all the port A pins (a.k.a 0-7)
17+
port_a_pins = []
18+
for pin in range(0, 8):
19+
port_a_pins.append(mcp.get_pin(pin))
20+
21+
# Make a list of all the port B pins (a.k.a 8-15)
22+
port_b_pins = []
23+
for pin in range(8, 16):
24+
port_b_pins.append(mcp.get_pin(pin))
25+
26+
# Set all the port A pins to output
27+
for pin in port_a_pins:
28+
pin.direction = Direction.OUTPUT
29+
30+
# Set all the port B pins to input, with pullups!
31+
for pin in port_b_pins:
32+
pin.direction = Direction.INPUT
33+
pin.pull = Pull.UP
34+
35+
# Set up to check all the port B pins (pins 8-15) w/interrupts!
36+
mcp.interrupt_enable = 0xFF00 # INTerrupt ENable top 8 bits
37+
# If intcon is set to 0's we will get interrupts on
38+
# both button presses and button releases
39+
mcp.interrupt_configuration = 0x0000 # interrupt on any change
40+
41+
# Or, we can ask to be notified CONTINUOUSLY if a pin goes LOW (button press)
42+
# we won't get an IRQ pulse when the pin is HIGH!
43+
#mcp.interrupt_configuration = 0xFF00 # notify pin value
44+
#mcp.default_value = 0xFF00 # default value is 'high' so notify whenever 'low'
45+
46+
# connect the IRQ B pin to D4
47+
irq_b = DigitalInOut(board.D4)
48+
49+
while True:
50+
if not irq_b.value:
51+
print("IRQ B went off")
52+
for num, button in enumerate(port_b_pins):
53+
if not button.value:
54+
print("Button #", num, "pressed!")
55+
# turn on matching port A pin
56+
port_a_pins[num].value = True # turn LED on!
57+
else:
58+
port_a_pins[num].value = False # turn LED off

0 commit comments

Comments
 (0)