Skip to main content

IO Expander MicroPython

The Pimoroni IO Expander Breakout is a Nuvoton MS51 microcontroller that gives you 14 extra pins over i2c. Eight of them can read a 12-bit ADC, six can drive a 16-bit PWM output, and four rotary encoders can be counted in hardware.

This driver also underpins the RGB Encoder, RGB Potentiometer and Encoder Wheel breakouts, which are all fundamentally an IO Expander with something wired to its pins.

Installing

Install with mip:

import mip
mip.install("github:pimoroni/ioexpander-micropython/package.json")

Or with Thonny, via Tools -> Manage Packages, searching for ioexpander-micropython.

Getting Started

from machine import I2C, Pin
from ioexpander import IOExpander

i2c = I2C(0, sda=Pin(20), scl=Pin(21))

ioe = IOExpander(i2c)

The breakout ships at address 0x18. Pins are numbered 1 to 14, matching the silkscreen.

Pin Modes

Every pin has to be told what it is before you use it:

from ioexpander import ADC, IN, IN_PU, OD, OUT, PWM

ioe.set_mode(1, OUT)     # Push-pull output
ioe.set_mode(2, IN)      # Input, high impedance
ioe.set_mode(3, IN_PU)   # Input with pull-up
ioe.set_mode(4, OD)      # Open-drain output
ioe.set_mode(5, PWM)     # PWM output
ioe.set_mode(14, ADC)    # Analog input

Not every pin can do everything. Pins 1 to 6 are PWM only, pins 10, 11, 13 and 14 are ADC only, and pins 7, 8, 9 and 12 can be either. Setting an unsupported mode raises a ValueError.

Two extra settings apply to particular modes:

ioe.set_mode(2, IN, schmitt_trigger=True)  # Cleans up a noisy input
ioe.set_mode(5, PWM, invert=True)          # For a common anode LED

Reading and Writing

input() returns a digital 0 or 1, or a 12-bit count from a pin in ADC mode:

value = ioe.input(14)
volts = ioe.input_as_voltage(14)

Voltages are scaled against the ADC reference, which defaults to 3.3V:

ioe.set_adc_vref(5.0)

output() writes a digital LOW or HIGH, or a PWM duty cycle:

from ioexpander import HIGH, LOW

ioe.output(1, HIGH)
ioe.output(5, 128)

PWM

All six PWM channels share one counter and the period and clock divider are global. The period sets how many steps of duty cycle you get. The divider sets how fast the counter runs:

ioe.set_pwm_period(255)   # 256 steps of duty cycle
ioe.set_pwm_control(2)    # Divide the 24MHz clock by 2

Or set a frequency and let the driver pick both:

period = ioe.set_pwm_frequency(1000)

New duty cycles are buffered until a load. output() loads by default, which is one i2c transaction per channel. To update several channels in step, use load=Talse until the last one:

ioe.output(1, r, load=False)
ioe.output(7, g, load=False)
ioe.output(2, b)

This combines multiple transactions into one, speeding things up slightly.

Rotary Encoders

The expander counts up to four rotary encoders in hardware, so you don't have to poll fast enough to catch every transition:

ioe.setup_rotary_encoder(1, pin_a=12, pin_b=3, pin_c=11)
count = ioe.read_rotary_encoder(1)
ioe.clear_rotary_encoder(1)

pin_c is the encoder's common terminal, if it is wired to a pin rather than to ground. Pass count_microsteps=True to count every state change rather than every detent.

The expander counts into a signed 8-bit register. read_rotary_encoder() tracks the wraparound for you and returns a count that keeps growing. You must read it often enough that the count doesn't move more than 128 between reads.

Interrupts

The expander can drive its INT pin when a watched input changes, so you can wait on a pin instead of polling over i2c:

from machine import Pin

interrupt = Pin(22, Pin.IN, Pin.PULL_UP)
ioe = IOExpander(i2c, interrupt=interrupt)

ioe.set_pin_interrupt(3, True)

if ioe.get_interrupt_flag():
    ...
    ioe.clear_interrupt_flag()

Without a pin, get_interrupt_flag() reads the flag over i2c instead.

Changing the Address

set_address() writes a new address into the expander's flash, where it persists across power cycles:

ioe.set_address(0x20)

Changelog

0.0.1

  • Initial Release

Release files for ioexpander-micropython 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ioexpander-micropython 0.0.1
File Size Uploaded
ioexpander_micropython-0.0.1.tar.gz 16.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ioexpander-micropython 0.0.1
File Interpreter ABI Platform
ioexpander_micropython-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 26.1 kB

Release files / ioexpander_micropython-0.0.1.tar.gz

Download URL ioexpander_micropython-0.0.1.tar.gz
Size 16.2 kB
Tags Source
SHA-256 checksum
How to use checksums
230db6d5434f1b9437737bfd4dbdc9fcf5841e71219723e111eafe64549b402b
BLAKE2b-256 checksum
How to use checksums
f3fe9fe89356336b4c70ef6b7cc21737493170aefa171faf16c953e8669dc45f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / ioexpander_micropython-0.0.1-py3-none-any.whl

Download URL ioexpander_micropython-0.0.1-py3-none-any.whl
Size 9.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
518792f04b94c3004fd0adaf9144b799830304b5eeeee5553d565e9d3aa1759f
BLAKE2b-256 checksum
How to use checksums
1f883a1bfa76744d45c0871216cf0c8ce4940dffc44c0b0eaae005c30c041f8c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page