Skip to content

Latest commit

 

History

History
217 lines (153 loc) · 6.08 KB

File metadata and controls

217 lines (153 loc) · 6.08 KB

MicroPython library for MCP23009E I/O Expander

This library provides a complete driver to control the MCP23009E I/O expander on the STeaMi board.

Features

  • Full GPIO control: Configure pins as input/output, read/write levels
  • Pull-up resistors: Built-in pull-up support
  • Interrupt support: Hardware interrupts with callback system
  • Pin-compatible API: MCP23009Pin class compatible with machine.Pin
  • Register access: Low-level register access for advanced usage

I²C Address

The base I²C address is `0x20` (A0=A1=A2=LOW). On the STeaMi board, the address is `0x20`.

Quick Start

Basic Usage with MCP23009E class

from machine import I2C, Pin
from mcp23009e import MCP23009E
from mcp23009e.const import MCP23009_DIR_INPUT, MCP23009_I2C_ADDR, MCP23009_PULLUP

# Initialize I2C and reset pin
bus = I2C(1)
reset = Pin("RST_EXPANDER", Pin.OUT)

# Create driver instance
mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset)

# Configure a GPIO as input with pull-up
mcp.setup(7, MCP23009_DIR_INPUT, pullup=MCP23009_PULLUP)

# Read the level
level = mcp.get_level(7)
print(f"GPIO 7 level: {level}")

# Configure a GPIO as output
mcp.setup(0, MCP23009_DIR_OUTPUT)
mcp.set_level(0, MCP23009_LOGIC_HIGH)

Pin-Compatible API with MCP23009Pin

The MCP23009Pin class provides a machine.Pin-compatible interface:

from machine import I2C, Pin
from mcp23009e import MCP23009E, MCP23009Pin
from mcp23009e.const import MCP23009_I2C_ADDR

# Initialize
bus = I2C(1)
reset = Pin("RST_EXPANDER", Pin.OUT)
mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset)

# Create a Pin object for a button
btn = MCP23009Pin(mcp, 7, MCP23009Pin.IN, MCP23009Pin.PULL_UP)
print(f"Button state: {btn.value()}")

# Create a Pin object for a LED
led = MCP23009Pin(mcp, 0, MCP23009Pin.OUT)
led.on()   # Turn on
led.off()  # Turn off
led.toggle()  # Toggle state

Interrupts

from machine import I2C, Pin
from mcp23009e import MCP23009E, MCP23009Pin
from mcp23009e.const import MCP23009_I2C_ADDR

# Initialize with interrupt pin
bus = I2C(1)
reset = Pin("RST_EXPANDER", Pin.OUT)
interrupt = Pin("INT_EXPANDER", Pin.IN)
mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset, interrupt_pin=interrupt)

# Create pin and configure interrupt
btn = MCP23009Pin(mcp, 7, MCP23009Pin.IN, MCP23009Pin.PULL_UP)

def callback(pin):
    print(f"Button state changed: {pin.value()}")

btn.irq(handler=callback, trigger=MCP23009Pin.IRQ_FALLING | MCP23009Pin.IRQ_RISING)

API Reference

MCP23009E Class

Constructor

MCP23009E(i2c, address, reset_pin, interrupt_pin=None)

Main Methods

  • setup(gpx, direction, pullup, polarity) - Configure a GPIO
  • set_level(gpx, level) - Set output level
  • get_level(gpx) - Read input level
  • interrupt_on_change(gpx, callback) - Register change callback
  • interrupt_on_falling(gpx, callback) - Register falling edge callback
  • interrupt_on_raising(gpx, callback) - Register rising edge callback
  • disable_interrupt(gpx) - Disable interrupts on a GPIO

MCP23009Pin Class

Constructor

MCP23009Pin(mcp, pin_number, mode=-1, pull=-1, value=None)

Methods (machine.Pin compatible)

  • init(mode, pull, value) - (Re)configure the pin
  • value(x=None) - Get or set pin value
  • on() - Set pin high
  • off() - Set pin low
  • toggle() - Toggle pin state
  • irq(handler, trigger) - Configure interrupt
  • mode(mode=None) - Get or set mode
  • pull(pull=None) - Get or set pull configuration

Constants

  • MCP23009Pin.IN / MCP23009Pin.OUT - Pin modes
  • MCP23009Pin.PULL_UP - Pull-up configuration
  • MCP23009Pin.IRQ_FALLING / MCP23009Pin.IRQ_RISING - Interrupt triggers

MCP23009ActiveLowPin Class

Special pin class for active-low configurations (LEDs connected between VCC and GPIO).

The MCP23009E can sink more current (25mA) than it can source (~1mA). For LEDs and similar loads, use this configuration:

3.3V → [LED] → [Resistor 220-330Ω] → GPIO

With MCP23009ActiveLowPin, the logic is automatically inverted:

  • led.on() → GPIO LOW → LED lights up
  • led.off() → GPIO HIGH → LED turns off

Example

from mcp23009e import MCP23009E, MCP23009ActiveLowPin

mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset)

# Create an active-low LED
led = MCP23009ActiveLowPin(mcp, 0)
led.on()   # LED lights up (GPIO goes LOW)
led.off()  # LED turns off (GPIO goes HIGH)
led.toggle()  # Toggle LED state

The API is identical to MCP23009Pin - just use MCP23009ActiveLowPin instead.

Power Management

The driver provides simple hardware power management helpers through the reset pin:

Power off

mcp.power_off()

Holds the reset pin low.

Power on

mcp.power_on()

Releases the reset pin.

Reset

mcp.reset()

Toggles the reset pin to perform a hardware reset.

Examples

The library includes several practical examples:

Example Description
buttons.py Simple D-PAD button reading using polling (no interrupts)
i2c_scan.py Scan the I2C bus to detect connected devices
reaction_timer.py Reaction time game using D-PAD buttons and interrupts (best of 5 rounds)
simon.py Simon Says memory game using the D-PAD
combination_lock.py Digital lock using a secret D-PAD sequence
dpad_counter.py Simple state machine: increment/decrement/reset/print using D-PAD
morse_code.py Morse code input using button press duration (dot/dash detection)
binary_counter.py 4-bit binary counter displayed on GPIO outputs (GPIO1–GPIO4 / pins 0–3)
dpad_piano.py Play musical notes with the D-PAD and buzzer (multi-press = higher octave)
menu_navigation.py Minimal centered UI for navigating a menu on the SSD1327 OLED display
sleep_on_button.py Low-power example: wake the board from sleep using MCP23009E interrupts

How to run

mpremote mount lib/mcp23009e run lib/mcp23009e/examples/buttons.py