Skip to content
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

Add toggle() to VirtualPin #14

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
147 changes: 105 additions & 42 deletions mcp23017.py → mcp2301X.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
_MCP_OLAT = const(0x0a) # R/W Output Latch Register

# Config register (IOCON) bits
_MCP_IOCON_INTCC = const(1)
_MCP_IOCON_INTPOL = const(2)
_MCP_IOCON_ODR = const(4)
# _MCP_IOCON_HAEN = const(8) # no used - for spi flavour of this chip
Expand Down Expand Up @@ -156,7 +157,7 @@ def output_latch(self, val):
self._write(_MCP_OLAT, val)


class MCP23017():
class MCP2301X():
def __init__(self, i2c, address=0x20):
self._i2c = i2c
self._address = address
Expand All @@ -183,43 +184,6 @@ def init(self):
self.pullup = 0x0000 # gpio weak pull up resistor - when configured as input (0=disabled, 1=enabled)
self.gpio = 0x0000 # port (0=logic low, 1=logic high)

def config(self, interrupt_polarity=None, interrupt_open_drain=None, sda_slew=None, sequential_operation=None, interrupt_mirror=None, bank=None):
io_config = self.porta.io_config

if interrupt_polarity is not None:
# configre INT as push-pull
# 0: Active low
# 1: Active high
io_config = self._flip_bit(io_config, interrupt_polarity, _MCP_IOCON_INTPOL)
if interrupt_polarity:
# if setting to 1, unset ODR bit - interrupt_open_drain
interrupt_open_drain = False
if interrupt_open_drain is not None:
# configure INT as open drain, overriding interrupt_polarity
# 0: INTPOL sets the polarity
# 1: Open drain, INTPOL ignored
io_config = self._flip_bit(io_config, interrupt_open_drain, _MCP_IOCON_ODR)
if sda_slew is not None:
# 0: Slew rate function on SDA pin enabled
# 1: Slew rate function on SDA pin disabled
io_config = self._flip_bit(io_config, sda_slew, _MCP_IOCON_DISSLW)
if sequential_operation is not None:
# 0: Enabled, address pointer increments
# 1: Disabled, address pointer fixed
io_config = self._flip_bit(io_config, sequential_operation, _MCP_IOCON_SEQOP)
if interrupt_mirror is not None:
# 0: Independent INTA,INTB pins
# 1: Internally linked INTA,INTB pins
io_config = self._flip_bit(io_config, interrupt_mirror, _MCP_IOCON_MIRROR)
if bank is not None:
# 0: Registers alternate between A and B ports
# 1: All port A registers first then all port B
io_config = self._flip_bit(io_config, bank, _MCP_IOCON_BANK)

# both ports share the same register, so you only need to write on one
self.porta.io_config = io_config
self._config = io_config

def _flip_bit(self, value, condition, bit):
if condition:
value |= bit
Expand Down Expand Up @@ -368,13 +332,108 @@ def output_latch(self, val):
self.portb.output_latch = (val >> 8)

