diff --git a/adafruit_mcp230xx.py b/adafruit_mcp230xx.py index e4618ba..ea8e9ca 100644 --- 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 @@ -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) @@ -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): @@ -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) diff --git a/examples/mcp230xx_leds_and_buttons.py b/examples/mcp230xx_leds_and_buttons.py new file mode 100644 index 0000000..be2f3b0 --- /dev/null +++ b/examples/mcp230xx_leds_and_buttons.py @@ -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 diff --git a/examples/mcp230xx_leds_and_buttons_irq.py b/examples/mcp230xx_leds_and_buttons_irq.py new file mode 100644 index 0000000..0400daf --- /dev/null +++ b/examples/mcp230xx_leds_and_buttons_irq.py @@ -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