From fa461be6c59d16052ea649a73ab90453ce58a938 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 2 Feb 2019 15:17:03 -0500 Subject: [PATCH 1/5] add irq support to 017 and two examples --- adafruit_mcp230xx.py | 53 +++++++++++++++++--- examples/mcp230xx_leds_and_buttons.py | 50 +++++++++++++++++++ examples/mcp230xx_leds_and_buttons_irq.py | 59 +++++++++++++++++++++++ 3 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 examples/mcp230xx_leds_and_buttons.py create mode 100644 examples/mcp230xx_leds_and_buttons_irq.py diff --git a/adafruit_mcp230xx.py b/adafruit_mcp230xx.py index e4618ba..57716b2 100644 --- a/adafruit_mcp230xx.py +++ b/adafruit_mcp230xx.py @@ -60,12 +60,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) @@ -413,3 +412,45 @@ def get_pin(self, pin): """ assert 0 <= pin <= 15 return DigitalInOut(pin, self) + + @property + def intcon(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) + + @intcon.setter + def intcon(self, val): + self._write_u16le(_MCP23017_INTCONA, val) + + @property + def gpinten(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) + + @gpinten.setter + def gpinten(self, val): + self._write_u16le(_MCP23017_GPINTENA, val) + + @property + def defval(self): + """The raw GPINTEN 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) + + @intcon.setter + def defval(self, val): + self._write_u16le(_MCP23017_DEFVALA, val) diff --git a/examples/mcp230xx_leds_and_buttons.py b/examples/mcp230xx_leds_and_buttons.py new file mode 100644 index 0000000..1d18047 --- /dev/null +++ b/examples/mcp230xx_leds_and_buttons.py @@ -0,0 +1,50 @@ +import time +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 diff --git a/examples/mcp230xx_leds_and_buttons_irq.py b/examples/mcp230xx_leds_and_buttons_irq.py new file mode 100644 index 0000000..1c1106d --- /dev/null +++ b/examples/mcp230xx_leds_and_buttons_irq.py @@ -0,0 +1,59 @@ +import time +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.gpinten = 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.intcon = 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.intcon = 0xFF00 # notify pin value +#mcp.defval = 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 From 0e12110cfd8f76f8a21268f627dc5c6865794349 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 2 Feb 2019 15:29:41 -0500 Subject: [PATCH 2/5] add `iocon` register, default to open drain IRQ (safest for mixed voltages) --- adafruit_mcp230xx.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/adafruit_mcp230xx.py b/adafruit_mcp230xx.py index 57716b2..8a16cd2 100644 --- a/adafruit_mcp230xx.py +++ b/adafruit_mcp230xx.py @@ -266,6 +266,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): @@ -454,3 +455,20 @@ def defval(self): @intcon.setter def defval(self, val): self._write_u16le(_MCP23017_DEFVALA, val) + + + @property + def iocon(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) + + @intcon.setter + def iocon(self, val): + self._write_u8(_MCP23017_IOCON, val) From d9898069926b83ad07e9af4f650e5bd640ee4c04 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 2 Feb 2019 20:37:03 +0000 Subject: [PATCH 3/5] linted! --- adafruit_mcp230xx.py | 9 ++++----- examples/mcp230xx_leds_and_buttons.py | 1 - examples/mcp230xx_leds_and_buttons_irq.py | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) mode change 100644 => 100755 adafruit_mcp230xx.py mode change 100644 => 100755 examples/mcp230xx_leds_and_buttons.py mode change 100644 => 100755 examples/mcp230xx_leds_and_buttons_irq.py diff --git a/adafruit_mcp230xx.py b/adafruit_mcp230xx.py old mode 100644 new mode 100755 index 8a16cd2..1411ebc --- a/adafruit_mcp230xx.py +++ b/adafruit_mcp230xx.py @@ -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 @@ -452,7 +451,7 @@ def defval(self): """ return self._read_u16le(_MCP23017_DEFVALA) - @intcon.setter + @defval.setter def defval(self, val): self._write_u16le(_MCP23017_DEFVALA, val) @@ -469,6 +468,6 @@ def iocon(self): """ return self._read_u8(_MCP23017_IOCON) - @intcon.setter + @iocon.setter def iocon(self, val): self._write_u8(_MCP23017_IOCON, val) diff --git a/examples/mcp230xx_leds_and_buttons.py b/examples/mcp230xx_leds_and_buttons.py old mode 100644 new mode 100755 index 1d18047..be2f3b0 --- a/examples/mcp230xx_leds_and_buttons.py +++ b/examples/mcp230xx_leds_and_buttons.py @@ -1,4 +1,3 @@ -import time import board import busio from digitalio import Direction, Pull diff --git a/examples/mcp230xx_leds_and_buttons_irq.py b/examples/mcp230xx_leds_and_buttons_irq.py old mode 100644 new mode 100755 index 1c1106d..dff2b67 --- a/examples/mcp230xx_leds_and_buttons_irq.py +++ b/examples/mcp230xx_leds_and_buttons_irq.py @@ -1,4 +1,3 @@ -import time import board import busio from digitalio import DigitalInOut, Direction, Pull From 3cc4ce1f4025212d99727195fe53223a24fa4648 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 2 Feb 2019 15:41:05 -0500 Subject: [PATCH 4/5] fix typos in strings --- adafruit_mcp230xx.py | 2 +- examples/mcp230xx_leds_and_buttons.py | 0 examples/mcp230xx_leds_and_buttons_irq.py | 0 3 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 adafruit_mcp230xx.py mode change 100755 => 100644 examples/mcp230xx_leds_and_buttons.py mode change 100755 => 100644 examples/mcp230xx_leds_and_buttons_irq.py diff --git a/adafruit_mcp230xx.py b/adafruit_mcp230xx.py old mode 100755 new mode 100644 index 1411ebc..3ffa69c --- a/adafruit_mcp230xx.py +++ b/adafruit_mcp230xx.py @@ -444,7 +444,7 @@ def gpinten(self, val): @property def defval(self): - """The raw GPINTEN interrupt control register. The default comparison + """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. diff --git a/examples/mcp230xx_leds_and_buttons.py b/examples/mcp230xx_leds_and_buttons.py old mode 100755 new mode 100644 diff --git a/examples/mcp230xx_leds_and_buttons_irq.py b/examples/mcp230xx_leds_and_buttons_irq.py old mode 100755 new mode 100644 From 3e28984304f3634de6bea4606e7739b29fe928f3 Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 6 Feb 2019 13:25:20 -0500 Subject: [PATCH 5/5] rename nicer props --- adafruit_mcp230xx.py | 24 +++++++++++------------ examples/mcp230xx_leds_and_buttons_irq.py | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/adafruit_mcp230xx.py b/adafruit_mcp230xx.py index 3ffa69c..ea8e9ca 100644 --- a/adafruit_mcp230xx.py +++ b/adafruit_mcp230xx.py @@ -414,7 +414,7 @@ def get_pin(self, pin): return DigitalInOut(pin, self) @property - def intcon(self): + 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 @@ -424,12 +424,12 @@ def intcon(self): """ return self._read_u16le(_MCP23017_INTCONA) - @intcon.setter - def intcon(self, val): + @interrupt_configuration.setter + def interrupt_configuration(self, val): self._write_u16le(_MCP23017_INTCONA, val) @property - def gpinten(self): + 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. @@ -438,12 +438,12 @@ def gpinten(self): """ return self._read_u16le(_MCP23017_GPINTENA) - @gpinten.setter - def gpinten(self, val): + @interrupt_enable.setter + def interrupt_enable(self, val): self._write_u16le(_MCP23017_GPINTENA, val) @property - def defval(self): + 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 @@ -451,13 +451,13 @@ def defval(self): """ return self._read_u16le(_MCP23017_DEFVALA) - @defval.setter - def defval(self, val): + @default_value.setter + def default_value(self, val): self._write_u16le(_MCP23017_DEFVALA, val) @property - def iocon(self): + 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. @@ -468,6 +468,6 @@ def iocon(self): """ return self._read_u8(_MCP23017_IOCON) - @iocon.setter - def iocon(self, val): + @io_control.setter + def io_control(self, val): self._write_u8(_MCP23017_IOCON, val) diff --git a/examples/mcp230xx_leds_and_buttons_irq.py b/examples/mcp230xx_leds_and_buttons_irq.py index dff2b67..0400daf 100644 --- a/examples/mcp230xx_leds_and_buttons_irq.py +++ b/examples/mcp230xx_leds_and_buttons_irq.py @@ -33,15 +33,15 @@ pin.pull = Pull.UP # Set up to check all the port B pins (pins 8-15) w/interrupts! -mcp.gpinten = 0xFF00 # INTerrupt ENable top 8 bits +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.intcon = 0x0000 # interrupt on any change +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.intcon = 0xFF00 # notify pin value -#mcp.defval = 0xFF00 # default value is 'high' so notify whenever 'low' +#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)