#i2c #shared-bus #pca #gpio #pcf

no-std port-expander

Abstraction for I2C port-expanders

6 releases (3 breaking)

0.4.0 Aug 13, 2023
0.3.1 Aug 13, 2023
0.3.0 May 6, 2022
0.2.1 Apr 26, 2021
0.1.0 Apr 24, 2021

#189 in Embedded development

Download history 10/week @ 2023-07-15 15/week @ 2023-07-22 8/week @ 2023-07-29 10/week @ 2023-08-05 69/week @ 2023-08-12 20/week @ 2023-08-19 12/week @ 2023-08-26 14/week @ 2023-09-02 25/week @ 2023-09-09 10/week @ 2023-09-16 11/week @ 2023-09-23 12/week @ 2023-09-30 22/week @ 2023-10-07 10/week @ 2023-10-14 25/week @ 2023-10-21 26/week @ 2023-10-28

88 downloads per month
Used in 2 crates


1.5K SLoC

port-expander crates.io page docs.rs page

This is a crate providing a common abstraction for I²C port-expanders. This abstraction is not necessarily the most performant, but it allows using the pins just like direct GPIOs. Because the pin types also implement the embedded-hal digital IO traits, they can also be passed to further drivers downstream (e.g. as a reset or chip-select pin).


// Initialize I2C peripheral from HAL
let i2c = todo!();

// A0: HIGH, A1: LOW, A2: LOW
let mut pca9555 = port_expander::Pca9555::new(i2c, true, false, false);
let pca_pins = pca9555.split();

let io0_0 = pca_pins.io0_0.into_output().unwrap();
let io1_5 = pca_pins.io0_1; // default is input


Accessing multiple pins at the same time

Sometimes timing constraints mandate that multiple pin accesses (reading or writing) happen at the same time. The write_multiple() and read_multiple() methods are designed for doing this.

Supported Devices

The following list is what port-expander currently supports. If you needs support for an additional device, it should be easy to add. It's best to take a similar existing implementation as inspiration. Contributions welcome!

Non-local sharing

port-expander uses the BusMutex from shared-bus under the hood. This means you can also make the pins shareable across task/thread boundaries, given that you provide an appropriate mutex type:

// Initialize I2C peripheral from HAL
let i2c = todo!();

// A0: HIGH, A1: LOW, A2: LOW
let mut pca9555: port_expander::Pca9555<std::sync::Mutex<_>> =
    port_expander::Pca9555::with_mutex(i2c, true, false, false);
let pca_pins = pca9555.split();


Licensed under either of

at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.