|
| 1 | +# MicroPython library for MCP23009E I/O Expander |
| 2 | + |
| 3 | +This library provides a complete driver to control the MCP23009E I/O expander on the STeaMi board. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- ✅ **Full GPIO control**: Configure pins as input/output, read/write levels |
| 8 | +- ✅ **Pull-up resistors**: Built-in pull-up support |
| 9 | +- ✅ **Interrupt support**: Hardware interrupts with callback system |
| 10 | +- ✅ **Pin-compatible API**: `MCP23009Pin` class compatible with `machine.Pin` |
| 11 | +- ✅ **Register access**: Low-level register access for advanced usage |
| 12 | + |
| 13 | +## Quick Start |
| 14 | + |
| 15 | +### Basic Usage with MCP23009E class |
| 16 | + |
| 17 | +```python |
| 18 | +from machine import I2C, Pin |
| 19 | +from mcp23009e import MCP23009E |
| 20 | +from mcp23009e.const import * |
| 21 | + |
| 22 | +# Initialize I2C and reset pin |
| 23 | +bus = I2C(1) |
| 24 | +reset = Pin("RST_EXPANDER", Pin.OUT) |
| 25 | + |
| 26 | +# Create driver instance |
| 27 | +mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset) |
| 28 | + |
| 29 | +# Configure a GPIO as input with pull-up |
| 30 | +mcp.setup(7, MCP23009_DIR_INPUT, pullup=MCP23009_PULLUP) |
| 31 | + |
| 32 | +# Read the level |
| 33 | +level = mcp.get_level(7) |
| 34 | +print(f"GPIO 7 level: {level}") |
| 35 | + |
| 36 | +# Configure a GPIO as output |
| 37 | +mcp.setup(0, MCP23009_DIR_OUTPUT) |
| 38 | +mcp.set_level(0, MCP23009_LOGIC_HIGH) |
| 39 | +``` |
| 40 | + |
| 41 | +### Pin-Compatible API with MCP23009Pin |
| 42 | + |
| 43 | +The `MCP23009Pin` class provides a **machine.Pin-compatible** interface: |
| 44 | + |
| 45 | +```python |
| 46 | +from machine import I2C, Pin |
| 47 | +from mcp23009e import MCP23009E, MCP23009Pin |
| 48 | +from mcp23009e.const import * |
| 49 | + |
| 50 | +# Initialize |
| 51 | +bus = I2C(1) |
| 52 | +reset = Pin("RST_EXPANDER", Pin.OUT) |
| 53 | +mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset) |
| 54 | + |
| 55 | +# Create a Pin object for a button |
| 56 | +btn = MCP23009Pin(mcp, 7, MCP23009Pin.IN, MCP23009Pin.PULL_UP) |
| 57 | +print(f"Button state: {btn.value()}") |
| 58 | + |
| 59 | +# Create a Pin object for a LED |
| 60 | +led = MCP23009Pin(mcp, 0, MCP23009Pin.OUT) |
| 61 | +led.on() # Turn on |
| 62 | +led.off() # Turn off |
| 63 | +led.toggle() # Toggle state |
| 64 | +``` |
| 65 | + |
| 66 | +### Interrupts |
| 67 | + |
| 68 | +```python |
| 69 | +from machine import I2C, Pin |
| 70 | +from mcp23009e import MCP23009E, MCP23009Pin |
| 71 | +from mcp23009e.const import * |
| 72 | + |
| 73 | +# Initialize with interrupt pin |
| 74 | +bus = I2C(1) |
| 75 | +reset = Pin("RST_EXPANDER", Pin.OUT) |
| 76 | +interrupt = Pin("INT_EXPANDER", Pin.IN) |
| 77 | +mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset, interrupt_pin=interrupt) |
| 78 | + |
| 79 | +# Create pin and configure interrupt |
| 80 | +btn = MCP23009Pin(mcp, 7, MCP23009Pin.IN, MCP23009Pin.PULL_UP) |
| 81 | + |
| 82 | +def callback(pin): |
| 83 | + print(f"Button state changed: {pin.value()}") |
| 84 | + |
| 85 | +btn.irq(handler=callback, trigger=MCP23009Pin.IRQ_FALLING | MCP23009Pin.IRQ_RISING) |
| 86 | +``` |
| 87 | + |
| 88 | +## Examples |
| 89 | + |
| 90 | +The library includes several examples: |
| 91 | + |
| 92 | +- `buttons.py` - Simple button reading with polling |
| 93 | +- `test_basic.py` - Basic driver functionality tests |
| 94 | +- `test_interrupts.py` - Interrupt system demonstration |
| 95 | +- `test_pin.py` - MCP23009Pin class usage examples |
| 96 | +- `test_pin_irq.py` - Pin-compatible interrupt examples |
| 97 | + |
| 98 | +Run examples with [mpremote](https://docs.micropython.org/en/latest/reference/mpremote.html): |
| 99 | + |
| 100 | +```sh |
| 101 | +mpremote mount . run examples/buttons.py |
| 102 | +mpremote mount . run examples/test_pin.py |
| 103 | +``` |
| 104 | + |
| 105 | +## API Reference |
| 106 | + |
| 107 | +### MCP23009E Class |
| 108 | + |
| 109 | +#### Constructor |
| 110 | +```python |
| 111 | +MCP23009E(i2c, address, reset_pin, interrupt_pin=None) |
| 112 | +``` |
| 113 | + |
| 114 | +#### Main Methods |
| 115 | +- `setup(gpx, direction, pullup, polarity)` - Configure a GPIO |
| 116 | +- `set_level(gpx, level)` - Set output level |
| 117 | +- `get_level(gpx)` - Read input level |
| 118 | +- `interrupt_on_change(gpx, callback)` - Register change callback |
| 119 | +- `interrupt_on_falling(gpx, callback)` - Register falling edge callback |
| 120 | +- `interrupt_on_raising(gpx, callback)` - Register rising edge callback |
| 121 | +- `disable_interrupt(gpx)` - Disable interrupts on a GPIO |
| 122 | + |
| 123 | +### MCP23009Pin Class |
| 124 | + |
| 125 | +#### Constructor |
| 126 | +```python |
| 127 | +MCP23009Pin(mcp, pin_number, mode=-1, pull=-1, value=None) |
| 128 | +``` |
| 129 | + |
| 130 | +#### Methods (machine.Pin compatible) |
| 131 | +- `init(mode, pull, value)` - (Re)configure the pin |
| 132 | +- `value(x=None)` - Get or set pin value |
| 133 | +- `on()` - Set pin high |
| 134 | +- `off()` - Set pin low |
| 135 | +- `toggle()` - Toggle pin state |
| 136 | +- `irq(handler, trigger)` - Configure interrupt |
| 137 | +- `mode(mode=None)` - Get or set mode |
| 138 | +- `pull(pull=None)` - Get or set pull configuration |
| 139 | + |
| 140 | +#### Constants |
| 141 | +- `MCP23009Pin.IN` / `MCP23009Pin.OUT` - Pin modes |
| 142 | +- `MCP23009Pin.PULL_UP` - Pull-up configuration |
| 143 | +- `MCP23009Pin.IRQ_FALLING` / `MCP23009Pin.IRQ_RISING` - Interrupt triggers |
| 144 | + |
| 145 | +### MCP23009ActiveLowPin Class |
| 146 | + |
| 147 | +Special pin class for **active-low configurations** (LEDs connected between VCC and GPIO). |
| 148 | + |
| 149 | +The MCP23009E can sink more current (25mA) than it can source (~1mA). For LEDs and similar loads, use this configuration: |
| 150 | + |
| 151 | +``` |
| 152 | +3.3V → [LED] → [Resistor 220-330Ω] → GPIO |
| 153 | +``` |
| 154 | + |
| 155 | +With `MCP23009ActiveLowPin`, the logic is automatically inverted: |
| 156 | +- `led.on()` → GPIO LOW → LED lights up |
| 157 | +- `led.off()` → GPIO HIGH → LED turns off |
| 158 | + |
| 159 | +#### Example |
| 160 | + |
| 161 | +```python |
| 162 | +from mcp23009e import MCP23009E, MCP23009ActiveLowPin |
| 163 | + |
| 164 | +mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset) |
| 165 | + |
| 166 | +# Create an active-low LED |
| 167 | +led = MCP23009ActiveLowPin(mcp, 0) |
| 168 | +led.on() # LED lights up (GPIO goes LOW) |
| 169 | +led.off() # LED turns off (GPIO goes HIGH) |
| 170 | +led.toggle() # Toggle LED state |
| 171 | +``` |
| 172 | + |
| 173 | +The API is identical to `MCP23009Pin` - just use `MCP23009ActiveLowPin` instead! |
0 commit comments