Expand description
This is a platform agnostic Rust driver for the PCF8574, PCF8574A and PCF8575
I/O expanders, based on the embedded-hal
traits.
This driver allows you to:
- Set all the outputs to
0
or1
at once. Seeset()
. - Read selected inputs. See
get()
. - Set all the outputs repeatedly looping through an array. See
write_array()
. - Read selected inputs repeatedly filling up an array. See
read_array()
. - Split the device into individual input/output pins. See
split()
.
§The devices
The devices consist of 8 or 16 quasi-bidirectional ports, I²C-bus interface, three hardware address inputs and interrupt output. The quasi-bidirectional port can be independently assigned as an input to monitor interrupt status or keypads, or as an output to activate indicator devices such as LEDs.
The active LOW open-drain interrupt output (INT) can be connected to the interrupt logic of the microcontroller and is activated when any input state differs from its corresponding input port register state.
Datasheets:
§Splitting the device into individual input/output pins
By calling split()
on the device it is possible to get a structure holding the
individual pins as separate elements. These pins implement the OutputPin
and
InputPin
traits (the latter only if activating the unproven
feature).
This way it is possible to use the pins transparently as normal I/O pins regardless
of the fact that an I/O expander is connected in between.
You can therefore also pass them to code expecting an OutputPin
or InputPin
.
However, you need to keep the device you split alive (lifetime annotations have put in place for Rust to enforce this).
For each operation done on an input/output pin, a read
or write
will be done
through I2C for all the pins, using a cached value for the rest of pins not being
operated on. This should all be transparent to the user but if operating on more
than one pin at once, the set
and get
methods will be faster.
Similarly, if several pins must be changed/read at the same time, the set
and
get
methods would be the correct choice.
At the moment, no mutex has been implemented for the individual pin access.
§Usage examples (see also examples folder)
Please find additional examples using hardware in this repository: driver-examples
§Instantiating with the default address
Import this crate and an embedded_hal
implementation, then instantiate
the device:
use linux_embedded_hal::I2cdev;
use pcf857x::{ Pcf8574, SlaveAddr };
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let address = SlaveAddr::default();
let mut expander = Pcf8574::new(dev, address);
§Providing an alternative address
use linux_embedded_hal::I2cdev;
use pcf857x::{ Pcf8574, SlaveAddr };
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let (a2, a1, a0) = (false, false, true);
let address = SlaveAddr::Alternative(a2, a1, a0);
let mut expander = Pcf8574::new(dev, address);
§Setting the output pins and reading P0 and P7
use linux_embedded_hal::I2cdev;
use pcf857x::{ Pcf8574, SlaveAddr, PinFlag };
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let address = SlaveAddr::default();
let mut expander = Pcf8574::new(dev, address);
let output_pin_status = 0b1010_1010;
expander.set(output_pin_status).unwrap();
let mask_of_pins_to_be_read = PinFlag::P0 | PinFlag::P7;
let read_input_pin_status = expander.get(mask_of_pins_to_be_read).unwrap();
println!("Input pin status: {}", read_input_pin_status);
§Splitting device into individual input/output pins and setting them.
use linux_embedded_hal::I2cdev;
use pcf857x::{ Pcf8574, SlaveAddr, PinFlag, OutputPin };
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let address = SlaveAddr::default();
let expander = Pcf8574::new(dev, address);
let mut parts = expander.split();
parts.p0.set_high().unwrap();
parts.p7.set_low().unwrap();
§Splitting device into individual input/output pins and reading them.
Only available if compiling with the “unproven
” feature
use linux_embedded_hal::I2cdev;
use pcf857x::{ Pcf8574, SlaveAddr, PinFlag };
#[cfg(feature="unproven")]
use pcf857x::InputPin;
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let address = SlaveAddr::default();
let expander = Pcf8574::new(dev, address);
let mut parts = expander.split();
#[cfg(feature="unproven")]
{
let is_input_p0_low = parts.p0.is_low().unwrap();
let is_input_p2_low = parts.p2.is_low().unwrap();
}
Modules§
- Module containing structures specific to PCF8574 and PCF8574A
- Module containing structures specific to PCF8575
Structs§
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Pin
- Device driver
- PCF8575 device driver
- Device driver
- I/O pin flags, used to select which pins to read in the
get
functions. It is possible to select multiple of them using the binary or operator (|
).
Enums§
- All possible errors in this crate
- Possible slave addresses
Traits§
- Single digital input pin
- Single digital push-pull output pin