# list interface
# mcp[pin] lazy creates a VirtualPin(pin, port)
def __getitem__(self, pin):
assert 0 <= pin <= 15
if not pin in self._virtual_pins:
def _get_pin_item(self, pin):
if pin not in self._virtual_pins:
self._virtual_pins[pin] = VirtualPin(pin, self.portb if pin // 8 else self.porta)
return self._virtual_pins[pin]

def _rslice(self, pin):
assert any(0 <= x < 16 for x in range(pin.start, pin.stop))
ret = []
for x in range(pin.start, pin.stop):
ret.append(self._get_pin_item(x))
return ret

# mcp[pin] lazy creates a VirtualPin(pin, port)
def __getitem__(self, pin):
if isinstance(pin, slice):
return self._rslice(pin)
assert pin in range(0, 16)
return self._get_pin_item(pin)

class MCP23017(MCP2301X):
def __init__(self, i2c, address=0x20):
super().__init__(i2c, address)

def config(self, interrupt_polarity=None, interrupt_open_drain=None, sda_slew=None, sequential_operation=None, interrupt_mirror=None, bank=None):
io_config = self.porta.io_config

if interrupt_polarity is not None:
# configre INT as push-pull
# 0: Active low
# 1: Active high
io_config = self._flip_bit(io_config, interrupt_polarity, _MCP_IOCON_INTPOL)
if interrupt_polarity:
# if setting to 1, unset ODR bit - interrupt_open_drain
interrupt_open_drain = False
if interrupt_open_drain is not None:
# configure INT as open drain, overriding interrupt_polarity
# 0: INTPOL sets the polarity
# 1: Open drain, INTPOL ignored
io_config = self._flip_bit(io_config, interrupt_open_drain, _MCP_IOCON_ODR)
if sda_slew is not None:
# 0: Slew rate function on SDA pin enabled
# 1: Slew rate function on SDA pin disabled
io_config = self._flip_bit(io_config, sda_slew, _MCP_IOCON_DISSLW)
if sequential_operation is not None:
# 0: Enabled, address pointer increments
# 1: Disabled, address pointer fixed
io_config = self._flip_bit(io_config, sequential_operation, _MCP_IOCON_SEQOP)
if interrupt_mirror is not None:
# 0: Independent INTA,INTB pins
# 1: Internally linked INTA,INTB pins
io_config = self._flip_bit(io_config, interrupt_mirror, _MCP_IOCON_MIRROR)
if bank is not None:
# 0: Registers alternate between A and B ports
# 1: All port A registers first then all port B
io_config = self._flip_bit(io_config, bank, _MCP_IOCON_BANK)

# both ports share the same register, so you only need to write on one
self.porta.io_config = io_config
self._config = io_config

class MCP23018(MCP2301X):
def __init__(self, i2c, address=0x20):
super().__init__(i2c, address)

def config(self, interrupt_clear_control=None, interrupt_polarity=None, interrupt_open_drain=None, sequential_operation=None, interrupt_mirror=None, bank=None):
io_config = self.porta.io_config

if interrupt_clear_control is not None:
# Interrupt Clearing Control
# 0: Reading GPIO register clears the interrup
# 1: Reading INTCAP register clears the interrupt
io_config = self._flip_bit(io_config, interrupt_clear_control, _MCP_IOCON_INTCC)
if interrupt_polarity is not None:
# Sets the polarity of the INT output pin.
# 0: Active low
# 1: Active high
io_config = self._flip_bit(io_config, interrupt_polarity, _MCP_IOCON_INTPOL)
if interrupt_polarity:
# if setting to 1, unset ODR bit - interrupt_open_drain
interrupt_open_drain = False
if interrupt_open_drain is not None:
# configure INT as open drain, overriding interrupt_polarity
# 0: INTPOL sets the polarity
# 1: Open drain, INTPOL ignored
io_config = self._flip_bit(io_config, interrupt_open_drain, _MCP_IOCON_ODR)
if sequential_operation is not None:
# 0: Enabled, address pointer increments
# 1: Disabled, address pointer fixed
io_config = self._flip_bit(io_config, sequential_operation, _MCP_IOCON_SEQOP)
if interrupt_mirror is not None:
# 0: Independent INTA,INTB pins
# 1: Internally linked INTA,INTB pins
io_config = self._flip_bit(io_config, interrupt_mirror, _MCP_IOCON_MIRROR)
if bank is not None:
# 0: Registers alternate between A and B ports
# 1: All port A registers first then all port B
io_config = self._flip_bit(io_config, bank, _MCP_IOCON_BANK)

# both ports share the same register, so you only need to write on one
self.porta.io_config = io_config
self._config = io_config

class VirtualPin():
def __init__(self, pin, port):
self._pin = pin % 8
Expand All @@ -396,6 +455,10 @@ def value(self, val=None):
else:
return self._get_bit(self._port.gpio)

def toggle(self):
if self._get_bit(self._port.mode) == 0:
self._port.gpio = self._flip_bit(self._port.gpio, 1 - self._get_bit(self._port.gpio))

def input(self, pull=None):
# if pull, enable pull up, else read
self._port.mode = self._flip_bit(self._port.mode, 1) # mode = input
Expand Down